command-code 1.9.1 → 1.11.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 CHANGED
@@ -1,17 +1,28 @@
1
1
  # command-code
2
2
 
3
- ## 1.9.1
3
+ ## 1.11.0
4
4
 
5
- ### Patch Changes
5
+ ### Minor Changes
6
+
7
+ - feat: syntax highlighting for code blocks and markdown in the TUI (#3319g)
8
+ - feat(mods): render `cmd.ui.setStatus` segments in the TUI footer
9
+ - feat: use Shades of Purple syntax theme (#3328)
10
+ - fix: size model picker name column to widest label #3329
6
11
 
7
- - fix(tui): /copy the whole reply, not just its last block (#3313)
12
+ ## 1.10.0
8
13
 
9
- ## Unreleased
14
+ ### Minor Changes
15
+
16
+ - feat(mods): render `cmd.ui.setStatus` segments in the TUI footer
17
+ - feat(tui): make /feedback tell you what enter will do, and add /issue (#3316)
18
+
19
+ ## 1.9.1
10
20
 
11
21
  ### Patch Changes
12
22
 
23
+ - fix(tui): /copy to copy the whole reply, not just its last block
13
24
  - fix: Restore colorized Edit/Write diff view in the TUI
14
- - fix: Render the Edit diff for legacy `oldValue`/`newValue` tool calls and keep long Write previews honest when expanded
25
+ - fix: Render the Edit diff for legacy `oldValue`/`newValue` tool calls
15
26
 
16
27
  ## 1.9.0
17
28
 
@@ -122,7 +122,7 @@ Every built-in command, grouped by area. Aliases are shown in parentheses on the
122
122
  | `/changelog [all]` | See what's new in Command Code (`all` for the full history) |
123
123
  | `/courses` | Open Command Code courses in your browser |
124
124
  | `/update` | Update Command Code to the latest version |
125
- | `/feedback` | Share feedback or report bugs |
125
+ | `/feedback [title]` (alias `/issue`) | Report a bug or share feedback — opens a prefilled GitHub issue |
126
126
  | `/trace` | Copy the current trace id; required for support debugging |
127
127
  | `/copy` | Copy the last response to the clipboard |
128
128
 
@@ -251,7 +251,7 @@ When multiple sources define the same name, dispatch resolves in this order - fi
251
251
  3. **Custom** commands (`.commandcode/commands/`, `~/.commandcode/commands/`)
252
252
  4. **Skills**
253
253
 
254
- So a custom command can never override a built-in, and a skill shadowed by any of the above resolves to its owner. Shadowed skills still render in the menu with a `- shadowed by /<name>` note so you know they exist. Lookup is case-insensitive (`/Reload` resolves to `/reload`).
254
+ So a custom command can never override a built-in, and a skill shadowed by any of the above resolves to its owner. Shadowed skills still render in the menu with a `- shadowed by /<name>` note so you know they exist, and they run under the `skill:` namespace: `/skill:<name>` bypasses this whole ladder and only ever resolves to a skill. Lookup is case-insensitive (`/Reload` resolves to `/reload`).
255
255
 
256
256
  ### Skill invocation
257
257
 
@@ -9,7 +9,7 @@ The model catalog — every id `/model`, `--model`, `model:effort` shorthand, an
9
9
  | Id (use EXACTLY this) | Name | Context | Efforts | $/1M in/out | Best for |
10
10
  |---|---|---|---|---|---|
11
11
  | `deepseek/deepseek-v4-pro` | DeepSeek V4 Pro | 1M | high, max | $0.435/$0.87 | hybrid-attention long-context reasoning |
12
- | `deepseek/deepseek-v4-flash` | DeepSeek V4 Flash | 1M | high, max | $0.14/$0.28 | fast hybrid-attention reasoning |
12
+ | `deepseek/deepseek-v4-flash` | DeepSeek V4 Flash (latest) | 1M | high, max | $0.14/$0.28 | fast hybrid-attention reasoning |
13
13
  | `moonshotai/Kimi-K3` | Kimi K3 | 1M | — | $3/$15 | long-horizon coding & knowledge work with 1M context |
14
14
  | `moonshotai/Kimi-K2.7-Code` | Kimi K2.7 Code | 256K | — | $0.95/$4 | improved long-horizon coding with vision |
15
15
  | `moonshotai/Kimi-K2.7-Code-Highspeed` | Kimi K2.7 Code HighSpeed | 262K | — | $1.9/$8 | high-speed long-horizon coding with vision |
@@ -46,7 +46,7 @@
46
46
  - /login: Log in to Command Code
47
47
  - /logout: Log out of Command Code
48
48
  - /courses: Open Command Code courses in your browser
49
- - /feedback [title]: Share feedback or report bugs (optional title)
49
+ - /feedback [title]: Report a bug or share feedback — opens a prefilled GitHub issue (alias: /issue)
50
50
  - /trace: Copy the current trace id; required for support debugging
51
51
  - /session-file: Show the current session id and path to the on-disk session file
52
52
  - /copy: Copy the last response to the clipboard
@@ -80,7 +80,7 @@
80
80
  - cmd help: Display help information
81
81
  - cmd whoami: Show current user
82
82
  - cmd update: Update Command Code to the latest version
83
- - cmd feedback [title]: Share feedback or report bugs (optional title)
83
+ - cmd feedback [title]: Report a bug or share feedback — opens a GitHub issue (alias: cmd issue)
84
84
  - cmd taste: Manage taste learning packages
85
85
  - cmd taste learn <source>: Learn taste from a local repository or GitHub repo
86
86
  - cmd learn-taste: Learn command structure from repositories
@@ -213,7 +213,8 @@ When two locations provide the same skill name, the higher-precedence copy wins
213
213
  **What happens on a collision.** When a skill name matches a built-in or a custom command:
214
214
 
215
215
  - Typing `/<name>` always resolves to the higher-precedence owner - the skill is not invoked.
216
- - The skill still appears in the `/` menu with a `[skill]` badge and a ` - shadowed by /<owner>` note, so you can see it exists and understand why `/<name>` runs the built-in command instead. Command Code prefers visibility with a marker over silently dropping the row.
216
+ - Run the skill as `/skill:<name>` instead. The `skill:` namespace skips the precedence ladder entirely and can only ever resolve to a skill, so it works for every skill, shadowed or not. Typing `/skill:` on its own lists all of them.
217
+ - The skill still appears in the `/` menu with a `[skill]` badge and a ` - shadowed by /<owner>, runs as /skill:<name>` note, and selecting that row inserts the namespaced form. Command Code prefers visibility with a marker over silently dropping the row.
217
218
 
218
219
  ---
219
220
 
@@ -238,7 +239,7 @@ This opens an interactive menu showing:
238
239
 
239
240
  Every installed skill is also surfaced as a first-class slash command in the `/` menu. If you install a skill named `pr-desc`, you will see `/pr-desc`, sorted after built-ins and any custom commands in the slash menu.
240
241
 
241
- If a skill name collides with a built-in or a custom command, the skill still appears in the `/` menu with a `[skill]` badge and a ` - shadowed by /<owner>` note. Typing `/<name>` always resolves to the higher-precedence owner, not the skill. See [Selection priority](#selection-priority) above for the full order.
242
+ If a skill name collides with a built-in or a custom command, the skill still appears in the `/` menu with a `[skill]` badge and a ` - shadowed by /<owner>` note. Typing `/<name>` always resolves to the higher-precedence owner, not the skill - use `/skill:<name>` to run the skill itself. See [Selection priority](#selection-priority) above for the full order.
242
243
 
243
244
  ---
244
245
 
@@ -255,6 +256,19 @@ Type `/skill-name` at the start of your prompt to run that skill for the current
255
256
  /pr-desc update the description based on new changes
256
257
  ```
257
258
 
259
+ Every skill also answers to the namespaced form `/skill:<name>`, which never
260
+ resolves to anything but a skill:
261
+
262
+ ```bash
263
+ # In Command Code session
264
+ /skill:changelog # the changelog skill, not the built-in /changelog
265
+ /skill changelog # same thing, space instead of colon
266
+ /skill: # browse every skill in the menu
267
+ ```
268
+
269
+ Reach for it when a skill's name is taken by a built-in or custom command - see
270
+ [What happens on a collision](#selection-priority).
271
+
258
272
  ### 2. Inline slash reference
259
273
 
260
274
  Drop `/skill-name` anywhere inside a longer prompt to pin that skill without losing your natural phrasing. You can mix multiple skills in a single prompt:
@@ -790,7 +804,7 @@ cmd skills add https://github.com/remotion-dev/skills --skill remotion-best-prac
790
804
 
791
805
  **Name collisions.** Skill names share the `/` menu with built-in commands (`/clear`, `/help`, `/share`, `/rewind`, …) and with the custom commands in `.commandcode/commands/`. Built-ins and custom commands take precedence - typing `/<name>` resolves to the owner, not to the skill.
792
806
 
793
- If you install a skill whose name collides with one of those, `cmd skills add` still completes normally - nothing blocks the install. The skill then appears in the `/` menu with a `[skill]` badge and a `shadowed by /<owner>` note so you can see it exists, while `/<name>` continues to route to the higher-precedence owner. See [Selection priority](#selection-priority) for the full order.
807
+ If you install a skill whose name collides with one of those, `cmd skills add` still completes normally - nothing blocks the install. The skill then appears in the `/` menu with a `[skill]` badge and a `shadowed by /<owner>` note, and runs as `/skill:<name>`, while a plain `/<name>` continues to route to the higher-precedence owner. See [Selection priority](#selection-priority) for the full order.
794
808
 
795
809
  ### cmd skills list
796
810
 
@@ -12,7 +12,7 @@
12
12
  | `cmd.cwd` | `string` | workspace root |
13
13
  | `cmd.session` | `ModSessionApi \| undefined` | persistence seam; undefined until bound |
14
14
  | `cmd.events` | `ModEventBus` | `emit(channel, data?)` / `on(channel, handler)` cross-mod bus |
15
- | `cmd.ui` | `ModUi` | `notify` / `confirm` / `select` / `input` / `setStatus` / `widget` / `refreshWidgets` |
15
+ | `cmd.ui` | `ModUi` | `notify` / `confirm` / `select` / `input` / `setStatus` / `widget` / `refreshWidgets` / `capabilities` |
16
16
  | `cmd.sessions` | `ModSessionControls` | `compact` / `tree` / `leafId` / `navigateTree` / `setLabel` |
17
17
 
18
18
  ## Registration (factory-time; each returns `Disposable`)
@@ -222,7 +222,7 @@ Ask for any of these by name or by what you want:
222
222
 
223
223
  - **Hooks mutate, `on` observes.** Event handlers cannot block tools or rewrite context; that is what `cmd.hooks` is for.
224
224
  - **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).
225
- - **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). 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).
225
+ - **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, and `cmd.ui.capabilities.status` is false). 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).
226
226
  - **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.
227
227
  - **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.
228
228
  - **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.
@@ -4,19 +4,36 @@
4
4
 
5
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
- ## Install, remove, list, update
7
+ ## Install, remove, list, update, open
8
8
 
9
9
  ```bash
10
- cmd mods add npm:@team/review-mod@1.2.0 # npm registry
10
+ cmd mods add cmd-mod-hi # bare name = npm package
11
+ cmd mods add @team/review-mod@1.2.0 # scoped npm name, pinned (npm: prefix optional)
11
12
  cmd mods add owner/repo@v1 # GitHub shorthand (any git host via git:<host>/…)
12
13
  cmd mods add ./tools/local-mod # local path, referenced in place
13
14
  cmd mods add -g owner/repo # user scope instead of project
14
- cmd mods list
15
- cmd mods update # reinstall missing, reconcile pinned refs
16
- cmd mods remove owner/repo
15
+ cmd mods list # alias: cmd mods ls
16
+ cmd mods update # reinstall missing, reconcile pinned refs (alias: up)
17
+ cmd mods remove owner/repo # alias: cmd mods rm
18
+ cmd mods remove fun-stuff # by the name `mods list` prints
19
+ cmd mods open # open the mods dir (project); --user for ~
17
20
  ```
18
21
 
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`.
22
+ `cmd mods list` prints one line per mod - name, scope, origin - project mods first, then user, then package-provided:
23
+
24
+ ```
25
+ Mods (2)
26
+ guard · project · .commandcode/mods/guard.ts
27
+ cmd-mod-hi · user · from npm:cmd-mod-hi
28
+ ```
29
+
30
+ The origin is the file for a drop-in mod and `from <source>` for a package mod (whose file lives under `.registry/`, which you never edit by hand). Built-in mods are Command Code's own internals and are never listed. Configured package sources stay out of the output entirely unless one needs attention - not installed, or installed but contributing no mods.
31
+
32
+ `remove` (`rm`) takes **either** a source or the mod NAME `cmd mods list` prints, and removes whatever backs that name: a drop-in file or directory is deleted from the mods dir, a package-provided mod removes its source (and says which sibling mods went with it), a `mods.paths` mod drops its settings entry. Scope follows where the mod actually lives, so a user-scope mod does not need `-g`; a source that is configured in neither scope reports that instead of a silent success.
33
+
34
+ `cmd mods open` opens the drop-in mods directory - `<project>/.commandcode/mods` by default, `~/.commandcode/mods` with `--user` (`-g`) - creating it if it does not exist yet. `--path` prints the directory instead of opening it.
35
+
36
+ A source with no slash is an npm package name, and so is a `@scope/name` - git shorthand always carries an `owner/repo` slash, so `npm:` is optional (an explicit `git:` prefix always wins). 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
37
 
21
38
  ## What a package ships
22
39
 
@@ -11,9 +11,23 @@ Everything a mod can put on screen rides `cmd.ui`, `cmd.addRenderer`, and `cmd.s
11
11
 
12
12
  ## Footer status segments and editor widgets
13
13
 
14
- > **Not wired into the TUI yet.** `cmd.ui.setStatus`, `cmd.ui.widget`, and `cmd.ui.refreshWidgets` exist on the surface and are safe to call - they never throw and return the documented `Disposable` - but they currently render **nowhere** (no-op everywhere, interactive and headless alike). The contract below is the intended design; wire-up is pending. Build against it, but don't rely on anything appearing on screen today.
14
+ > **Widgets are not wired into the TUI yet.** `cmd.ui.widget` and `cmd.ui.refreshWidgets` exist on the surface and are safe to call - they never throw and return the documented `Disposable` - but they currently render **nowhere**. The contract below is the intended design; wire-up is pending. `cmd.ui.setStatus` **is** wired and renders today.
15
15
 
16
- `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).
16
+ `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` (or whitespace-only text) clears it, and the returned `Disposable` clears it too - but only while it still owns the segment, so a stale handle disposing late can't wipe a newer status. Segments from multiple mods render on one row in load order, and a call from async code repaints on its own. Text is printed verbatim (style it with ansi), collapsed to a single line: newlines and tabs become spaces. Headless: stored, rendered nowhere.
17
+
18
+ ```ts
19
+ cmd.hooks({
20
+ onSessionStart: () => cmd.ui.setStatus('#channel ✓ connected'),
21
+ onSessionEnd: () => cmd.ui.setStatus(null),
22
+ });
23
+ ```
24
+
25
+ `cmd.ui.capabilities.status` - whether this host renders footer segments (true in the interactive TUI, false headless). Use it to pick a surface instead of shipping a permanent fallback:
26
+
27
+ ```ts
28
+ if (cmd.ui.capabilities.status) cmd.ui.setStatus(text);
29
+ else cmd.ui.notify(text);
30
+ ```
17
31
 
18
32
  `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.
19
33
 
@@ -43,6 +57,6 @@ Rendering is deliberately **line-based, not component-based**: mods return style
43
57
  | `notify` | notice feed row | printed notice |
44
58
  | `confirm` | modal | resolves `false` |
45
59
  | `select` / `input` | modal | resolves `undefined` |
46
- | `setStatus` | no-op (wire-up pending) | no-op |
60
+ | `setStatus` | footer segment under the input | stored, rendered nowhere |
47
61
  | `widget` | no-op (wire-up pending) | no-op |
48
62
  | `showEntry` | rendered feed row | dropped |
@@ -26,7 +26,8 @@ Your mod must appear, with no load warnings. If it does not appear, the warning
26
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
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
28
  - **Input interception** - type the pattern `transformInput` matches and confirm the rewrite/consume happened.
29
- - **Status / widget** - `cmd.ui.setStatus` / `cmd.ui.widget` / `cmd.ui.refreshWidgets` must return without throwing and hand back a `Disposable`. They render **nothing** today (TUI wire-up pending - see the [UI surface](./ui.md#ui-surface) note), so don't expect a footer segment or editor widget to appear yet; only verify the calls are safe.
29
+ - **Status** - `cmd.ui.setStatus('text')` must show up as a segment on the row under the input, replace itself on the next call, and disappear on `setStatus(null)`.
30
+ - **Widget** - `cmd.ui.widget` / `cmd.ui.refreshWidgets` must return without throwing and hand back a `Disposable`. They render **nothing** today (TUI wire-up pending - see the [UI surface](./ui.md#ui-surface) note), so don't expect an editor widget to appear yet; only verify the calls are safe.
30
31
  - **Renderer** - `cmd.showEntry` rows render styled; an unregistered type pretty-prints as JSON.
31
32
 
32
33
  ### Test: block-dangerous-commands guards rm -rf