T-MVW5-code-editor-package
State: planning/proposed · Impact: medium · Complexity: medium
A skill carries scripts, JSON and YAML beside its note, and determined has nowhere to show them: the
shell’s Browse page prints file text into a <pre>, and Agent Manager has no code surface at all.
Three ad-hoc CodeMirror 6 mounts already exist across the repo, each with its own theme and its own
language wiring. One package gives every determined surface a themed, read-or-write code editor, and
gives the preview and related-files panes something to render into.
| Location | Role today |
|---|---|
solutions/determined/packages/shell/app/pages/apps/browse.vue | Renders a file’s text into <pre class="browse-body">: no highlighting, no editing, no language awareness |
solutions/determined/experiences/polish/app/components/PolishCodePreviewPane.vue | Ad-hoc CM6 mount: markdown only, read-only, themed with oneDark rather than the --d-* tokens |
apps/agentpants/src-nuxt/app/components/preview/CodeMirrorViewer.vue | The standalone viewer’s own CM6 mount, with a line-highlight state field and oneDark + defaultHighlightStyle |
apps/agentpants/src-nuxt/app/components/preview/RendererRegistry.ts | That mount’s language registry: markdown, yaml, json and the rest, each lazily imported |
solutions/augmented/apps/vimit_prototype/app/components/VimEditor/VimEditor.vue | @replit/codemirror-vim over basicSetup, with the extension-ordering and keymap-precedence prior art |
packages/ts/obsidian-editor/src/theme.ts#obsidianEditorTheme | The theming contract to copy: every color is var(--obsmd-*, fallback) and a host themes by setting variables on an ancestor, never by overriding selectors |
packages/ts/ui/app/assets/css/tokens.css | The --d-* token set a determined surface themes from |
solutions/determined/packages/app-state/ | The tier-0 package shape: package.json, moon.yml, tsconfig.json, src/ |
packages/ts/markdown-ui/nuxt.config.ts | The Nuxt-layer shape a component-bearing package uses so consumers get auto-imports |
.moon/workspace.yml | solutions/determined/packages/* is not glob-discovered; each project is registered by id |
docs/LIBRARIES.md | The tier-0 table, one row per solution-local package |
docs/planning/decisions/D-0001-project-structure.md | The placement gradient: start solution-local, promote on a consumer outside the origin solution |
Proposed
Section titled “Proposed”A new tier-0 package solutions/determined/packages/code-editor, published in-repo as
@determined/code-editor. Both named consumers are determined, so D-0001 puts it in that solution
and a second-solution consumer is what would promote it later. The package name does not change on
promotion.
It ships one Vue component, CodeSurface.vue, over CodeMirror 6:
- languages from
@codemirror/lang-json,-yaml,-javascriptand-python, plus a@codemirror/legacy-modesfallback for shell and anything else, resolved from a file extension and imported lazily; - read or write, with
readOnlyand anonSaveemit; - themed entirely through
--d-*tokens with neutral fallbacks, on theobsidian-editorcontract: no hardcoded palette and nooneDark; - an extension slot a host fills, which is where the vim extension goes.
browse.vue mounts it instead of the <pre>. Agent Manager’s preview and related-files panes mount
it for file contents. docs/LIBRARIES.md gains a tier-0 row. PolishCodePreviewPane.vue is named
as the migration candidate and is not migrated here.
Approach
Section titled “Approach”- Scaffold the package on the shape
app-stateandmarkdown-uiestablish:package.json,moon.yml,tsconfig.json, and register the project id in.moon/workspace.yml. Decision inside this step: ship it as a Nuxt layer, matchingmarkdown-ui, so a consuming layer gets the component by auto-import rather than a manual registration in each product. - Write the language resolver — extension to lazily-imported
LanguageSupport, with a plain-text fallback.RendererRegistry.tsin the standalone viewer is the working reference for the lazy shape. - Write
CodeSurface.vue: mount,readOnly,onSave, document-swap on a content change, teardown on unmount. - Write the theme extension over
--d-*with fallbacks, followingobsidianEditorTheme’s rule that a host sets variables and never overrides selectors. - Add the extension slot the vim extension will occupy. Decision inside this step: this task ships the slot only; T-FG8R-editor-settings-toolbar-and-vim owns the vim dependency and the setting that turns it on.
- Swap
browse.vue’s<pre>forCodeSurfacein read-only mode, keeping the existingdata-browse-contenthook so the shell’s tests still address it. - Declare the dependency in the agent-pants experience so the preview and related panes can mount
it, and add the tier-0 row to
docs/LIBRARIES.mdnamingPolishCodePreviewPane.vueas the migration candidate.
| Area | Note |
|---|---|
solutions/determined/packages/code-editor/package.json | @determined/code-editor, CM6 and language dependencies |
solutions/determined/packages/code-editor/moon.yml | Project config on the app-state pattern |
solutions/determined/packages/code-editor/tsconfig.json | Package tsconfig |
solutions/determined/packages/code-editor/nuxt.config.ts | Layer entry point |
solutions/determined/packages/code-editor/app/components/CodeSurface.vue | The editor component |
solutions/determined/packages/code-editor/app/utils/languages.ts | Extension to lazy LanguageSupport, with the plain-text fallback |
solutions/determined/packages/code-editor/app/utils/theme.ts | The --d-* theme extension |
solutions/determined/packages/code-editor/test/languages.test.ts | Extension resolution, including the fallback |
.moon/workspace.yml | Register the code-editor project id |
solutions/determined/packages/shell/package.json | Depend on @determined/code-editor |
solutions/determined/packages/shell/nuxt.config.ts | Extend the layer |
solutions/determined/packages/shell/app/pages/apps/browse.vue | Mount CodeSurface read-only in place of the <pre> |
solutions/determined/experiences/agent-pants/package.json | Depend on the package for the preview and related panes |
solutions/determined/experiences/agent-pants/nuxt.config.ts | Extend the layer |
docs/LIBRARIES.md | Tier-0 row, naming the migration candidate |
bun.lock | Root lockfile regeneration |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
solutions/determined/packages/code-editorexists, is registered in.moon/workspace.yml, and itschecktask passes. - AC-2:
browse.vuerendersCodeSurfaceand no longer contains a<pre>for file content. - AC-3: Opening a
.json, a.yaml, a.py, a.jsand a.shfile in Browse highlights each one; an unknown extension falls back to plain text without an error. - AC-4:
CodeSurfacein write mode emitssaveon the save keybinding, andreadOnlyblocks every edit. - AC-5: The package contains no
oneDarkimport and no literal hex color — every color is avar(--d-*, fallback). - AC-6: The editor is legible in both the light and the dark appearance, with no rule outside
the
--d-*contract. - AC-7:
docs/LIBRARIES.mdcarries the tier-0 row and namesPolishCodePreviewPane.vueas the migration candidate. - AC-8:
bun install --frozen-lockfilepasses at the root.
Out of scope
Section titled “Out of scope”- Migrating
PolishCodePreviewPane.vueor the standalone viewer’sCodeMirrorViewer.vue. Both are named as candidates; neither moves here. - Vim mode and the editor settings section: T-FG8R-editor-settings-toolbar-and-vim.
- Diffs.
DiffViewer.vuein the standalone viewer stays where it is; the git panel (T-L7YP-git-panel-commit-with-validation) decides what it needs. - Markdown. Markdown bodies stay on
MdSurfacefrommarkdown-ui; this surface is for the files a note carries. - Promotion to tier 1. It stays solution-local until a consumer outside determined imports it.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Member of milestone M-BMFD, from the user’s planning request of 2026-09-07 on the editor
workbench: the files a skill carries need a viewer, and the preview and related-files panes need
somewhere to render source. Placement follows the
D-0001-project-structure gradient, and the theming rule follows
packages/ts/obsidian-editor/src/theme.ts. The three existing CM6 mounts named in Today are the
prior art this package consolidates.