terminal-pilot 0.0.42 → 0.0.44

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.
Files changed (82) hide show
  1. package/README.md +7 -3
  2. package/dist/cli.js +3435 -3165
  3. package/dist/cli.js.map +4 -4
  4. package/dist/commands/close-session.js +5 -0
  5. package/dist/commands/close-session.js.map +2 -2
  6. package/dist/commands/create-session.js +5 -0
  7. package/dist/commands/create-session.js.map +2 -2
  8. package/dist/commands/daemon-runtime.js.map +1 -1
  9. package/dist/commands/fill.js +5 -0
  10. package/dist/commands/fill.js.map +2 -2
  11. package/dist/commands/get-session.js +5 -0
  12. package/dist/commands/get-session.js.map +2 -2
  13. package/dist/commands/index.js +5 -0
  14. package/dist/commands/index.js.map +3 -3
  15. package/dist/commands/install.js +5 -0
  16. package/dist/commands/install.js.map +2 -2
  17. package/dist/commands/installer.js.map +2 -2
  18. package/dist/commands/list-sessions.js +5 -0
  19. package/dist/commands/list-sessions.js.map +2 -2
  20. package/dist/commands/press-key.js +5 -0
  21. package/dist/commands/press-key.js.map +2 -2
  22. package/dist/commands/read-history.js +5 -0
  23. package/dist/commands/read-history.js.map +2 -2
  24. package/dist/commands/read-screen.js +5 -0
  25. package/dist/commands/read-screen.js.map +2 -2
  26. package/dist/commands/resize.js +5 -0
  27. package/dist/commands/resize.js.map +2 -2
  28. package/dist/commands/runtime.js.map +1 -1
  29. package/dist/commands/screenshot.js +5 -0
  30. package/dist/commands/screenshot.js.map +2 -2
  31. package/dist/commands/send-signal.js +5 -0
  32. package/dist/commands/send-signal.js.map +2 -2
  33. package/dist/commands/type.js +5 -0
  34. package/dist/commands/type.js.map +2 -2
  35. package/dist/commands/uninstall.js +5 -0
  36. package/dist/commands/uninstall.js.map +2 -2
  37. package/dist/commands/wait-for-exit.js +5 -0
  38. package/dist/commands/wait-for-exit.js.map +2 -2
  39. package/dist/commands/wait-for.js +5 -0
  40. package/dist/commands/wait-for.js.map +2 -2
  41. package/dist/composition.json +35 -0
  42. package/dist/templates/terminal-pilot.md +1 -1
  43. package/dist/testing/cli-repl.js +3435 -3165
  44. package/dist/testing/cli-repl.js.map +4 -4
  45. package/dist/testing/qa-cli.js +3435 -3165
  46. package/dist/testing/qa-cli.js.map +4 -4
  47. package/node_modules/@poe-code/agent-defs/LICENSE +21 -0
  48. package/node_modules/@poe-code/agent-defs/package.json +9 -2
  49. package/node_modules/@poe-code/agent-skill-config/README.md +25 -17
  50. package/node_modules/@poe-code/agent-skill-config/dist/templates/poe-generate.md +16 -22
  51. package/node_modules/@poe-code/agent-skill-config/dist/templates/terminal-pilot.md +1 -1
  52. package/node_modules/@poe-code/agent-skill-config/package.json +1 -0
  53. package/node_modules/@poe-code/config-mutations/LICENSE +21 -0
  54. package/node_modules/@poe-code/config-mutations/README.md +8 -8
  55. package/node_modules/@poe-code/config-mutations/package.json +8 -1
  56. package/node_modules/@poe-code/frontmatter/LICENSE +21 -0
  57. package/node_modules/@poe-code/frontmatter/README.md +2 -2
  58. package/node_modules/@poe-code/frontmatter/package.json +8 -1
  59. package/node_modules/toolcraft-design/LICENSE +21 -0
  60. package/node_modules/toolcraft-design/README.md +8 -4
  61. package/node_modules/toolcraft-design/dist/components/file-changes.d.ts +16 -0
  62. package/node_modules/toolcraft-design/dist/components/file-changes.js +162 -0
  63. package/node_modules/toolcraft-design/dist/components/index.d.ts +2 -0
  64. package/node_modules/toolcraft-design/dist/components/index.js +1 -0
  65. package/node_modules/toolcraft-design/dist/dashboard/terminal.js +48 -6
  66. package/node_modules/toolcraft-design/dist/explorer/actions.d.ts +4 -0
  67. package/node_modules/toolcraft-design/dist/explorer/actions.js +1 -0
  68. package/node_modules/toolcraft-design/dist/explorer/events.d.ts +4 -0
  69. package/node_modules/toolcraft-design/dist/explorer/jobs.d.ts +1 -0
  70. package/node_modules/toolcraft-design/dist/explorer/jobs.js +28 -0
  71. package/node_modules/toolcraft-design/dist/explorer/keymap.js +2 -2
  72. package/node_modules/toolcraft-design/dist/explorer/reducer.js +66 -6
  73. package/node_modules/toolcraft-design/dist/explorer/render/detail.js +1 -1
  74. package/node_modules/toolcraft-design/dist/explorer/render/list.js +48 -21
  75. package/node_modules/toolcraft-design/dist/explorer/render/modal.js +15 -2
  76. package/node_modules/toolcraft-design/dist/explorer/render/test-fixtures.js +1 -1
  77. package/node_modules/toolcraft-design/dist/explorer/runtime.js +3 -0
  78. package/node_modules/toolcraft-design/dist/explorer/state.d.ts +9 -0
  79. package/node_modules/toolcraft-design/dist/index.d.ts +2 -0
  80. package/node_modules/toolcraft-design/dist/index.js +1 -0
  81. package/node_modules/toolcraft-design/package.json +3 -1
  82. package/package.json +1 -1
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Poe Platform
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -2,6 +2,7 @@
2
2
  "name": "@poe-code/agent-defs",
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
+ "license": "MIT",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
@@ -15,6 +16,12 @@
15
16
  "build": "node ../../scripts/guard-package-dist.mjs && tsc"
