A VS Code companion extension for Oh My OpenAgent — a community-driven enhancement layer for OpenAI Codex CLI. It gives you a visual tree of agents, categories, and profiles, and a form-based editor for model overrides without hand-editing JSONC files.
- GitHub: github.com/oh-my-openagent/oh-my-openagent — main project repository
- Site: omo.dev — official documentation and downloads
Screenshots
The sidebar view shows your active config, all built-in agents and categories with their assigned models, and saved profiles. The editor panel opens on demand for any agent or category — it supports model selection, sampling parameters, thinking budgets, and fallback models.
| Sidebar overview | Agent editor in action |
|---|---|
![]() |
![]() |
Features
- Agent and category model overrides: see all 11 built-in agents and 8 built-in categories in a hierarchical tree. Edit any item in the webview form. Saving an edit to a built-in item creates its override. The tree renders labels like
sisyphus → opencode-go/kimi-k2.7-codeso you always know which model is assigned. - Ordered model cards: position 1 is Main and every later card is a fallback. Drag any fallback into position 1 to replace Main. The
Draghandle explains this on hover and supports keyboard reordering: press Space or Enter to pick up, use Arrow Up or Arrow Down to move, press Space or Enter to drop, or Escape to cancel. Main settings are shared defaults. In each card's Advanced section, a blank select showsInherit (<default>), a selected value is an override, an empty numeric input inherits the value shown by its placeholder, and a populated numeric input is an override. Shared Temperature and Top-p defaults remain editable when a model reports no sampling support; that model's card inputs are disabled with an explanatory tooltip, and inherited values are not serialized as card overrides. - Lazy model picker — the Model field is populated asynchronously from the local
opencode models --verboseCLI, with a free-form fallback when the CLI is unavailable. The discovered model IDs appear as autocomplete suggestions alongside each model's capabilities and variants. A reload button lets you re-run discovery at any time. - JSONC preservation — all writes go through
jsonc-parservia a per-path diff engine. TheConfigStorecompares the original and modified config recursively, then callsmodify()on each changed JSON path individually. Comments, trailing commas, and formatting on untouched keys survive every edit. - Profiles — canonical internal snapshots of the current
agentsandcategories, stored in a sidecar file (omo.profiles.json). A profile remains the source of truth when activated: edits update the profile first and then project it toomo.jsoncusing the selected harness and routing model. Each profile can carry an optional description. The active profile is marked with a check icon and(active)label. - Profile import and export — move individual profiles or your whole sidecar in and out as JSON or JSONC. Import a single
{ agents, categories }fragment, or import a full{ version: 1, profiles: [...] }sidecar and choose whether to extend the existing list or replace it. Export one profile or every profile at once. - JSON profile editing — open a saved profile or the active config's
agents/categoriesas JSON in an untitled editor, edit freely, and save to apply. Useful for bulk changes that the form editor does not expose. - Selectable harness and routing model — one settings flow sequentially selects the config scope (
global,opencode,senpi,codex) and disk routing model (latest,mainline). Both selections appear side by side on the config item. Changing either selection reprojects the active profile; switching toglobalfirst reconcilesomo.jsonc, because harness blocks would otherwise shadow every global edit. - Sidebar integration — the
Oh My OpenAgentactivity bar view puts everything one click away. Three collapsible groups (Agents, Categories, Profiles) with inline edit buttons, context menu actions, and tooltips that show configured parameters on hover. - Commands where they belong:
Open Agent Manager,Configure Harness and Routing Model,Refresh,Create Profile,Import Profiles, andExport All Profilesare available from the Command Palette and view title. Editing, override management, profile actions, and JSON editing appear only when their sidebar context applies.
Requirements
- VS Code 1.85 or newer
- An existing Oh My OpenAgent configuration, or a first-run scenario where the extension will create one for you
Development and packaging require Node.js 22 or newer.
Development and packaging require Node.js 22 or newer.
Config scope
The extension can edit different parts of the unified omo.jsonc config. Choose the active config scope to control where agent and category overrides are written:
global— the shared base ofomo.jsonc. Use this for settings that apply to every harness. Onlyagentsandcategoriesare written here;agent_orderanddisabled_agentsare ignored/stripped if present.opencode— the[opencode]harness block. This is the default scope. All OmO keys (agents,categories,agent_order,disabled_agents) can be written here.senpi— the[senpi]harness block. Onlyagentsandcategoriesare written here.codex— the[codex]harness block. Onlyagentsandcategoriesare written here.
Choose the scope in the first step of Oh My OpenAgent: Configure Harness and Routing Model, available from the Command Palette and the Models view-title gear. The picker lists all four scopes and marks the current one before the routing-model step.
Switching to the global scope
Harness blocks take precedence over the shared base, so while [opencode], [senpi], or [codex] defines agents or categories, nothing written to the base can reach that harness. When you pick global and such a block exists, the command asks how to update omo.jsonc before switching:
- Remove Harness Blocks — delete every
[<harness>]block, leaving the shared base as the only source of overrides. This is the durable choice: laterglobaledits keep applying everywhere. - Copy Global to All Harnesses — make every harness block's
agentsandcategoriesmatch the shared base: a key the base defines replaces the harness copy, and a key it leaves undefined is dropped from the block so it cannot shadow a value you add later. Harness-only keys such asagent_orderare kept. This reconciles the file once; a laterglobaledit to a key the blocks now define is shadowed again.
Both rewrites preserve comments and formatting. Cancelling the prompt leaves the scope and omo.jsonc untouched. Switching to a harness scope never rewrites the file, because that block already wins on read.
Your choice is persisted as a configScope field inside the omo.profiles.json sidecar file, next to the user config. It is not stored as a VS Code setting. On activation the extension restores the persisted scope, falling back to opencode when none is saved.
The sidebar config item shows both selections side by side (for example, opencode · latest). Switching scope closes any open agent editor and reports the change, so stale edits cannot be saved into the wrong block.
The active scope controls all writes: agent/category editor saves, profile activation, and the active-profile JSON editor all target the selected scope. Project-layer reads still merge the shared base with the selected harness block; sibling harness blocks and base keys outside the selected scope are preserved untouched.
Config file layers
- User layer —
~/.omo/omo.jsonc(falling back toomo.json) on every platform. This is where all writes go. - Project layers —
.omo/omo.jsonc(then.omo/omo.json) in every directory from the workspace root up to your home directory. The nearest project file wins on read and beats the user layer; the extension never writes to project files.
On a fresh install the extension creates ~/.omo/omo.jsonc on first write. Legacy oh-my-openagent.json[c] / oh-my-opencode.json[c] files are no longer read — run bunx oh-my-openagent config migrate once to import them into the unified file.
Profiles live next to the user config in omo.profiles.json. A legacy oh-my-openagent.profiles.json sidecar is renamed automatically on first access.
Routing dialect
The extension can write agent and category routing to omo.jsonc in either of two dialects. Choose the active routing dialect to match the version of Oh My OpenAgent you are running:
mainline— the omo ≥ 5.0.0 dialect. Writes one orderedmodelsarray per agent or category. The first entry is the main model merged with its overrides, and later entries are fallbacks. A reasoning-levelvariantis stored asreasoning.latest— the omo 4.x stable dialect, and the default. In theopencodescope it writesmodelplus flattened top-level overrides plusfallback_models; in thesenpiandcodexscopes it writes themodelsarray; in theglobalscope it writes model-only entries and drops fallback chains, with an editor warning when a chain cannot be represented.
Select both the harness and routing model with Oh My OpenAgent: Configure Harness and Routing Model, available from the Command Palette and the gear icon in the Models view title. The two sequential pickers mark their current values; the config item displays the result as <harness> · <routing model>.
The choices are persisted as configScope and routingDialect fields inside the omo.profiles.json sidecar file, next to the user config. They are not stored as VS Code settings. On activation the extension restores them, defaulting to opencode and latest. When an active profile exists, changing either choice immediately reprojects that unchanged internal profile to omo.jsonc; without an active profile, the choice applies on the next config write.
Why two dialects?
The 4.x and 5.x runtimes disagree on which routing keys are valid. In omo 4.19.4 the plugin schema rejects agents.*.models (unknown key, doctor fails), while its strict unified core schema rejects agents.*.fallback_models and agents.*.category at the root and inside [senpi] and [codex]. The [opencode] block is opaque to the core schema, so [opencode].agents.*.fallback_models is the only agent-chain encoding that passes doctor on 4.x stable (with a harmless "deprecated key" warning) and is honored by both the 4.x and 5.x runtimes. categories.*.models is valid on both versions. The latest dialect keeps configs compatible with omo 4.x stable; the mainline dialect opts into the newer models-array schema for omo ≥ 5.0.0.
Requirements
- VS Code 1.85 or newer
- An existing Oh My OpenAgent configuration, or a first-run scenario where the extension will create one for you
Installation
From a .vsix file
- Download
oh-my-openagent-vscode-X.Y.Z.vsixfrom the release page. - Open VS Code and run
Extensions: Install from VSIX...from the Command Palette. - Select the downloaded file.
Development build
-
Clone the repository:
git clone https://github.com/oh-my-openagent/oh-my-openagent-vscode.git cd oh-my-openagent-vscode -
Install dependencies:
npm install -
Compile:
npm run compile -
Press
F5to open the Extension Development Host with the extension loaded.
Usage
Opening the view
- Click the
Oh My OpenAgentactivity bar icon (robot symbol). - Or run the command
Oh My OpenAgent: Open Agent Managerfrom the Command Palette.
The sidebar nests the tree under the active config file:
- Active config file — the name of the user-layer file (e.g.
omo.jsonc). Hover to see the full resolved path. It expands to show the active profile (when one is active) and, nested under it, the Agents and Categories groups. When no profile is active, Agents and Categories appear directly under the config file. - Agents — built-in agents; overridden agents are shown as override items.
- Categories — built-in categories; overridden categories are shown as override items.
- Profiles — saved snapshots of your agents and categories. A root-level sibling of the config file.
Agents, categories, and profiles are expandable when they contain configured values:
- An expanded agent or category shows its configured parameters (
variant,reasoning,temperature,top_p,maxTokens,thinking,verbosity,disabled) and afallbacks (N)group with each fallback model. - An expanded profile shows nested Agents and Categories subgroups with the same
name → modelleaves you see in the main tree, so you can inspect what the profile captured before activating it.
The Profiles group always shows the active state: when no profile is active, a No active profile indicator appears at the top of the group. The active profile is marked with a check icon and an (active) description.
Editing an agent or category
- Hover over the agent or category and click the pencil inline action, or right-click and choose
Edit Agent/Edit Category. Both built-in items, existing override items, and profile-contained items can be edited. - The webview editor opens one ordered Model routing list plus shared Default generation settings.
- The cards form one ordered model list. Position 1 is Main, and later cards are fallbacks. Drag any fallback into position 1 to replace Main. Hover over a
Draghandle for this reminder. For keyboard reordering, focus a handle, press Space or Enter to pick up, use Arrow Up or Arrow Down to move, press Space or Enter to drop, or Escape to cancel. There are no separate promotion or move controls. - The main Model field is a free-form text input with a lazy datalist. While the editor loads, the extension runs
opencode models --verboselocally and offers the returned model IDs as autocomplete suggestions, together with each model's capabilities and variants. Any existing model value is preserved, even if it is not in the discovered list. - The defaults section sets shared Reasoning effort, Thinking, Temperature, Top-p, and Max tokens values.
variantand the legacyreasoningEffortfield remain preserved in stored data but are not exposed as editable generation controls. - Each card's Advanced section has one control per setting. For Reasoning effort and Thinking, the blank option reads
Inherit (<default>); selecting another option creates an override. For numeric settings, an empty input inherits the placeholder value and a populated input creates an override. Clearing a control returns it to inheritance. - Hover over the reload button next to the Model field to re-run discovery and refresh the model list at any time. If discovered capabilities do not support an effective setting, including an inherited setting, the editor marks the conflict and blocks saving until you clear or change it.
- Use a fallback's Remove button to remove it. Removing the final fallback explicitly removes the fallback chain from the saved config.
- Change values and click Save. Saving a built-in agent or category creates its override in the active config. The sidebar refreshes after the JSONC-preserving write completes. Fields that are not exposed in the form, such as
permission,tools,prompt, andproviderOptions, are preserved rather than overwritten. - The upstream config can store only top-level defaults and fallback entries. It cannot represent the fallback intent attached to the model that is currently Main after the editor is closed and reopened. Transient webview restoration preserves dirty in-panel state, but a saved config cannot preserve that Main model's fallback intent across a new editor session.
- Hover over any agent or category leaf in the sidebar to see a tooltip with the configured parameters (temperature, top-p, max tokens, reasoning effort, thinking budget, variant, and fallback models).
Context menu actions
Right-click items in the Models view for more options:
- On a built-in agent:
Edit Agentopens the editor. Saving creates the agent override. - On a built-in category:
Edit Categoryopens the editor. Saving creates the category override. - On an override item:
Edit Agent/Edit Categoryopens the editor. - On a profile:
Activate,Rename,Duplicate,Delete,Export Profile, orEdit Profile JSON. - Profile-contained agent/category leaves reuse the same
Edit Agent/Edit Categorycommands as the main tree. - On a modified active profile:
Save Active Profilesnapshots the current config back into that profile. - On the active config file item:
Edit Active Profile JSONopens the active config'sagents/categoriesas JSON. - On the Profiles group header:
Create Profile from Config File…,Import Profiles, orExport All Profiles.
The view title also provides one Configure Harness and Routing Model settings button, plus Refresh, Create Profile, Import Profiles, and Export All Profiles.
Commands
The extension contributes 17 commands. All are prefixed with Oh My OpenAgent. Open Agent Manager, Configure Harness and Routing Model, Refresh, Create Profile, Create Profile from Config File…, Import Profiles, and Export All Profiles are visible in the Command Palette and view title. The remaining commands are contextual sidebar actions.
| Command | Availability | What it does |
|---|---|---|
Open Agent Manager |
Command Palette | Focuses the Oh My OpenAgent sidebar view. |
Configure Harness and Routing Model |
Command Palette and view title | Sequentially selects the active harness (global, opencode, senpi, codex) and routing model (latest, mainline). The config item shows both selections side by side. Command id: ohMyOpenAgent.configureSettings. |
Edit Agent |
Contextual | Opens the editor for the selected agent. |
Edit Category |
Contextual | Opens the editor for the selected category. |
Refresh |
Command Palette and view title | Refreshes the Models tree from disk. |
Create Profile |
Command Palette and view title | Creates a new profile from the current config. |
Create Profile from Config File… |
Command Palette | Creates a profile from a .json or .jsonc Oh My OpenAgent config file's agents and categories sections. The active config is not modified. |
Activate Profile |
Contextual | Applies the selected profile to the active config. |
Rename Profile |
Contextual | Renames the selected profile. |
Duplicate Profile |
Contextual | Creates a copy of the selected profile. |
Delete Profile |
Contextual | Deletes the selected profile after confirmation. |
Save Active Profile |
Contextual | Saves the current config into the modified active profile. |
Import Profiles |
Command Palette and view title | Imports one .json or .jsonc file as a single profile fragment or a full sidecar. |
Export All Profiles |
Command Palette and view title | Exports the full sidecar to a JSON file. |
Export Profile |
Contextual | Exports the selected profile as a single { agents, categories } fragment. |
Edit Profile JSON |
Contextual | Opens the selected saved profile's agents/categories as JSON for editing. |
Edit Active Profile JSON |
Contextual | Opens the active config's agents/categories as JSON for editing. |
Profiles
Profiles are named snapshots of the agents and categories sections of your active config. They are stored in omo.profiles.json, next to the user config file.
Create a profile
- Click the
Create Profileicon in the Models view title, or runOh My OpenAgent: Create Profile. - Enter a unique profile name.
- Optionally enter a description.
The new profile captures the current agents and categories exactly as they are on disk.
To create a profile from another config file instead of the active config, use Create Profile from Config File… (Command Palette or right-click the Profiles group header). It extracts agents and categories from any Oh My OpenAgent .json/.jsonc config — a full omo.jsonc works (the [opencode] block is merged over the shared base); other top-level keys are ignored — and never modifies the active config.
Activate a profile
- Right-click the profile in the sidebar and choose
Activate. - The active config's
agentsandcategoriessections are replaced with the profile's values.
Activation preserves comments and trailing commas in the active config because it reuses the same JSONC-preserving write path as the editor.
Rename, duplicate, or delete a profile
- Rename updates the profile name. If it was the active profile,
lastActiveProfileis updated automatically. - Duplicate creates a deep copy under a new name; the original is unchanged.
- Delete asks for confirmation and removes the profile. If it was the active profile, the active marker is cleared.
Import and export format
The transfer layer accepts both single-profile fragments and full sidecar files. Input may be JSON or JSONC (comments and trailing commas are allowed). Output is always canonical JSON with two-space indentation and sorted object keys.
A single-profile fragment contains only the profile payload:
{
"agents": {
"sisyphus": {
"model": "opencode-go/kimi-k2.7-code"
}
},
"categories": {
}
}
At least one of agents or categories must be present. The top-level keys version and profiles are reserved for sidecar files; a fragment cannot mix them with agents or categories.
A full sidecar follows this shape:
{
"version": 1,
"profiles": [
{
"name": "fast",
"agents": {
"sisyphus": {
"model": "opencode-go/kimi-k2.7-code"
}
},
"createdAt": "2026-07-23T12:00:00Z",
"updatedAt": "2026-07-23T12:00:00Z"
}
],
"lastActiveProfile": "fast"
}
version must be 1. profiles is required. lastActiveProfile is optional. Each profile object may contain name, description, agents, categories, createdAt, and updatedAt. Timestamps must be valid ISO 8601 strings.
Import semantics:
- JSONC input is accepted; the parser allows comments and trailing commas. Canonical JSON is produced on export.
- Semantic losslessness: values and structure survive, but comments, formatting, and key order are normalized. Export sorts object keys alphabetically.
- Extend (default) appends imported profiles to the existing list. Replace overwrites the existing list.
- Name collisions are resolved with exact case-sensitive matching. If
fastalready exists, the imported profile becomesfast-2, thenfast-3, and so on. - Size limit: transfer inputs are rejected when they exceed 5 MiB. UTF-8 is required; a leading UTF-8 BOM is accepted and stripped.
- Imported
lastActiveProfileis ignored. Your local active marker is preserved only when a profile with that exact name still exists after the import. - No auto-activation: importing a profile or sidecar updates the sidecar file only; the active config is not changed.
Export semantics:
- Single-profile export writes
{ agents?, categories? }as a fragment file. - Full sidecar export writes
{ version: 1, profiles: [...], lastActiveProfile? }. - Provider options warning: export warns when a profile contains non-empty
providerOptions, because provider options often hold credentials or API keys. The warning is informational; you can cancel or proceed. - Active saved-profile save: when you save a modified active profile, the active config is updated first, then the profile is snapshotted. If snapshotting fails, the config change remains and the sidecar stays unchanged, so partial failures leave the live config in the intended state.
Architecture
The extension follows a clean layered architecture with strict separation of concerns:
extension.ts (activation orchestrator)
|
├── commands.ts (17 command registrations)
|
├── profileTransferCommands.ts (import/export/JSON-edit handlers)
│ ├── profileTransferCommandHandlers.ts
│ └── profileTransferFiles.ts (VS Code open/save dialog helpers)
|
├── ui/
│ ├── agentModelTreeProvider.ts (sidebar TreeDataProvider)
│ ├── agentEditorPanel.ts (webview panel singleton and JSON editor host)
│ ├── profileJsonEditorHost.ts (active/saved profile JSON editing protocol)
│ └── webview/ (ordered model routing, capability validation, and ProfileJsonEditor)
│ ├── App.svelte / AgentFormEditor.svelte
│ └── ProfileJsonEditor.svelte
│
└── config/
├── schema.ts (TypeScript types for OmO config)
├── routingConversion.ts (internal ↔ public model routing)
├── configStore.ts (JSONC read/write, file watching)
├── profileStore.ts (profile CRUD, activation, import/export)
├── profileTransfer.ts (parser and byte-limit/UTF-8 validation)
├── profileValidation.ts (fragment/sidecar runtime validator)
├── profileEntryValidation.ts (per-field validation rules)
└── profileTransferSerialization.ts (canonical JSON, name collision, export helpers)
Key design decisions
- ConfigStore is pure Node.js — zero VS Code dependency, making it testable in isolation with vitest. File watching uses
fs.watchwith 150 ms debounce and asuppressWatchflag to ignore self-triggered events during atomic writes. - Profiles are canonical; routing is a projection — the editor and every saved profile keep the internal routing shape (
model,main_overrides,fallback_models).ProfileStorecanonicalizes public inputs before every sidecar write. Comparisons project both the profile and live config through the selected harness/routing model first, so equivalent shapes do not appear modified.mainline(omo ≥ 5.0.0) writes one orderedmodelsarray whose first entry is the main model merged with its overrides;latest(omo 4.x stable, the default) writesmodelplus flattened overrides and scope-dependent fallback routing.routingConversion.tsowns both directions, andConfigStoreconverts at theomo.jsoncboundary. - Atomic writes everywhere — both
ConfigStoreandProfileStorewrite via temp-file +fs.renameSync, guaranteeing no partial content even on crash. - Per-path JSONC diffing —
updateConfig()deep-clones the parsed config, runs the updater callback, thendiffConfigs()recursively compares original and draft. Each changed JSON path gets its ownjsonc-parsermodify()call, so comments and formatting on untouched keys are never disturbed. - Webview security — strict CSP with
default-src 'none', per-render nonces viacrypto.randomBytes(16), local resource roots restricted toout/only, and all DOM text insertion uses.textContent(neverinnerHTML). - Singleton editor panel —
AgentEditorPaneluses a staticcurrentPanelreference to prevent multiple webview instances. Panel state survives tab switches viaretainContextWhenHidden: true. - Sidecar profiles and config projection — profiles are stored in
omo.profiles.jsonso the main OmO config stays schema-clean. Activation and active-profile edits project the saved profile through the JSONC-preservingConfigStore.updateConfig()path without mutating the profile for the selected routing model. The chosen harness and routing model are persisted in the sidecar and restored on activation. - Transfer canonical JSON — export serializes only JSON-safe values (null, booleans, finite numbers, strings, dense arrays, and plain objects), sorts keys, and appends a trailing newline. This prevents accidental disclosure of getters, symbols, or cyclic structures.
- Profile JSON editor host —
profileJsonEditorHost.tsisolates the active/saved target protocol from the UI, whileProfileJsonEditor.svelteprovides a focused textarea with save, dirty tracking, and error display. - Scope-aware writes —
ConfigStorecarries aConfigScopevalue (global,opencode,senpi, orcodex). Reads merge the shared base with the selected harness block; writes prefix each JSONC patch with the matching harness block or target the root forglobal. The active scope is saved to and restored fromomo.profiles.jsonviaProfileStore, so the same scope is active across extension restarts without touching VS Code settings. - Global-scope reconciliation — because harness blocks outrank the shared base, selecting
globalwhile one of them definesagentsorcategorieswould make every global edit a no-op.ConfigStore.getShadowingHarnessScopes()detects that state and the command offers the two fixes,removeHarnessBlocks()orcopyBaseToHarnessBlocks(), before the scope changes. Both go through the same JSONC-preserving edit path as ordinary writes.
Built-in inventory
| Domain | Items |
|---|---|
| Agents | sisyphus, hephaestus, prometheus, oracle, librarian, explore, multimodal-looker, metis, momus, atlas, sisyphus-junior (11 total) |
| Categories | visual-engineering, ultrabrain, deep, artistry, quick, unspecified-low, unspecified-high, writing (8 total) |
Development
This extension is built with TypeScript and esbuild. Development and packaging require Node.js 22 or newer. The extension itself runs on VS Code 1.85 or newer.
# Install dependencies
npm install
# One-shot compile
npm run compile
# Watch mode
npm run watch
# Run tests
npm test
# Package for release
npm run package
To run the extension locally, press F5 in VS Code. This opens the Extension Development Host with the compiled extension loaded.
Tests
Tests are written with Vitest. The suite covers the extension's main behaviors:
| Suite | What it covers |
|---|---|
modelDiscovery.test.ts |
opencode models parsing, fallback handling, metadata normalization, and cache behavior |
agentModelTreeProvider.test.ts |
Tree structure, context values, override detection, active profile indicators, refresh, and disposal |
agentEditorPanel.test.ts |
Webview lifecycle, messages, save writes, profile creation, and model discovery reloads |
profileStore.test.ts |
Profile creation, rename, duplicate, isolation, activation, save-back, import, export, and change events |
profileTransfer.test.ts |
Byte limits, UTF-8 handling, JSONC parsing, duplicate-key detection, and fragment/sidecar classification |
profileTransferSerialization.test.ts |
Canonical JSON serialization, name derivation, collision resolution, and provider-options detection |
profileValidation.test.ts |
Fragment and sidecar validation, timestamp checks, nested field policies, and unknown-key rejection |
profileTransferCommands.test.ts |
Import/export/JSON-edit command handlers, dialogs, cancellation, and error reporting |
profileTransferFiles.test.ts |
VS Code open/save dialog helpers and successful transfer-file operations |
profileTransferFiles.rejections.test.ts |
Primitive rejection contract for transfer-file dialog failures |
smoke.test.ts |
End-to-end editor saves across stores, panel, tree, JSONC writes, profile transfer round-trips, and JSON editing |
packageMenus.test.ts |
The 17-command contribution surface and contextual menu visibility |
configStore.test.ts |
Config discovery, JSONC parsing, formatting-preserving updates, key removal, and file watching |
routingConversion.test.ts |
Internal ↔ public routing conversion for both dialects: models chains, model/fallback_models chains, main overrides, reasoning-style variants, precedence, and idempotency |
routingBoundary.test.ts |
End-to-end routing projection at the disk boundary: one canonical profile across mainline/latest, scope-specific hidden routing, legacy activation, inverse reads, snapshots, and JSON-editor saves |
modelRouting.test.ts |
Ordered-card promotion, shared defaults, fallback inheritance and overrides, serialization, removal, and session-bound routing intent |
modelCapabilities.test.ts |
Capability validation for explicit card overrides, including inherited sampling defaults that unsupported models do not serialize as overrides |
webview.test.ts |
Model picker behavior, simplified inherit/override controls, legacy-field preservation, drag promotion, fallback editing, profile JSON editor UI, and persisted state |
editorPayloadValidation.test.ts |
Structured-editor allow-lists for agent and category save payloads |
reorder.test.ts |
Fallback list reordering via drag and keyboard |
schema.test.ts |
Profile schema contract and shape invariants |
The JSONC preservation tests verify that comments, trailing commas, and formatting survive round-trips through updateConfig() and profile activation — confirmed against real config fixtures with inline comments and trailing commas.
npm test
Release / packaging
-
Update the version in
package.json. -
Run the packaging command:
npm run packagenpm run packageproduces a.vsixfile in the current directory. -
The resulting
.vsixfile can be uploaded to a release page or installed directly.
The package script uses the maintained @vscode/vsce packaging tool. The packaging rules in .vscodeignore make sure out/extension.js, out/webview.js, src/ui/webview/webview.html, and src/ui/webview/webview.css are included, while source maps, tests, and node_modules are excluded. Generated VSIX files and verification evidence are kept in .omo/evidence and are not committed.
License
MIT License

