terminal-pilot 0.0.41 → 0.0.43
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/LICENSE +21 -0
- package/README.md +7 -3
- package/dist/cli.js +789 -9707
- package/dist/cli.js.map +4 -4
- package/dist/commands/close-session.js.map +1 -1
- package/dist/commands/create-session.js.map +1 -1
- package/dist/commands/daemon-runtime.js.map +1 -1
- package/dist/commands/fill.js.map +1 -1
- package/dist/commands/get-session.js.map +1 -1
- package/dist/commands/index.js.map +2 -2
- package/dist/commands/install.js.map +2 -2
- package/dist/commands/installer.js.map +2 -2
- package/dist/commands/list-sessions.js.map +1 -1
- package/dist/commands/press-key.js.map +1 -1
- package/dist/commands/read-history.js.map +1 -1
- package/dist/commands/read-screen.js.map +1 -1
- package/dist/commands/resize.js.map +1 -1
- package/dist/commands/runtime.js.map +1 -1
- package/dist/commands/screenshot.js.map +1 -1
- package/dist/commands/send-signal.js.map +1 -1
- package/dist/commands/type.js.map +1 -1
- package/dist/commands/uninstall.js.map +2 -2
- package/dist/commands/wait-for-exit.js.map +1 -1
- package/dist/commands/wait-for.js.map +1 -1
- package/dist/composition.json +35 -0
- package/dist/templates/terminal-pilot.md +1 -1
- package/dist/testing/cli-repl.js +795 -9713
- package/dist/testing/cli-repl.js.map +4 -4
- package/dist/testing/qa-cli.js +804 -9722
- package/dist/testing/qa-cli.js.map +4 -4
- package/node_modules/@poe-code/agent-defs/LICENSE +21 -0
- package/node_modules/@poe-code/agent-defs/package.json +12 -3
- package/node_modules/@poe-code/agent-skill-config/README.md +25 -17
- package/node_modules/@poe-code/agent-skill-config/dist/templates/poe-generate.md +16 -22
- package/node_modules/@poe-code/agent-skill-config/dist/templates/terminal-pilot.md +1 -1
- package/node_modules/@poe-code/agent-skill-config/package.json +1 -0
- package/node_modules/@poe-code/config-mutations/LICENSE +21 -0
- package/node_modules/@poe-code/config-mutations/README.md +8 -8
- package/node_modules/@poe-code/config-mutations/package.json +11 -2
- package/node_modules/@poe-code/frontmatter/LICENSE +21 -0
- package/node_modules/@poe-code/frontmatter/README.md +2 -2
- package/node_modules/@poe-code/frontmatter/package.json +11 -2
- package/node_modules/toolcraft-design/LICENSE +21 -0
- package/node_modules/toolcraft-design/README.md +8 -4
- package/node_modules/toolcraft-design/dist/dashboard/terminal.js +48 -6
- package/node_modules/toolcraft-design/dist/explorer/actions.d.ts +4 -0
- package/node_modules/toolcraft-design/dist/explorer/actions.js +1 -0
- package/node_modules/toolcraft-design/dist/explorer/events.d.ts +4 -0
- package/node_modules/toolcraft-design/dist/explorer/reducer.js +52 -4
- package/node_modules/toolcraft-design/dist/explorer/render/list.js +47 -20
- package/node_modules/toolcraft-design/dist/explorer/render/modal.js +13 -1
- package/node_modules/toolcraft-design/dist/explorer/render/test-fixtures.js +1 -1
- package/node_modules/toolcraft-design/dist/explorer/runtime.js +3 -0
- package/node_modules/toolcraft-design/dist/explorer/state.d.ts +9 -0
- package/node_modules/toolcraft-design/package.json +3 -2
- package/package.json +2 -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.
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poe-code/agent-defs",
|
|
3
3
|
"version": "0.0.1",
|
|
4
|
-
"
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
5
8
|
"type": "module",
|
|
6
9
|
"main": "dist/index.js",
|
|
7
10
|
"types": "dist/index.d.ts",
|
|
@@ -15,6 +18,12 @@
|
|
|
15
18
|
"build": "node ../../scripts/guard-package-dist.mjs && tsc"
|
|
16
19
|
},
|
|
17
20
|
"files": [
|
|
18
|
-
"dist"
|
|
19
|
-
|
|
21
|
+
"dist",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/poe-platform/poe-code.git",
|
|
27
|
+
"directory": "packages/agent-defs"
|
|
28
|
+
}
|
|
20
29
|
}
|
|
@@ -13,12 +13,12 @@ Skill refs use one of two forms:
|
|
|
13
13
|
|
|
14
14
|
Examples:
|
|
15
15
|
|
|
16
|
-
| Ref
|
|
17
|
-
|
|
18
|
-
| `"my-helper"`
|
|
19
|
-
| `"claude/my-helper"`
|
|
20
|
-
| `"claude-code/my-helper"` | `~/.claude/skills/my-helper` canonical id
|
|
21
|
-
| `"codex/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
|
|
54
|
-
|
|
55
|
-
| `malformed`
|
|
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`
|
|
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
|
|
62
|
-
|
|
63
|
-
| `local-collision`
|
|
64
|
-
| `global-collision`
|
|
65
|
-
| `self-reference`
|
|
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:
|
|
3
|
+
description: "Poe Code agent prompting guidance"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Poe Code Prompting
|
|
7
7
|
|
|
8
|
-
Use
|
|
8
|
+
Use Poe Code's supported agent surfaces for prompts. The current CLI has no standalone generation command.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## One-shot Poe Agent Prompt
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
poe-code
|
|
13
|
+
poe-code agent "Summarize the current repository."
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Specify the
|
|
16
|
+
Specify a model when the command supports it:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
|
|
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
|
-
##
|
|
22
|
+
## Coding Agent Prompt
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
Use `spawn` when the prompt should run through a configured coding agent CLI:
|
|
29
25
|
|
|
30
26
|
```bash
|
|
31
|
-
poe-code
|
|
32
|
-
poe-code
|
|
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
|
-
|
|
31
|
+
Run against a GitHub locator when the work should happen outside the current checkout:
|
|
37
32
|
|
|
38
33
|
```bash
|
|
39
|
-
poe-code
|
|
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
|
-
-
|
|
47
|
-
- Use
|
|
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.
|
|
@@ -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
|
|
42
|
-
|
|
|
43
|
-
| `fs`
|
|
44
|
-
| `homeDir`
|
|
45
|
-
| `dryRun`
|
|
46
|
-
| `observers`
|
|
47
|
-
| `templates`
|
|
48
|
-
| `pathMapper` | `PathMapper`
|
|
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.
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poe-code/config-mutations",
|
|
3
3
|
"version": "0.0.1",
|
|
4
|
-
"
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
5
8
|
"type": "module",
|
|
6
9
|
"main": "dist/index.js",
|
|
7
10
|
"types": "dist/index.d.ts",
|
|
@@ -19,8 +22,14 @@
|
|
|
19
22
|
"build": "node ../../scripts/guard-package-dist.mjs && tsc"
|
|
20
23
|
},
|
|
21
24
|
"files": [
|
|
22
|
-
"dist"
|
|
25
|
+
"dist",
|
|
26
|
+
"LICENSE"
|
|
23
27
|
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/poe-platform/poe-code.git",
|
|
31
|
+
"directory": "packages/config-mutations"
|
|
32
|
+
},
|
|
24
33
|
"dependencies": {
|
|
25
34
|
"jsonc-parser": "^3.3.1",
|
|
26
35
|
"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
|
-
##
|
|
33
|
+
## Configuration Options
|
|
34
34
|
|
|
35
35
|
This package has no configuration options.
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poe-code/frontmatter",
|
|
3
3
|
"version": "0.0.1",
|
|
4
|
-
"
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
5
8
|
"type": "module",
|
|
6
9
|
"main": "dist/index.js",
|
|
7
10
|
"types": "dist/index.d.ts",
|
|
@@ -17,8 +20,14 @@
|
|
|
17
20
|
"test:unit": "cd ../.. && vitest run packages/frontmatter/src"
|
|
18
21
|
},
|
|
19
22
|
"files": [
|
|
20
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"LICENSE"
|
|
21
25
|
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/poe-platform/poe-code.git",
|
|
29
|
+
"directory": "packages/frontmatter"
|
|
30
|
+
},
|
|
22
31
|
"dependencies": {
|
|
23
32
|
"yaml": "^2.8.2"
|
|
24
33
|
}
|
|
@@ -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
|
-
|
|
121
|
+
````ts
|
|
122
122
|
import { renderMarkdown, renderMarkdownHtml } from "toolcraft-design";
|
|
123
123
|
|
|
124
|
-
const html = renderMarkdownHtml(
|
|
124
|
+
const html = renderMarkdownHtml('```ts\nconst value = "hello";\n```', {
|
|
125
125
|
syntaxHighlight: true
|
|
126
126
|
});
|
|
127
|
-
const terminal = renderMarkdown(
|
|
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.
|
|
@@ -118,19 +118,18 @@ export function createTerminalDriver(opts) {
|
|
|
118
118
|
if (destroyed) {
|
|
119
119
|
return () => { };
|
|
120
120
|
}
|
|
121
|
-
const listener = (
|
|
122
|
-
const event
|
|
123
|
-
if (event !== undefined) {
|
|
121
|
+
const listener = (chunk) => {
|
|
122
|
+
for (const event of parseKeypressChunk(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))) {
|
|
124
123
|
handler(event);
|
|
125
124
|
}
|
|
126
125
|
};
|
|
127
126
|
keypressListeners.add(listener);
|
|
128
|
-
stdin.on("
|
|
127
|
+
stdin.on("data", listener);
|
|
129
128
|
return () => {
|
|
130
129
|
if (!keypressListeners.delete(listener)) {
|
|
131
130
|
return;
|
|
132
131
|
}
|
|
133
|
-
stdin.off("
|
|
132
|
+
stdin.off("data", listener);
|
|
134
133
|
};
|
|
135
134
|
}
|
|
136
135
|
function destroy() {
|
|
@@ -138,7 +137,7 @@ export function createTerminalDriver(opts) {
|
|
|
138
137
|
return;
|
|
139
138
|
}
|
|
140
139
|
for (const listener of keypressListeners) {
|
|
141
|
-
stdin.off("
|
|
140
|
+
stdin.off("data", listener);
|
|
142
141
|
}
|
|
143
142
|
keypressListeners.clear();
|
|
144
143
|
for (const listener of resizeListeners) {
|
|
@@ -173,6 +172,9 @@ export function parseKeypress(data) {
|
|
|
173
172
|
if (data.length === 0) {
|
|
174
173
|
return undefined;
|
|
175
174
|
}
|
|
175
|
+
if (data.length === 1 && data[0] === 0x1b) {
|
|
176
|
+
return { name: "escape", ctrl: false, meta: false, shift: false };
|
|
177
|
+
}
|
|
176
178
|
const stream = new PassThrough();
|
|
177
179
|
const stdin = stream;
|
|
178
180
|
let event;
|
|
@@ -184,6 +186,46 @@ export function parseKeypress(data) {
|
|
|
184
186
|
stream.destroy();
|
|
185
187
|
return event;
|
|
186
188
|
}
|
|
189
|
+
function parseKeypressChunk(data) {
|
|
190
|
+
const events = [];
|
|
191
|
+
const input = data.toString("utf8");
|
|
192
|
+
let index = 0;
|
|
193
|
+
while (index < input.length) {
|
|
194
|
+
const sequence = nextKeySequence(input, index);
|
|
195
|
+
if (sequence.length === 0) {
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
const event = parseKeypress(Buffer.from(sequence));
|
|
199
|
+
if (event !== undefined) {
|
|
200
|
+
events.push(event);
|
|
201
|
+
}
|
|
202
|
+
index += sequence.length;
|
|
203
|
+
}
|
|
204
|
+
return events;
|
|
205
|
+
}
|
|
206
|
+
function nextKeySequence(input, index) {
|
|
207
|
+
const character = input[index];
|
|
208
|
+
if (character === undefined) {
|
|
209
|
+
return "";
|
|
210
|
+
}
|
|
211
|
+
if (character !== "\u001b") {
|
|
212
|
+
return character;
|
|
213
|
+
}
|
|
214
|
+
const next = input[index + 1];
|
|
215
|
+
if (next === undefined) {
|
|
216
|
+
return character;
|
|
217
|
+
}
|
|
218
|
+
if (next !== "[") {
|
|
219
|
+
return input.slice(index, index + 2);
|
|
220
|
+
}
|
|
221
|
+
for (let cursor = index + 2; cursor < input.length; cursor += 1) {
|
|
222
|
+
const code = input.charCodeAt(cursor);
|
|
223
|
+
if ((code >= 0x40 && code <= 0x7e) || input[cursor] === "~") {
|
|
224
|
+
return input.slice(index, cursor + 1);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return input.slice(index);
|
|
228
|
+
}
|
|
187
229
|
function toKeypressEvent(str, key) {
|
|
188
230
|
const controlCharacter = controlCharacterToKeypress(key?.sequence);
|
|
189
231
|
if (controlCharacter !== undefined) {
|
|
@@ -7,6 +7,10 @@ type ExplorerKeypressEvent = Extract<ExplorerEvent, {
|
|
|
7
7
|
export type ActionRuntimeHandles = {
|
|
8
8
|
refresh: () => Promise<void>;
|
|
9
9
|
suspendAnd: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
10
|
+
openModal: (content: {
|
|
11
|
+
title: string;
|
|
12
|
+
content: string;
|
|
13
|
+
}) => void;
|
|
10
14
|
toast: (msg: string, tone?: Tone) => void;
|
|
11
15
|
confirm: (prompt: string) => Promise<boolean>;
|
|
12
16
|
exit: (after?: () => void | Promise<void>) => void;
|
|
@@ -20,6 +20,7 @@ export function buildActionContext(state, _action, source, runtimeHandles, rowsO
|
|
|
20
20
|
filter: state.filter,
|
|
21
21
|
refresh: runtimeHandles.refresh,
|
|
22
22
|
suspendAnd: runtimeHandles.suspendAnd,
|
|
23
|
+
openModal: runtimeHandles.openModal,
|
|
23
24
|
toast: runtimeHandles.toast,
|
|
24
25
|
confirm: runtimeHandles.confirm,
|
|
25
26
|
exit: runtimeHandles.exit
|
|
@@ -5,6 +5,7 @@ const NO_EFFECTS = [];
|
|
|
5
5
|
const DEFAULT_ACTION_HANDLES = {
|
|
6
6
|
refresh: async () => undefined,
|
|
7
7
|
suspendAnd: async (fn) => fn(),
|
|
8
|
+
openModal: () => undefined,
|
|
8
9
|
toast: () => undefined,
|
|
9
10
|
confirm: async () => false,
|
|
10
11
|
exit: () => undefined
|
|
@@ -31,6 +32,13 @@ export function step(state, event, runtimeHandles = DEFAULT_ACTION_HANDLES) {
|
|
|
31
32
|
return expireToast(state);
|
|
32
33
|
case "suspendResumed":
|
|
33
34
|
return suspendResumed(state, event.emit, runtimeHandles);
|
|
35
|
+
case "modalOpened":
|
|
36
|
+
return setModal(state, {
|
|
37
|
+
kind: "content",
|
|
38
|
+
title: event.title,
|
|
39
|
+
content: event.content,
|
|
40
|
+
scroll: 0
|
|
41
|
+
});
|
|
34
42
|
case "modalDismissed":
|
|
35
43
|
return modalDismissed(state, event.result, runtimeHandles);
|
|
36
44
|
}
|
|
@@ -164,6 +172,26 @@ function stepModalKey(state, key, target, runtimeHandles) {
|
|
|
164
172
|
}
|
|
165
173
|
return paletteInput(state, key);
|
|
166
174
|
}
|
|
175
|
+
if (state.modal?.kind === "content") {
|
|
176
|
+
if (target?.type === "builtin") {
|
|
177
|
+
switch (target.id) {
|
|
178
|
+
case "escape":
|
|
179
|
+
case "confirm":
|
|
180
|
+
return modalDismissed(state, false, runtimeHandles);
|
|
181
|
+
case "cursorDown":
|
|
182
|
+
case "detailScrollDown":
|
|
183
|
+
return scrollContentModal(state, 1);
|
|
184
|
+
case "cursorUp":
|
|
185
|
+
case "detailScrollUp":
|
|
186
|
+
return scrollContentModal(state, -1);
|
|
187
|
+
case "pageDown":
|
|
188
|
+
return scrollContentModal(state, modalBodyHeight(state));
|
|
189
|
+
case "pageUp":
|
|
190
|
+
return scrollContentModal(state, -modalBodyHeight(state));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return mark(state, 0);
|
|
194
|
+
}
|
|
167
195
|
return mark(state, 0);
|
|
168
196
|
}
|
|
169
197
|
function resize(state, cols, rows) {
|
|
@@ -287,7 +315,7 @@ function suspendResumed(state, emit, runtimeHandles) {
|
|
|
287
315
|
}
|
|
288
316
|
function modalDismissed(state, result, runtimeHandles) {
|
|
289
317
|
const modal = state.modal;
|
|
290
|
-
const closed = { ...state, modal: null, dirty:
|
|
318
|
+
const closed = { ...state, modal: null, dirty: REGION_ALL };
|
|
291
319
|
if (modal?.kind === "confirm") {
|
|
292
320
|
modal.resolver(result === true);
|
|
293
321
|
}
|
|
@@ -466,9 +494,6 @@ function selectionChanged(state, selected) {
|
|
|
466
494
|
return { state: next, effects: NO_EFFECTS };
|
|
467
495
|
}
|
|
468
496
|
function detailScroll(state, delta) {
|
|
469
|
-
if (state.focused !== "detail") {
|
|
470
|
-
return mark(state, 0);
|
|
471
|
-
}
|
|
472
497
|
const scroll = clamp(state.detail.scroll + delta, 0, maxDetailScroll(state));
|
|
473
498
|
if (scroll === state.detail.scroll) {
|
|
474
499
|
return mark(state, 0);
|
|
@@ -478,6 +503,29 @@ function detailScroll(state, delta) {
|
|
|
478
503
|
effects: NO_EFFECTS
|
|
479
504
|
};
|
|
480
505
|
}
|
|
506
|
+
function scrollContentModal(state, delta) {
|
|
507
|
+
if (state.modal?.kind !== "content") {
|
|
508
|
+
return mark(state, 0);
|
|
509
|
+
}
|
|
510
|
+
const scroll = clamp(state.modal.scroll + delta, 0, maxContentModalScroll(state));
|
|
511
|
+
if (scroll === state.modal.scroll) {
|
|
512
|
+
return mark(state, 0);
|
|
513
|
+
}
|
|
514
|
+
return setModal(state, { ...state.modal, scroll });
|
|
515
|
+
}
|
|
516
|
+
function maxContentModalScroll(state) {
|
|
517
|
+
if (state.modal?.kind !== "content") {
|
|
518
|
+
return 0;
|
|
519
|
+
}
|
|
520
|
+
return Math.max(0, state.modal.content.split("\n").length - modalBodyHeight(state));
|
|
521
|
+
}
|
|
522
|
+
function modalBodyHeight(state) {
|
|
523
|
+
const screenHeight = normalizeSize(state.size.rows);
|
|
524
|
+
if (screenHeight <= 2) {
|
|
525
|
+
return 0;
|
|
526
|
+
}
|
|
527
|
+
return Math.max(0, screenHeight - 4);
|
|
528
|
+
}
|
|
481
529
|
function clampDetailScroll(state) {
|
|
482
530
|
const scroll = clamp(state.detail.scroll, 0, maxDetailScroll(state));
|
|
483
531
|
if (scroll === state.detail.scroll) {
|