16
17
  },
17
18
  "files": [
18
- "dist"
19
- ]
19
+ "dist",
20
+ "LICENSE"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/poe-platform/poe-code.git",
25
+ "directory": "packages/agent-defs"
26
+ }
20
27
  }
@@ -13,12 +13,12 @@ Skill refs use one of two forms:
13
13
 
14
14
  Examples:
15
15
 
16
- | Ref | Source |
17
- |-----|--------|
18
- | `"my-helper"` | `~/.poe-code/skills/my-helper` or `<cwd>/.poe-code/skills/my-helper` |
19
- | `"claude/my-helper"` | `~/.claude/skills/my-helper` alias for `claude-code` |
20
- | `"claude-code/my-helper"` | `~/.claude/skills/my-helper` canonical id |
21
- | `"codex/my-helper"` | `~/.codex/skills/my-helper` |
16
+ | Ref | Source |
17
+ | ------------------------- | -------------------------------------------------------------------- |
18
+ | `"my-helper"` | `~/.poe-code/skills/my-helper` or `<cwd>/.poe-code/skills/my-helper` |
19
+ | `"claude/my-helper"` | `~/.claude/skills/my-helper` alias for `claude-code` |
20
+ | `"claude-code/my-helper"` | `~/.claude/skills/my-helper` canonical id |
21
+ | `"codex/my-helper"` | `~/.codex/skills/my-helper` |
22
22
 
23
23
  The agent token accepts canonical ids, aliases, and any casing. It is normalized with `resolveAgentId` from `@poe-code/agent-defs`. The token is not the source agent's native directory name; the source path always comes from `agentSkillConfigs[canonicalId]`, so aliases map to the directory owned by that canonical agent.
24
24
 
@@ -50,20 +50,20 @@ The source ref's agent prefix never appears in the target path. For a Claude Cod
50
50
 
51
51
  Resolution failures abort the whole bridge before any copy. Error messages distinguish:
52
52
 
53
- | Kind | Meaning |
54
- |------|---------|
55
- | `malformed` | Bad syntax; expected `"<name>"` or `"<agentId>/<name>"`. |
53
+ | Kind | Meaning |
54
+ | --------------- | ------------------------------------------------------------------------------------ |
55
+ | `malformed` | Bad syntax; expected `"<name>"` or `"<agentId>/<name>"`. |
56
56
  | `unknown-agent` | Agent token does not resolve to a supported agent; the error lists supported agents. |
