command-code 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/bundled/command-code-knowledge/SKILL.md +2 -1
- package/dist/bundled/command-code-knowledge/reference/custom-agents.md +7 -7
- package/dist/bundled/command-code-knowledge/reference/custom-slash-commands.md +5 -5
- package/dist/bundled/command-code-knowledge/reference/headless.md +7 -7
- package/dist/bundled/command-code-knowledge/reference/hooks.md +7 -7
- package/dist/bundled/command-code-knowledge/reference/mcp.md +8 -8
- package/dist/bundled/command-code-knowledge/reference/permissions.md +75 -75
- package/dist/bundled/command-code-knowledge/reference/plan-mode.md +2 -0
- package/dist/bundled/command-code-knowledge/reference/plan-review.md +226 -0
- package/dist/bundled/command-code-knowledge/reference/skills.md +27 -27
- package/dist/bundled/mod-builder/reference/api.md +21 -21
- package/dist/bundled/mod-builder/reference/hooks-and-events.md +48 -48
- package/dist/bundled/mod-builder/reference/overview.md +19 -17
- package/dist/bundled/mod-builder/reference/packaging.md +6 -6
- package/dist/bundled/mod-builder/reference/ui.md +9 -9
- package/dist/bundled/mod-builder/reference/verify.md +11 -11
- package/dist/cli.mjs +2 -2
- package/package.json +4 -4
- package/vsix/commandcode-vscode.vsix +0 -0
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# Mods
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **Experimental.** The `ModApi` is new and still taking shape. Surfaces and signatures can change as we learn from how mods get built - so pin what you ship, and tell us what's missing. Your feedback is what stabilizes it.
|
|
6
|
+
|
|
7
|
+
Mods are TypeScript packages that let you modify almost any behavior of Command Code. They're far more powerful than the plugin or extension APIs you'll find in other agents - though you can absolutely use one to build a plugin or an extension. Each mod is written against the `ModApi`: a plain TypeScript file that Command Code discovers on disk, loads at startup, and compiles onto its agent loop. One file can add tools the model calls, slash commands, mutating lifecycle hooks, event observers, typed-input interception, custom feed rendering, configurable flags, and model providers. Command Code's own built-in features - providers, session titling, the update notice - are built as mods against this very same API. If Command Code can do it, a mod can change it.
|
|
6
8
|
|
|
7
9
|
A loadable mod IS an `AgentMod` once loaded; the mod host just builds it from a factory file instead of a code import:
|
|
8
10
|
|
|
@@ -22,7 +24,7 @@ addRenderer ──► custom feed entries (showEntry → styled lines in t
|
|
|
22
24
|
queueMessage ──► the loop's steering / follow-up drains
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
The factory receives the API bound as `cmd
|
|
27
|
+
The factory receives the API bound as `cmd`. Registration verbs are all `add*` and each returns a `Disposable` - call `.dispose()` to undo exactly that one registration.
|
|
26
28
|
|
|
27
29
|
This page is the whole mods surface end to end: the quick start and loading rules first, then the full **ModApi reference**, the **hooks and events** contract, the **UI surface**, **packaging and install**, and how to **verify a mod**. Jump to any section from the sidebar.
|
|
28
30
|
|
|
@@ -36,7 +38,7 @@ Create `~/.commandcode/mods/review-guard.ts`:
|
|
|
36
38
|
import type {ModApi} from '@commandcode/harness';
|
|
37
39
|
|
|
38
40
|
export default function (cmd: ModApi) {
|
|
39
|
-
// Block dangerous writes (a mutating hook
|
|
41
|
+
// Block dangerous writes (a mutating hook - see the hooks catalog).
|
|
40
42
|
cmd.hooks({
|
|
41
43
|
beforeToolCall: async ({toolName, input}) => {
|
|
42
44
|
if (toolName !== 'shell_command') return undefined;
|
|
@@ -67,7 +69,7 @@ export default function (cmd: ModApi) {
|
|
|
67
69
|
handler: () => ({prompt: 'List every TODO comment in this repo and rank by urgency.'}),
|
|
68
70
|
});
|
|
69
71
|
|
|
70
|
-
// Observe the event stream (never mutates
|
|
72
|
+
// Observe the event stream (never mutates - mutation is what hooks are for).
|
|
71
73
|
cmd.on('turn_end', () => cmd.ui.notify('turn finished'));
|
|
72
74
|
}
|
|
73
75
|
```
|
|
@@ -98,8 +100,8 @@ Dot-entries and `node_modules` are never scanned (the package registry lives und
|
|
|
98
100
|
|
|
99
101
|
## The one rule: hooks mutate, `on` observes
|
|
100
102
|
|
|
101
|
-
- **`cmd.hooks({...})`** is the only place that can change behavior
|
|
102
|
-
- **`cmd.on(event, ...)`** only observes
|
|
103
|
+
- **`cmd.hooks({...})`** is the only place that can change behavior - block a tool (`beforeToolCall`), rewrite a result (`afterToolCall`), add to the prompt (`appendSystemPrompt`), rewrite typed input (`transformInput`), force a finished run to keep going (`onStop`), react to session start/end (`onSessionStart`/`onSessionEnd`), or run post-turn work (`onRunEnd`). Multiple `hooks()` calls compose in registration order.
|
|
104
|
+
- **`cmd.on(event, ...)`** only observes - it cannot block or rewrite. Handlers are isolated (a throw becomes a `mod_error` event, never a crash).
|
|
103
105
|
|
|
104
106
|
If you find yourself wanting an `on` handler to stop a tool, you want a hook instead. The full mutating surface is in [Hooks and events](./hooks-and-events.md#hooks-and-events); the full registration/live surface is the [ModApi reference](./api.md#mod-api-reference).
|
|
105
107
|
|
|
@@ -107,28 +109,28 @@ If you find yourself wanting an `on` handler to stop a tool, you want a hook ins
|
|
|
107
109
|
|
|
108
110
|
## Built-in mods
|
|
109
111
|
|
|
110
|
-
Command Code's own features ride this exact API. First-party providers (`provider-anthropic` / `provider-copilot` / `provider-openai`), the update notice, and the harness-side titling and taste-learning triggers are **built-in mods**: compiled-in factories registered on the same host before any discovered mod. They are not special
|
|
112
|
+
Command Code's own features ride this exact API. First-party providers (`provider-anthropic` / `provider-copilot` / `provider-openai`), the update notice, and the harness-side titling and taste-learning triggers are **built-in mods**: compiled-in factories registered on the same host before any discovered mod. They are not special - they use `cmd.addProvider`, `cmd.on`, and `cmd.hooks` like any mod, appear in `cmd mods list` with source `builtin`, and honor the same disable key:
|
|
111
113
|
|
|
112
114
|
```json
|
|
113
115
|
{"mods": {"disabled": ["provider-copilot", "update-notice", "titling", "learning"]}}
|
|
114
116
|
```
|
|
115
117
|
|
|
116
|
-
Built-in mods always win a name collision against a discovered mod of the same name (the loader shadows the file with a warning), and they are compiled in
|
|
118
|
+
Built-in mods always win a name collision against a discovered mod of the same name (the loader shadows the file with a warning), and they are compiled in - never jiti-loaded from a writable path, so they are not supply-chain surface. Structural harness mods (workspace, compaction, checkpoints) are load-bearing for correctness and stay unconditional; only the observer-style built-ins above are disable-able.
|
|
117
119
|
|
|
118
120
|
---
|
|
119
121
|
|
|
120
122
|
## Runnable examples
|
|
121
123
|
|
|
122
|
-
Runnable, single-file example mods ship with Command Code inside the bundled `mod-builder` skill (`src/skills/bundled/mod-builder/examples/`) and are validated in CI
|
|
124
|
+
Runnable, single-file example mods ship with Command Code inside the bundled `mod-builder` skill (`src/skills/bundled/mod-builder/examples/`) and are validated in CI - they load through the real loader on every test run, so they never rot. Ask Command Code to "build a mod" and it reads these.
|
|
123
125
|
|
|
124
126
|
| File | Shows |
|
|
125
127
|
|---|---|
|
|
126
|
-
| `slash-command.ts` | `addCommand`
|
|
127
|
-
| `custom-tool.ts` | `addTool`
|
|
128
|
-
| `block-dangerous-commands.ts` | `hooks.beforeToolCall`
|
|
129
|
-
| `input-shortcuts.ts` | `hooks.transformInput`
|
|
128
|
+
| `slash-command.ts` | `addCommand` - a `/command` returning `{prompt}` or `{message}` |
|
|
129
|
+
| `custom-tool.ts` | `addTool` - a model-callable tool with `run` + `exec` |
|
|
130
|
+
| `block-dangerous-commands.ts` | `hooks.beforeToolCall` - block/allow with a confirm |
|
|
131
|
+
| `input-shortcuts.ts` | `hooks.transformInput` - rewrite / handle typed input |
|
|
130
132
|
| `observe-events.ts` | `on(event)` + the cross-mod `events` bus |
|
|
131
|
-
| `custom-entry-renderer.ts` | `addRenderer` + `showEntry`
|
|
133
|
+
| `custom-entry-renderer.ts` | `addRenderer` + `showEntry` - styled feed rows |
|
|
132
134
|
| `flags-and-options.ts` | `addFlag` / `getFlag` + `--mod-option` |
|
|
133
135
|
| `lifecycle-hooks.ts` | `hooks.onStop` (Stop) + `onSessionStart`/`onSessionEnd` + `afterToolCall` `isError` + `on('subagent_start'/'subagent_stop')` |
|
|
134
136
|
| `status-and-widgets.ts` | `ui.setStatus` footer segment + `ui.widget` above the editor + a timed confirm |
|
|
@@ -139,9 +141,9 @@ Runnable, single-file example mods ship with Command Code inside the bundled `mo
|
|
|
139
141
|
## Boundaries (deliberate)
|
|
140
142
|
|
|
141
143
|
- **Hooks mutate, `on` observes.** Event handlers cannot block tools or rewrite context; that is what `cmd.hooks` is for.
|
|
142
|
-
- **Project mods are trust-gated** like project skills: they load only after the workspace trust prompt, because a mod is arbitrary code. User-scope and `--mod` mods always load. There is no sandbox
|
|
143
|
-
- **Print mode loads user-scope and `--mod` mods only**, with the ui bridge degraded to headless defaults (confirm → false, select/input → undefined
|
|
144
|
-
- **Mod-queued messages don't echo in the feed** the way typed input does
|
|
144
|
+
- **Project mods are trust-gated** like project skills: they load only after the workspace trust prompt, because a mod is arbitrary code. User-scope and `--mod` mods always load. There is no sandbox - install packages you trust. Package installs run npm with `--ignore-scripts` (mods are jiti-loaded TypeScript; they need no build step, so lifecycle scripts are pure attack surface).
|
|
145
|
+
- **Print mode loads user-scope and `--mod` mods only**, with the ui bridge degraded to headless defaults (confirm → false, select/input → undefined - never auto-approved; `setStatus`/`widget` render nowhere; timed dialogs resolve `timeoutValue` immediately). Project mods stay out of headless runs because print never shows a trust prompt; pass `--dangerously-skip-permissions` to opt a repo's own mods into a headless run (CI).
|
|
146
|
+
- **Mod-queued messages don't echo in the feed** the way typed input does - they land in the transcript and steer the model, but the visible record is the model's response.
|
|
145
147
|
- **Rendering is line-based, not component-based.** `cmd.addRenderer` returns styled text lines the host prints as feed rows; mods do not mount React components into the TUI. That keeps renderers host-agnostic (the same mod renders in any future host) and a crashing renderer degrades to a warning notice, never a broken screen.
|
|
146
148
|
- **Reload is the `/reload` path.** Mods load once per process; `/reload` restarts the process, which re-discovers and re-imports every mod (jiti caches nothing between loads). There is no in-place hot swap.
|
|
147
149
|
- **Session controls stop at the harness surface.** `cmd.sessions` covers what the live harness owns (compact, tree, navigate, labels); creating/switching/forking sessions is host lifecycle, not harness state, and stays with the host UI.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Packaging and install
|
|
4
4
|
|
|
5
|
-
A mod starts life as a loose file in `~/.commandcode/mods/`. When it should be shared
|
|
5
|
+
A mod starts life as a loose file in `~/.commandcode/mods/`. When it should be shared - with a team, or the world - it becomes a **package**: an npm package, a git repo, or a local directory that `cmd mods add` installs and Command Code loads on every session.
|
|
6
6
|
|
|
7
7
|
## Install, remove, list, update
|
|
8
8
|
|
|
@@ -16,11 +16,11 @@ cmd mods update # reinstall missing, reconcile pinne
|
|
|
16
16
|
cmd mods remove owner/repo
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Sources persist in the `mods.sources` settings key (project scope writes `.commandcode/settings.json`, `-g` writes `~/.commandcode/settings.json`). Identity is version/ref-agnostic
|
|
19
|
+
Sources persist in the `mods.sources` settings key (project scope writes `.commandcode/settings.json`, `-g` writes `~/.commandcode/settings.json`). Identity is version/ref-agnostic - `owner/repo@v1` and `https://github.com/owner/repo` are the same package, and a project entry shadows the same identity at user scope. Installs land in `<scope>/.commandcode/mods/.registry/{npm,git}/…`; startup never runs npm/git on its own - a configured-but-missing package is a warning pointing at `cmd mods update`.
|
|
20
20
|
|
|
21
21
|
## What a package ships
|
|
22
22
|
|
|
23
|
-
A package declares what it ships via `package.json`
|
|
23
|
+
A package declares what it ships via `package.json` - exact paths, directories, or globs (expanded against the package root; entries escaping the root are dropped):
|
|
24
24
|
|
|
25
25
|
```json
|
|
26
26
|
{
|
|
@@ -45,7 +45,7 @@ A `mods.sources` entry can be the object form to load only part of a package:
|
|
|
45
45
|
}
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
Four pattern kinds, applied in precedence order: `-path` force-exclude (exact, beats everything) → `+path` force-include (exact, restores what globs dropped) → `!glob` exclude → plain-glob include (when any includes exist, an entry must match one). Patterns match the entry's package-relative path or its mod name. `cmd mods add` / `remove` preserve hand-written object entries
|
|
48
|
+
Four pattern kinds, applied in precedence order: `-path` force-exclude (exact, beats everything) → `+path` force-include (exact, restores what globs dropped) → `!glob` exclude → plain-glob include (when any includes exist, an entry must match one). Patterns match the entry's package-relative path or its mod name. `cmd mods add` / `remove` preserve hand-written object entries - they never flatten your filters.
|
|
49
49
|
|
|
50
50
|
## Disabling without deleting
|
|
51
51
|
|
|
@@ -57,7 +57,7 @@ Works for discovered files, installed packages, and the disable-able built-ins (
|
|
|
57
57
|
|
|
58
58
|
## Trust and safety
|
|
59
59
|
|
|
60
|
-
- **There is no sandbox**
|
|
60
|
+
- **There is no sandbox** - a mod is arbitrary code; install packages you trust.
|
|
61
61
|
- **Project mods are trust-gated** like project skills: they load only after the workspace trust prompt. User-scope and `--mod` mods always load.
|
|
62
|
-
- **Package installs run npm with `--ignore-scripts`**
|
|
62
|
+
- **Package installs run npm with `--ignore-scripts`** - mods are jiti-loaded TypeScript; they need no build step, so lifecycle scripts are pure attack surface.
|
|
63
63
|
- **Print mode loads user-scope and `--mod` mods only.** Project mods stay out of headless runs because print never shows a trust prompt; pass `--dangerously-skip-permissions` to opt a repo's own mods into a headless run (CI).
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
# UI surface
|
|
4
4
|
|
|
5
|
-
Everything a mod can put on screen rides `cmd.ui`, `cmd.addRenderer`, and `cmd.showEntry`. All of it is line-based and host-agnostic: the TUI wires real rendering, headless runs degrade to deterministic defaults, and a crashing renderer becomes a warning
|
|
5
|
+
Everything a mod can put on screen rides `cmd.ui`, `cmd.addRenderer`, and `cmd.showEntry`. All of it is line-based and host-agnostic: the TUI wires real rendering, headless runs degrade to deterministic defaults, and a crashing renderer becomes a warning - never a broken screen.
|
|
6
6
|
|
|
7
7
|
## Notifications and dialogs
|
|
8
8
|
|
|
9
|
-
- `cmd.ui.notify(message)`
|
|
10
|
-
- `cmd.ui.confirm({title})` / `cmd.ui.select({title, options})` / `cmd.ui.input({title})`
|
|
9
|
+
- `cmd.ui.notify(message)` - a `notice` feed row.
|
|
10
|
+
- `cmd.ui.confirm({title})` / `cmd.ui.select({title, options})` / `cmd.ui.input({title})` - the Interaction question modal in the TUI. Headless, each resolves its deterministic default: confirm → `false`, select/input → `undefined` - never auto-approved.
|
|
11
11
|
|
|
12
12
|
### Timed dialogs
|
|
13
13
|
|
|
14
|
-
Each dialog accepts `{timeoutMs, timeoutValue}`: after `timeoutMs` the dialog auto-resolves `timeoutValue` (default: the dialog's headless default). The TUI shows a visible countdown and dismisses the modal at the deadline; on a TIMED dialog a dismissal without an answer (auto-dismiss or Esc) also resolves `timeoutValue`. Headless, a timed dialog resolves `timeoutValue` immediately
|
|
14
|
+
Each dialog accepts `{timeoutMs, timeoutValue}`: after `timeoutMs` the dialog auto-resolves `timeoutValue` (default: the dialog's headless default). The TUI shows a visible countdown and dismisses the modal at the deadline; on a TIMED dialog a dismissal without an answer (auto-dismiss or Esc) also resolves `timeoutValue`. Headless, a timed dialog resolves `timeoutValue` immediately - it never blocks a print run.
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
17
|
const proceed = await cmd.ui.confirm({
|
|
@@ -23,11 +23,11 @@ const proceed = await cmd.ui.confirm({
|
|
|
23
23
|
|
|
24
24
|
## Footer status segments
|
|
25
25
|
|
|
26
|
-
`cmd.ui.setStatus(text | null)`
|
|
26
|
+
`cmd.ui.setStatus(text | null)` - a persistent per-mod segment in the TUI footer (under the input panel). One segment per mod: a new call replaces the text, `null` clears it, the returned `Disposable` clears it too. Segments from multiple mods concatenate in load order. Headless: renders nowhere (no-op).
|
|
27
27
|
|
|
28
28
|
## Editor widgets
|
|
29
29
|
|
|
30
|
-
`cmd.ui.widget({placement: 'above-editor' | 'below-editor', render: () => lines})`
|
|
30
|
+
`cmd.ui.widget({placement: 'above-editor' | 'below-editor', render: () => lines})` - a line-based widget the TUI renders around the input panel. Same verbatim-lines contract as `addRenderer` (style with ansi); `render` re-runs on every repaint, and `cmd.ui.refreshWidgets()` requests a repaint after your data changes. A throwing render is skipped (reported as a `mod_error`) so siblings keep rendering. Headless: no-op.
|
|
31
31
|
|
|
32
32
|
```ts
|
|
33
33
|
let failing = 0;
|
|
@@ -43,8 +43,8 @@ cmd.on('tool_completed', () => {
|
|
|
43
43
|
|
|
44
44
|
## Custom feed rendering
|
|
45
45
|
|
|
46
|
-
- `cmd.addRenderer(customType, data => lines)`
|
|
47
|
-
- `cmd.showEntry(customType, data)`
|
|
46
|
+
- `cmd.addRenderer(customType, data => lines)` - a renderer for a custom entry type; returns the lines to print (style them with ansi escapes - picocolors, `@commandcode/tui` helpers, or raw codes). First registration per type wins across mods.
|
|
47
|
+
- `cmd.showEntry(customType, data)` - render a custom entry into the live feed through the renderer registered for that type (unrendered types pretty-print as JSON). The TUI wires the sink; headless runs drop entries. Pair with `cmd.session.appendCustomEntry` when the data should also persist.
|
|
48
48
|
|
|
49
49
|
Rendering is deliberately **line-based, not component-based**: mods return styled text lines, never React components. That keeps renderers host-agnostic (the same mod renders in any future host) and a crashing renderer degrades to a warning notice, never a broken screen.
|
|
50
50
|
|
|
@@ -60,4 +60,4 @@ Rendering is deliberately **line-based, not component-based**: mods return style
|
|
|
60
60
|
| `widget` | rendered around the editor | no-op |
|
|
61
61
|
| `showEntry` | rendered feed row | dropped |
|
|
62
62
|
|
|
63
|
-
The `status-and-widgets.ts` bundled example exercises all of this in one file
|
|
63
|
+
The `status-and-widgets.ts` bundled example exercises all of this in one file - see [Runnable examples](./overview.md#runnable-examples).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Verify a mod
|
|
4
4
|
|
|
5
|
-
A mod that fails to import, exports no factory, or throws in its factory becomes a **warning
|
|
5
|
+
A mod that fails to import, exports no factory, or throws in its factory becomes a **warning - never a crashed session**. That safety also means a broken mod can fail silently if you never check. This section is the verification loop: load it, list it, exercise it, reload it.
|
|
6
6
|
|
|
7
7
|
## 1. Load it without installing
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ A mod that fails to import, exports no factory, or throws in its factory becomes
|
|
|
10
10
|
cmd --mod ./your-mod.ts
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
`--mod` is repeatable, loads ahead of installed mods, and wins name collisions
|
|
13
|
+
`--mod` is repeatable, loads ahead of installed mods, and wins name collisions - the fastest try-it loop. No build step: jiti compiles the TypeScript at load.
|
|
14
14
|
|
|
15
15
|
## 2. Confirm it registered
|
|
16
16
|
|
|
@@ -22,12 +22,12 @@ Your mod must appear, with no load warnings. If it does not appear, the warning
|
|
|
22
22
|
|
|
23
23
|
## 3. Exercise every surface it registers
|
|
24
24
|
|
|
25
|
-
- **Slash command**
|
|
26
|
-
- **Tool**
|
|
27
|
-
- **Hook**
|
|
28
|
-
- **Input interception**
|
|
29
|
-
- **Status / widget**
|
|
30
|
-
- **Renderer**
|
|
25
|
+
- **Slash command** - type `/` in the chat input: the command must appear in autocomplete with its description. Run it; `{message}` renders an info row, `{prompt}` starts an automated turn.
|
|
26
|
+
- **Tool** - ask the model to use it by name ("call count_todos"). The tool call renders in the feed like any built-in.
|
|
27
|
+
- **Hook** - trigger the behavior it guards (for a `beforeToolCall` blocker, ask for the blocked action and watch the block reason land as the tool result).
|
|
28
|
+
- **Input interception** - type the pattern `transformInput` matches and confirm the rewrite/consume happened.
|
|
29
|
+
- **Status / widget** - the footer segment appears under the input panel; the widget renders around the editor.
|
|
30
|
+
- **Renderer** - `cmd.showEntry` rows render styled; an unregistered type pretty-prints as JSON.
|
|
31
31
|
|
|
32
32
|
### Test: block-dangerous-commands guards rm -rf
|
|
33
33
|
|
|
@@ -38,12 +38,12 @@ Run rm -rf /tmp/scratch-dir
|
|
|
38
38
|
Expected result:
|
|
39
39
|
|
|
40
40
|
- ✅ The mod's confirm dialog appears before the shell command runs
|
|
41
|
-
- ✅ Declining blocks the tool
|
|
41
|
+
- ✅ Declining blocks the tool - the model sees the block reason and adapts
|
|
42
42
|
- ❌ No `tool_running` fires for the blocked call
|
|
43
43
|
|
|
44
44
|
## 4. Iterate with /reload
|
|
45
45
|
|
|
46
|
-
Mods load once per process. After editing the file, run `/reload`
|
|
46
|
+
Mods load once per process. After editing the file, run `/reload` - it restarts Command Code, resumes the session, and re-discovers and re-imports every mod (jiti caches nothing between loads).
|
|
47
47
|
|
|
48
48
|
## 5. Headless check (CI)
|
|
49
49
|
|
|
@@ -55,4 +55,4 @@ Print mode loads user-scope and `--mod` mods with the UI bridge degraded to dete
|
|
|
55
55
|
|
|
56
56
|
## Working from the bundled examples
|
|
57
57
|
|
|
58
|
-
Command Code ships runnable single-file examples inside the bundled `mod-builder` skill
|
|
58
|
+
Command Code ships runnable single-file examples inside the bundled `mod-builder` skill - each one loads through the real mod loader in CI on every test run, so copying one is copying something proven to load. In the Command Code repo itself, the same validation is a vitest suite (`packages/harness/src/mod-host/__tests__/examples.test.ts`); if you are contributing an example, that test must stay green.
|