57
- | `not-found` | No skill folder exists at any tier; the error lists searched paths in order. |
57
+ | `not-found` | No skill folder exists at any tier; the error lists searched paths in order. |
58
58
 
59
59
  Collisions never abort. The bridge emits one `BridgeWarning` per skipped ref, leaves no state for that ref, and continues the batch.
60
60
 
61
- | Warning kind | Skip condition |
62
- |--------------|----------------|
63
- | `local-collision` | Target folder already exists in the spawning agent's local skill dir. |
64
- | `global-collision` | Target folder already exists in the spawning agent's global skill dir. |
65
- | `self-reference` | The spawning agent references its own native skill. |
66
- | `intra-batch-collision` | Two refs produce the same target basename; first input ref wins. |
61
+ | Warning kind | Skip condition |
62
+ | ----------------------- | ---------------------------------------------------------------------- |
63
+ | `local-collision` | Target folder already exists in the spawning agent's local skill dir. |
64
+ | `global-collision` | Target folder already exists in the spawning agent's global skill dir. |
65
+ | `self-reference` | The spawning agent references its own native skill. |
66
+ | `intra-batch-collision` | Two refs produce the same target basename; first input ref wins. |
67
67
 
68
68
  Native skills are never overwritten. Callers, including the spawn runner, surface `manifest.warnings` through the design-system warning channel before launching the agent.
69
69
 
@@ -84,7 +84,7 @@ import {
84
84
  resolveAgentSupport,
85
85
  getAgentConfig,
86
86
  resolveSkillDir,
87
- supportedAgents,
87
+ supportedAgents
88
88
  } from "@poe-code/agent-skill-config";
89
89
  ```
90
90
 
@@ -92,6 +92,14 @@ Exported types include `AgentSkillConfig`, `AgentSupportResult`, `SkillScope`, `
92
92
 
93
93
  `agentSkillConfigs` is internal and is not exported.
94
94
 
95
+ ## CLI Commands
96
+
97
+ | Command | Purpose |
98
+ | ---------------------------- | --------------------------------------------------------------------------------------------------- |
99
+ | `poe-code skill install` | Install one `SKILL.md` for an agent. Use `--name`, `--file`, `--local`, `--global`, or `--yes`. |
100
+ | `poe-code skill configure` | Create the native skill directory layout for an agent. Supports `--local`, `--global`, and `--yes`. |
101
+ | `poe-code skill unconfigure` | Remove native skill directories. Use `--force` to remove a non-empty directory. |
102
+
95
103
  ## Config Options
96
104
 
97
105
  This package exposes no user-facing config options.
@@ -1,47 +1,41 @@
1
1
  ---
2
2
  name: poe-generate
3
- description: 'Poe code generation skill'
3
+ description: "Poe Code agent prompting guidance"
4
4
  ---
5
5
 
6
- # poe-code generate
6
+ # Poe Code Prompting
7
7
 
8
- Use `poe-code generate` to create text, images, audio, or video via the Poe API.
8
+ Use Poe Code's supported agent surfaces for prompts. The current CLI has no standalone generation command.
9
9
 
10
- ## Text generation
10
+ ## One-shot Poe Agent Prompt
11
11
 
12
12
  ```bash
13
- poe-code generate "Write a short function that parses a JSON string safely."
13
+ poe-code agent "Summarize the current repository."
14
14
  ```
15
15
 
16
- Specify the model/bot:
16
+ Specify a model when the command supports it:
17
17
 
18
18
  ```bash
19
- # CLI option
20
- poe-code generate --model "gpt-4.1" "Summarize this codebase change."
21
-
22
- # Some agent runtimes call the model selector `--bot`
23
- poe-code generate --bot "gpt-4.1" "Summarize this codebase change."
19
+ poe-code agent "Summarize this codebase change." --model "<model-id>"
24
20
  ```
25
21
 
26
- ## Media generation
22
+ ## Coding Agent Prompt
27
23
 
28
- The CLI supports media generation as subcommands:
24
+ Use `spawn` when the prompt should run through a configured coding agent CLI:
29
25
 
30
26
  ```bash
31
- poe-code generate image "A 3D render of a rubber duck wearing sunglasses" --model "gpt-image-1" -o duck.png
32
- poe-code generate video "A cinematic timelapse of a city at night" --model "veo" -o city.mp4
33
- poe-code generate audio "A calm 10 second lo-fi beat" --model "audio-model" -o beat.wav
27
+ poe-code spawn codex "Review the auth module"
28
+ poe-code spawn claude-code "Fix the failing tests" --model "<model-id>"
34
29
  ```
35
30
 
36
- Some agent runtimes expose the same media types as flags. If available, these are equivalent:
31
+ Run against a GitHub locator when the work should happen outside the current checkout:
37
32
 
38
33
  ```bash
39
- poe-code generate --image "A 3D render of a rubber duck wearing sunglasses" --bot "gpt-image-1" -o duck.png
40
- poe-code generate --video "A cinematic timelapse of a city at night" --bot "veo" -o city.mp4
41
- poe-code generate --audio "A calm 10 second lo-fi beat" --bot "audio-model" -o beat.wav
34
+ poe-code spawn codex "Review this package" --cwd github://owner/repo#main:packages/auth
42
35
  ```
43
36
 
44
37
  ## Tips
45
38
 
46
- - Use `--param key=value` to pass provider/model parameters (repeatable).
47
- - Use `--output <path>` (or `-o`) for media outputs.
39
+ - Run `poe-code models` to find model IDs and endpoint support.
40
+ - Use `poe-code auth status` to verify credentials before running prompts.
41
+ - Use `poe-code spawn --help` and `poe-code agent --help` for current flags.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: terminal-pilot
3
- description: 'Terminal automation skill using the terminal-pilot CLI'
3
+ description: "Terminal automation skill using the terminal-pilot CLI"
4
4
  ---
5
5
 
6
6
  # Terminal Pilot
@@ -2,6 +2,7 @@
2
2
  "name": "@poe-code/agent-skill-config",
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
+ "license": "MIT",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Poe Platform
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -38,14 +38,14 @@ await runMutations(
38
38
 
39
39
  `MutationContext` controls execution:
40
40
 
41
- | Option | Type | Description |
42
- | ------ | ---- | ----------- |
43
- | `fs` | `FileSystem` | Required filesystem adapter. |
44
- | `homeDir` | `string` | Required home directory for `~` expansion. |
45
- | `dryRun` | `boolean` | Reports changes without writing them. |
46
- | `observers` | `MutationObservers` | Receives mutation lifecycle events. |
47
- | `templates` | `TemplateLoader` | Loads templates referenced by template mutations. |
48
- | `pathMapper` | `PathMapper` | Redirects target directories for isolated config flows. |
41
+ | Option | Type | Description |
42
+ | ------------ | ------------------- | ------------------------------------------------------- |
43
+ | `fs` | `FileSystem` | Required filesystem adapter. |
44
+ | `homeDir` | `string` | Required home directory for `~` expansion. |
45
+ | `dryRun` | `boolean` | Reports changes without writing them. |
46
+ | `observers` | `MutationObservers` | Receives mutation lifecycle events. |
47
+ | `templates` | `TemplateLoader` | Loads templates referenced by template mutations. |
48
+ | `pathMapper` | `PathMapper` | Redirects target directories for isolated config flows. |
49
49
 
50
50
  Mutation builders also expose per-mutation options such as target path, format,
51
51
  label, force removal, backup behavior, template id, and transform callbacks.
@@ -2,6 +2,7 @@
2
2
  "name": "@poe-code/config-mutations",
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
+ "license": "MIT",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
@@ -19,8 +20,14 @@
19
20
  "build": "node ../../scripts/guard-package-dist.mjs && tsc"
20
21
  },
21
22
  "files": [
22
- "dist"
23
+ "dist",
24
+ "LICENSE"
23
25
  ],
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/poe-platform/poe-code.git",
29
+ "directory": "packages/config-mutations"
30
+ },
24
31
  "dependencies": {
25
32
  "jsonc-parser": "^3.3.1",
26
33
  "smol-toml": "^1.3.0",
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Poe Platform
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -26,10 +26,10 @@ Duplicate mapping keys use YAML's last-wins behavior by default, matching the
26
26
  legacy frontmatter readers. Callers that need strict YAML mappings can pass
27
27
  `{ uniqueKeys: true }` to `parseFrontmatter` or `parseFrontmatterDocument`.
28
28
 
29
- ## Environment
29
+ ## Environment Variables
30
30
 
31
31
  This package reads no environment variables.
32
32
 
33
- ## Config
33
+ ## Configuration Options
34
34
 
35
35
  This package has no configuration options.
@@ -2,6 +2,7 @@
2
2
  "name": "@poe-code/frontmatter",
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
+ "license": "MIT",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
@@ -17,8 +18,14 @@
17
18
  "test:unit": "cd ../.. && vitest run packages/frontmatter/src"
18
19
  },
19
20
  "files": [
20
- "dist"
21
+ "dist",
22
+ "LICENSE"
21
23
  ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/poe-platform/poe-code.git",
27
+ "directory": "packages/frontmatter"
28
+ },
22
29
  "dependencies": {
23
30
  "yaml": "^2.8.2"
24
31
  }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Poe Platform
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -118,16 +118,16 @@ Raw HTML in Markdown is escaped by default. Pass `{ allowRawHtml: true }` only w
118
118
 
119
119
  Fenced code block syntax highlighting is opt-in:
120
120
 
121
- ```ts
121
+ ````ts
122
122
  import { renderMarkdown, renderMarkdownHtml } from "toolcraft-design";
123
123
 
124
- const html = renderMarkdownHtml("```ts\nconst value = \"hello\";\n```", {
124
+ const html = renderMarkdownHtml('```ts\nconst value = "hello";\n```', {
125
125
  syntaxHighlight: true
126
126
  });
127
- const terminal = renderMarkdown("```ts\nconst value = \"hello\";\n```", {
127
+ const terminal = renderMarkdown('```ts\nconst value = "hello";\n```', {
128
128
  syntaxHighlight: true
129
129
  });
130
- ```
130
+ ````
131
131
 
132
132
  HTML highlighting emits escaped code text with neutral Toolcraft-owned `<span>` wrappers. The renderer does not ship or inject CSS, so consumers control the appearance:
133
133
 
@@ -340,3 +340,7 @@ nvm exec 18.18 node packages/toolcraft-design/scripts/check-node18.mjs
340
340
  - `NO_COLOR`: disables color when `FORCE_COLOR` does not enable it.
341
341
  - `TERM`: participates in color support detection; an unset or `dumb` terminal disables color unless forced.
342
342
  - `POE_NO_SPINNER`: uses non-animated spinner behavior when set to `1`.
343
+
344
+ ## Configuration Options
345
+
346
+ Use `configureTheme({ brand?, label? })` for process-local brand settings, `withOutputFormat(format, fn)` for scoped output-format overrides, and component-specific options such as `RenderTableOptions`, `RenderMarkdownOptions`, prompt options, dashboard options, and explorer config. Environment variables above are process defaults, not config files.
@@ -0,0 +1,16 @@
1
+ export type FileChangeKind = "added" | "modified" | "deleted" | "renamed";
2
+ export type FileChangeDisplayMode = "status" | "diff";
3
+ export type FileChangeOutputFormat = "terminal" | "markdown";
4
+ export interface FileChange {
5
+ path: string;
6
+ kind: FileChangeKind;
7
+ oldPath?: string;
8
+ conflict?: boolean;
9
+ oldContent?: string;
10
+ newContent?: string;
11
+ }
12
+ export interface RenderFileChangesOptions {
13
+ mode?: FileChangeDisplayMode;
14
+ format?: FileChangeOutputFormat;
15
+ }
16
+ export declare function renderFileChanges(changes: readonly FileChange[], options?: RenderFileChangesOptions): string;
@@ -0,0 +1,162 @@
1
+ import { color } from "./color.js";
2
+ const STATUS_MARKERS = {
3
+ added: "A",
4
+ modified: "M",
5
+ deleted: "D",
6
+ renamed: "R"
7
+ };
8
+ const STATUS_LABELS = {
9
+ added: "added",
10
+ modified: "modified",
11
+ deleted: "deleted",
12
+ renamed: "renamed"
13
+ };
14
+ function changePath(change) {
15
+ if (change.kind === "renamed" && change.oldPath) {
16
+ return `${change.oldPath} -> ${change.path}`;
17
+ }
18
+ return change.path;
19
+ }
20
+ function colorStatusMarker(change, marker) {
21
+ if (change.conflict) {
22
+ return color.red.bold(marker);
23
+ }
24
+ switch (change.kind) {
25
+ case "added":
26
+ return color.green(marker);
27
+ case "modified":
28
+ return color.yellow(marker);
29
+ case "deleted":
30
+ return color.red(marker);
31
+ case "renamed":
32
+ return color.cyan(marker);
33
+ }
34
+ }
35
+ function formatSummary(changes) {
36
+ const counts = new Map();
37
+ let conflicts = 0;
38
+ for (const change of changes) {
39
+ counts.set(change.kind, (counts.get(change.kind) ?? 0) + 1);
40
+ if (change.conflict) {
41
+ conflicts += 1;
42
+ }
43
+ }
44
+ const details = Object.keys(STATUS_LABELS)
45
+ .flatMap((kind) => {
46
+ const count = counts.get(kind) ?? 0;
47
+ return count > 0 ? [`${count} ${STATUS_LABELS[kind]}`] : [];
48
+ });
49
+ if (conflicts > 0) {
50
+ details.push(`${conflicts} ${conflicts === 1 ? "conflict" : "conflicts"}`);
51
+ }
52
+ return `${changes.length} ${changes.length === 1 ? "change" : "changes"} (${details.join(", ")})`;
53
+ }
54
+ function renderStatus(changes, format) {
55
+ const lines = changes.map((change) => {
56
+ const marker = `${STATUS_MARKERS[change.kind]}${change.conflict ? "!" : " "}`;
57
+ const renderedMarker = format === "terminal" ? colorStatusMarker(change, marker) : marker;
58
+ return `${renderedMarker} ${changePath(change)}`;
59
+ });
60
+ const output = [...lines, "", formatSummary(changes)].join("\n");
61
+ return format === "markdown" ? `\`\`\`text\n${output}\n\`\`\`` : output;
62
+ }
63
+ function diffPath(prefix, path) {
64
+ return `${prefix}/${path}`;
65
+ }
66
+ function contentLines(content) {
67
+ const lines = content.split("\n");
68
+ if (lines.at(-1) === "") {
69
+ lines.pop();
70
+ }
71
+ return lines;
72
+ }
73
+ function commonPrefixLength(oldLines, newLines) {
74
+ const limit = Math.min(oldLines.length, newLines.length);
75
+ let index = 0;
76
+ while (index < limit && oldLines[index] === newLines[index]) {
77
+ index += 1;
78
+ }
79
+ return index;
80
+ }
81
+ function commonSuffixLength(oldLines, newLines, prefixLength) {
82
+ const limit = Math.min(oldLines.length, newLines.length) - prefixLength;
83
+ let length = 0;
84
+ while (length < limit &&
85
+ oldLines[oldLines.length - length - 1] === newLines[newLines.length - length - 1]) {
86
+ length += 1;
87
+ }
88
+ return length;
89
+ }
90
+ function hunkRange(startIndex, count) {
91
+ const lineNumber = count === 0 ? 0 : startIndex + 1;
92
+ return `${lineNumber},${count}`;
93
+ }
94
+ function createUnifiedHunk(oldContent, newContent) {
95
+ const oldLines = contentLines(oldContent);
96
+ const newLines = contentLines(newContent);
97
+ const prefixLength = commonPrefixLength(oldLines, newLines);
98
+ const suffixLength = commonSuffixLength(oldLines, newLines, prefixLength);
99
+ const context = 3;
100
+ const oldChangeEnd = oldLines.length - suffixLength;
101
+ const newChangeEnd = newLines.length - suffixLength;
102
+ const oldStart = Math.max(0, prefixLength - context);
103
+ const newStart = Math.max(0, prefixLength - context);
104
+ const oldEnd = Math.min(oldLines.length, oldChangeEnd + context);
105
+ const newEnd = Math.min(newLines.length, newChangeEnd + context);
106
+ const oldCount = oldEnd - oldStart;
107
+ const newCount = newEnd - newStart;
108
+ const before = oldLines.slice(oldStart, prefixLength).map((line) => ` ${line}`);
109
+ const removed = oldLines.slice(prefixLength, oldChangeEnd).map((line) => `-${line}`);
110
+ const added = newLines.slice(prefixLength, newChangeEnd).map((line) => `+${line}`);
111
+ const after = oldLines.slice(oldChangeEnd, oldEnd).map((line) => ` ${line}`);
112
+ return [
113
+ `@@ -${hunkRange(oldStart, oldCount)} +${hunkRange(newStart, newCount)} @@`,
114
+ ...before,
115
+ ...removed,
116
+ ...added,
117
+ ...after
118
+ ].join("\n");
119
+ }
120
+ function createChangePatch(change) {
121
+ const oldPath = change.kind === "added"
122
+ ? "/dev/null"
123
+ : diffPath("a", change.oldPath ?? change.path);
124
+ const newPath = change.kind === "deleted" ? "/dev/null" : diffPath("b", change.path);
125
+ const oldContent = change.kind === "added" ? "" : (change.oldContent ?? "");
126
+ const newContent = change.kind === "deleted" ? "" : (change.newContent ?? "");
127
+ const headers = [`--- ${oldPath}`, `+++ ${newPath}`];
128
+ if (oldContent !== newContent) {
129
+ return [...headers, createUnifiedHunk(oldContent, newContent)].join("\n");
130
+ }
131
+ return headers.join("\n");
132
+ }
133
+ function colorDiffLine(line) {
134
+ if (line.startsWith("@@")) {
135
+ return color.cyan(line);
136
+ }
137
+ if (line.startsWith("+++") || line.startsWith("---")) {
138
+ return color.bold(line);
139
+ }
140
+ if (line.startsWith("+")) {
141
+ return color.green(line);
142
+ }
143
+ if (line.startsWith("-")) {
144
+ return color.red(line);
145
+ }
146
+ return line;
147
+ }
148
+ function renderDiff(changes, format) {
149
+ const output = changes.map(createChangePatch).join("\n\n");
150
+ if (format === "markdown") {
151
+ return `\`\`\`diff\n${output}\n\`\`\``;
152
+ }
153
+ return output.split("\n").map(colorDiffLine).join("\n");
154
+ }
155
+ export function renderFileChanges(changes, options = {}) {
156
+ if (changes.length === 0) {
157
+ return "No file changes.";
158
+ }
159
+ const mode = options.mode ?? "status";
160
+ const format = options.format ?? "terminal";
161
+ return mode === "diff" ? renderDiff(changes, format) : renderStatus(changes, format);
162
+ }
@@ -10,6 +10,8 @@ export { formatCommandNotFound } from "./command-errors.js";
10
10
  export { formatCommandNotFoundPanel } from "./command-errors.js";
11
11
  export { renderTable } from "./table.js";
12
12
  export type { TableColumn, RenderTableOptions } from "./table.js";
13
+ export { renderFileChanges } from "./file-changes.js";
14
+ export type { FileChange, FileChangeDisplayMode, FileChangeKind, FileChangeOutputFormat, RenderFileChangesOptions } from "./file-changes.js";
13
15
  export { renderCatalog } from "./catalog.js";
14
16
  export type { CatalogGroup, CatalogItem, CatalogMetric, CatalogTone, RenderCatalogOptions } from "./catalog.js";
15
17
  export { getTemplatePartialNames, renderTemplate, resolveTemplatePartials } from "./template.js";
@@ -6,5 +6,6 @@ export { helpFormatter, formatColumns, formatCommand, formatUsage, formatOption,
6
6
  export { formatCommandNotFound } from "./command-errors.js";
7
7
  export { formatCommandNotFoundPanel } from "./command-errors.js";
8
8
  export { renderTable } from "./table.js";
9
+ export { renderFileChanges } from "./file-changes.js";
9
10
  export { renderCatalog } from "./catalog.js";
10
11
  export { getTemplatePartialNames, renderTemplate, resolveTemplatePartials } from "./template.js";