one-code-extension 0.1.4 → 0.3.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/LICENSE +20 -0
- package/README.md +200 -172
- package/agents/explore.md +9 -6
- package/agents/general-purpose.md +1 -1
- package/agents/plan.md +6 -4
- package/docs/guide/README.md +52 -0
- package/docs/guide/bring-your-claude-code-setup.md +126 -0
- package/docs/guide/configuration.md +171 -0
- package/docs/guide/differences-from-claude-code.md +150 -0
- package/docs/guide/doctor.md +86 -0
- package/docs/guide/hooks.md +109 -0
- package/docs/guide/installation.md +124 -0
- package/docs/guide/permissions-modes-and-auto-mode.md +450 -0
- package/docs/guide/providers-and-models.md +194 -0
- package/docs/guide/reference.md +224 -0
- package/docs/guide/sessions-and-context.md +190 -0
- package/docs/guide/skills-plugins-and-mcp.md +176 -0
- package/docs/guide/subagents-and-workflows.md +193 -0
- package/docs/guide/tasks-and-background-work.md +111 -0
- package/docs/guide/terminal-interface.md +155 -0
- package/docs/guide/tools.md +175 -0
- package/docs/guide/troubleshooting.md +175 -0
- package/extensions/ask-user/index.ts +65 -71
- package/extensions/ask-user/questions.ts +15 -28
- package/extensions/ask-user/widget.ts +533 -0
- package/extensions/auto-mode/actions.ts +9 -26
- package/extensions/auto-mode/classifier-prompt.ts +127 -0
- package/extensions/auto-mode/classifier.ts +305 -227
- package/extensions/auto-mode/config.ts +279 -77
- package/extensions/auto-mode/defaults.ts +17 -60
- package/extensions/auto-mode/instructions.ts +2 -1
- package/extensions/auto-mode/model-picker.ts +53 -31
- package/extensions/auto-mode/model-select.ts +153 -82
- package/extensions/auto-mode/paths.ts +13 -1
- package/extensions/auto-mode/pause.ts +8 -0
- package/extensions/auto-mode/prompt.ts +205 -238
- package/extensions/auto-mode/recoverability.ts +229 -0
- package/extensions/auto-mode/rules.ts +92 -75
- package/extensions/auto-mode/safety-floor.ts +43 -12
- package/extensions/auto-mode/sensitive.ts +11 -0
- package/extensions/auto-mode/setup-run.ts +245 -0
- package/extensions/auto-mode/setup.ts +235 -0
- package/extensions/auto-mode/shell-analysis.ts +332 -26
- package/extensions/auto-mode/transcript.ts +102 -0
- package/extensions/background/index.ts +256 -43
- package/extensions/background/monitor-batch.ts +58 -0
- package/extensions/background/registry.ts +9 -0
- package/extensions/background/wakeup.ts +45 -0
- package/extensions/bash/background.ts +47 -22
- package/extensions/bash/guards.ts +229 -0
- package/extensions/bash/index.ts +81 -19
- package/extensions/branding/index.ts +44 -18
- package/extensions/branding/startup.ts +23 -8
- package/extensions/claude-compat/index.ts +17 -2
- package/extensions/claude-context/index.ts +41 -12
- package/extensions/clear/index.ts +27 -0
- package/extensions/compaction/fit.ts +121 -0
- package/extensions/compaction/index.ts +176 -71
- package/extensions/compaction/prompt.ts +21 -1
- package/extensions/context-budget/budget.ts +61 -0
- package/extensions/context-budget/index.ts +66 -0
- package/extensions/context-management/index.ts +40 -16
- package/extensions/doctor/build.ts +226 -0
- package/extensions/doctor/cli.ts +99 -0
- package/extensions/doctor/compat.ts +532 -0
- package/extensions/doctor/dependencies.ts +186 -0
- package/extensions/doctor/fix-prompt.ts +125 -0
- package/extensions/doctor/index.ts +308 -0
- package/extensions/doctor/models.ts +231 -0
- package/extensions/doctor/presets.ts +208 -0
- package/extensions/doctor/report.ts +189 -0
- package/extensions/doctor/update-lookup.ts +46 -0
- package/extensions/doctor/viewer.ts +124 -0
- package/extensions/effort/index.ts +41 -4
- package/extensions/effort/slider.ts +33 -2
- package/extensions/file-tracker/index.ts +143 -20
- package/extensions/file-tracker/replay.ts +46 -0
- package/extensions/file-tracker/tracker.ts +51 -4
- package/extensions/footer/footer-line.ts +207 -0
- package/extensions/footer/index.ts +152 -0
- package/extensions/footer/pr.ts +53 -0
- package/extensions/hooks/executor.ts +57 -20
- package/extensions/hooks/formatter-notice.ts +76 -0
- package/extensions/hooks/index.ts +314 -73
- package/extensions/hooks/matcher.ts +35 -1
- package/extensions/hooks/plugin-hooks.ts +3 -3
- package/extensions/hooks/protocol.ts +58 -0
- package/extensions/hooks/subagent-bridge.ts +77 -0
- package/extensions/hooks/trust.ts +15 -4
- package/extensions/init/index.ts +26 -0
- package/extensions/init/prompt.ts +40 -0
- package/extensions/interrupted/index.ts +35 -0
- package/extensions/interrupted/line.ts +9 -0
- package/extensions/lib/abort.ts +15 -0
- package/extensions/lib/agent-loader.ts +183 -0
- package/extensions/lib/anthropic-payload.ts +15 -0
- package/extensions/lib/atomic-write.ts +56 -0
- package/extensions/lib/bridge-watch.ts +20 -0
- package/extensions/lib/cache-retention.ts +60 -0
- package/extensions/lib/capability-index.ts +466 -0
- package/extensions/lib/claude-context.ts +318 -27
- package/extensions/lib/claude-settings.ts +64 -0
- package/extensions/lib/consent-preview.ts +30 -0
- package/extensions/lib/deferred.ts +144 -13
- package/extensions/lib/favorites.ts +43 -0
- package/extensions/lib/fetch-timeout.ts +15 -0
- package/extensions/lib/frontmatter.ts +31 -0
- package/extensions/lib/git.ts +44 -2
- package/extensions/lib/hook-gate.ts +90 -0
- package/extensions/lib/interrupt.ts +94 -0
- package/extensions/lib/mcp-overrides.ts +61 -0
- package/extensions/lib/mcp-share.ts +25 -0
- package/extensions/lib/mcp-status.ts +34 -0
- package/extensions/lib/memory.ts +41 -6
- package/extensions/lib/model-facts.generated.json +2480 -0
- package/extensions/lib/model-facts.ts +162 -0
- package/extensions/lib/model-policy.ts +145 -189
- package/extensions/lib/model-tier.ts +480 -64
- package/extensions/lib/model-unusable.ts +37 -0
- package/extensions/lib/notifications.ts +320 -1
- package/extensions/lib/one-code-settings.ts +63 -0
- package/extensions/lib/original-command.ts +71 -0
- package/extensions/lib/package-version.ts +31 -0
- package/extensions/lib/paths.ts +39 -4
- package/extensions/lib/permission-gate.ts +192 -0
- package/extensions/lib/persisted-output.ts +18 -0
- package/extensions/lib/pi-ai-estimate.ts +160 -0
- package/extensions/lib/pi-version.ts +1 -1
- package/extensions/lib/plan-mode-channels.ts +11 -0
- package/extensions/lib/plugin-overrides.ts +24 -0
- package/extensions/lib/plugin-root.ts +44 -0
- package/extensions/lib/plugins.ts +233 -54
- package/extensions/lib/prefix-warm-gate.ts +157 -0
- package/extensions/lib/process-tree.ts +56 -0
- package/extensions/lib/reminders.ts +321 -68
- package/extensions/lib/scratchpad.ts +11 -8
- package/extensions/lib/session-lifecycle.ts +28 -0
- package/extensions/lib/settings-channels.ts +14 -0
- package/extensions/lib/shell-tasks.ts +54 -0
- package/extensions/lib/skill-overrides.ts +86 -0
- package/extensions/lib/skill-scan.ts +110 -0
- package/extensions/lib/text-width.ts +267 -0
- package/extensions/lib/tui-render.ts +281 -54
- package/extensions/lib/usage-bus.ts +75 -0
- package/extensions/lib/usage-tracker.ts +67 -0
- package/extensions/lib/worktree-isolation.ts +170 -0
- package/extensions/lsp/client.ts +69 -12
- package/extensions/lsp/format.ts +12 -2
- package/extensions/lsp/index.ts +273 -84
- package/extensions/lsp/install-hints.ts +43 -0
- package/extensions/lsp/keep-alive.ts +19 -0
- package/extensions/lsp/plugin-servers.ts +331 -0
- package/extensions/lsp/watcher.ts +157 -0
- package/extensions/mcp/announce.ts +99 -0
- package/extensions/mcp/client.ts +181 -22
- package/extensions/mcp/config.ts +55 -24
- package/extensions/mcp/index.ts +586 -86
- package/extensions/mcp/oauth/browser.ts +26 -0
- package/extensions/mcp/oauth/callback.ts +104 -0
- package/extensions/mcp/oauth/flow.ts +68 -0
- package/extensions/mcp/oauth/provider.ts +147 -0
- package/extensions/mcp/oauth/store.ts +86 -0
- package/extensions/mcp/panel/keys.ts +34 -0
- package/extensions/mcp/panel/model.ts +62 -0
- package/extensions/mcp/panel/render.ts +141 -0
- package/extensions/mcp/panel/state.ts +108 -0
- package/extensions/mcp/schema.ts +83 -6
- package/extensions/mcp/trust.ts +340 -0
- package/extensions/memory/entries.ts +163 -0
- package/extensions/memory/index.ts +119 -2
- package/extensions/memory/open-external.ts +97 -0
- package/extensions/memory/panel.ts +124 -0
- package/extensions/model-default/index.ts +74 -0
- package/extensions/notebook/index.ts +36 -18
- package/extensions/notebook/notebook.ts +110 -17
- package/extensions/permissions/index.ts +1012 -247
- package/extensions/permissions/matcher.ts +488 -57
- package/extensions/permissions/modes.ts +55 -7
- package/extensions/permissions/project-trust.ts +81 -0
- package/extensions/permissions/protected-paths.ts +16 -3
- package/extensions/permissions/rule-prose.ts +79 -0
- package/extensions/permissions/session-grant.ts +91 -0
- package/extensions/permissions/settings.ts +112 -33
- package/extensions/permissions/subagent-gate.ts +57 -0
- package/extensions/plan-mode/index.ts +143 -33
- package/extensions/plan-mode/reminder.ts +16 -19
- package/extensions/plan-mode/viewer.ts +40 -31
- package/extensions/plugins/counts.ts +68 -0
- package/extensions/plugins/index.ts +496 -32
- package/extensions/plugins/install/install.ts +167 -0
- package/extensions/plugins/install/paths.ts +23 -0
- package/extensions/plugins/install/registry.ts +72 -0
- package/extensions/plugins/marketplace/git.ts +103 -0
- package/extensions/plugins/marketplace/official.ts +36 -0
- package/extensions/plugins/marketplace/parse.ts +94 -0
- package/extensions/plugins/marketplace/registry.ts +60 -0
- package/extensions/plugins/marketplace/sync.ts +146 -0
- package/extensions/plugins/marketplace/types.ts +128 -0
- package/extensions/plugins/panel/keys.ts +52 -0
- package/extensions/plugins/panel/render.ts +315 -0
- package/extensions/plugins/panel/rows.ts +230 -0
- package/extensions/plugins/panel/state.ts +333 -0
- package/extensions/recap/index.ts +215 -0
- package/extensions/recap/prompt.ts +44 -0
- package/extensions/recap/scheduler.ts +87 -0
- package/extensions/search-tools/index.ts +0 -0
- package/extensions/search-tools/tools.ts +7 -5
- package/extensions/skill/index.ts +360 -34
- package/extensions/skill/invoke.ts +185 -0
- package/extensions/skill/listing.ts +21 -0
- package/extensions/skill/panel/keys.ts +41 -0
- package/extensions/skill/panel/render.ts +91 -0
- package/extensions/skill/panel/state.ts +115 -0
- package/extensions/spinner/index.ts +110 -0
- package/extensions/spinner/line.ts +51 -0
- package/extensions/spinner/verbs.ts +201 -0
- package/extensions/subagents/agents.ts +88 -44
- package/extensions/subagents/default-model.ts +62 -32
- package/extensions/subagents/delegation-steer.ts +23 -0
- package/extensions/subagents/hand-back-review.ts +67 -0
- package/extensions/subagents/index.ts +1545 -346
- package/extensions/subagents/live-runs.ts +293 -0
- package/extensions/subagents/model-select.ts +252 -82
- package/extensions/subagents/outcome.ts +90 -0
- package/extensions/subagents/panel-keys.ts +41 -0
- package/extensions/subagents/panel-render.ts +357 -0
- package/extensions/subagents/panel-widget.ts +330 -0
- package/extensions/subagents/pending-claim.ts +45 -0
- package/extensions/subagents/prose.ts +105 -0
- package/extensions/subagents/runner.ts +674 -0
- package/extensions/subagents/runs.ts +68 -1
- package/extensions/subagents/send-to-main-tool.ts +55 -0
- package/extensions/subagents/session-turns.ts +138 -0
- package/extensions/subagents/shell-panel.ts +198 -0
- package/extensions/subagents/usage.ts +16 -4
- package/extensions/subagents/worktree.ts +13 -0
- package/extensions/system-prompt/environment.ts +5 -3
- package/extensions/system-prompt/git-status.ts +93 -0
- package/extensions/system-prompt/index.ts +23 -1
- package/extensions/system-prompt/template.ts +34 -4
- package/extensions/system-prompt/tiers/common.ts +31 -6
- package/extensions/system-prompt/tiers/low.ts +13 -3
- package/extensions/system-prompt/tiers/mid.ts +21 -8
- package/extensions/system-reminder/index.ts +53 -9
- package/extensions/tasks/index.ts +65 -16
- package/extensions/tasks/store.ts +76 -3
- package/extensions/tool-search/announce.ts +42 -0
- package/extensions/tool-search/index.ts +136 -13
- package/extensions/turn-duration/index.ts +60 -0
- package/extensions/turn-duration/line.ts +22 -0
- package/extensions/turn-duration/span.ts +41 -0
- package/extensions/turn-duration/verbs.ts +24 -0
- package/extensions/web/backends.ts +421 -0
- package/extensions/web/index.ts +178 -21
- package/extensions/web-fetch/index.ts +74 -18
- package/extensions/web-fetch/summarize.ts +1 -1
- package/extensions/workflow/agent-session.ts +182 -112
- package/extensions/workflow/globals.ts +129 -106
- package/extensions/workflow/index.ts +343 -28
- package/extensions/workflow/records.ts +118 -0
- package/extensions/workflow/run-manager.ts +80 -31
- package/extensions/workflow/saved-workflows.ts +2 -1
- package/extensions/workflow/script-worker.mjs +110 -0
- package/extensions/workflow/types.ts +74 -8
- package/extensions/workflow/viewer.ts +562 -0
- package/extensions/workflow/vm-runtime.ts +118 -22
- package/extensions/workflow/widget.ts +126 -18
- package/extensions/worktree/guards.ts +240 -0
- package/extensions/worktree/index.ts +30 -5
- package/extensions/worktree/rewrite.ts +32 -16
- package/package.json +20 -10
- package/skills/code-review/SKILL.md +165 -0
- package/skills/fewer-permission-prompts/SKILL.md +61 -0
- package/skills/security-review/SKILL.md +178 -0
- package/skills/simplify/SKILL.md +70 -0
- package/themes/{one-code-light.json → onecode-light.json} +6 -1
- package/themes/{one-code.json → onecode.json} +6 -1
- package/types/app.d.ts +8 -1
- package/types/community-packages.d.ts +45 -2
- package/docs/decisions/auto-mode.md +0 -526
- package/docs/decisions/branding.md +0 -127
- package/docs/decisions/code-review-remediation.md +0 -106
- package/docs/decisions/compaction.md +0 -140
- package/docs/decisions/distribution.md +0 -168
- package/docs/decisions/hooks.md +0 -64
- package/docs/decisions/lsp.md +0 -58
- package/docs/decisions/mcp.md +0 -104
- package/docs/decisions/memory-state.md +0 -170
- package/docs/decisions/model-policy.md +0 -126
- package/docs/decisions/modes.md +0 -178
- package/docs/decisions/skills-plugins.md +0 -56
- package/docs/decisions/subagents-workflows.md +0 -225
- package/docs/decisions/system-prompt.md +0 -98
- package/docs/decisions/tools.md +0 -407
- package/docs/decisions/tui.md +0 -217
- package/docs/decisions.md +0 -148
- package/extensions/subagents/child.ts +0 -414
- package/extensions/subagents/rpc-turns.ts +0 -123
- package/extensions/todo/index.ts +0 -133
- package/extensions/workflow/permission-gate.ts +0 -71
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Tools
|
|
2
|
+
|
|
3
|
+
The model works by calling tools. You do not type tool names; you describe
|
|
4
|
+
the task and the model chooses. This page lists every tool One Code gives
|
|
5
|
+
the model, what each does, what you see when it runs, and how Claude Code's
|
|
6
|
+
tool names map onto them.
|
|
7
|
+
|
|
8
|
+
Every tool call passes through the permission gate. See
|
|
9
|
+
[Permissions, modes, and auto mode](permissions-modes-and-auto-mode.md).
|
|
10
|
+
|
|
11
|
+
## Eager and deferred tools
|
|
12
|
+
|
|
13
|
+
Tools come in two kinds:
|
|
14
|
+
|
|
15
|
+
- **Eager tools** are in every request. These are the tools the model uses
|
|
16
|
+
constantly: `read`, `write`, `edit`, `bash`, `Agent`, `skill`,
|
|
17
|
+
`ask_user_question`, `workflow`, and `tool_search`.
|
|
18
|
+
- **Deferred tools** are listed by name only. When the model needs one, it
|
|
19
|
+
calls `tool_search` to load the full definition, and the tool stays
|
|
20
|
+
available for the rest of the session. This keeps the prompt small and
|
|
21
|
+
works the same way on every model tier and provider.
|
|
22
|
+
|
|
23
|
+
Run `/tools-deferred` to see which deferred tools are loaded and which are
|
|
24
|
+
still waiting. The list is fixed once the first request has gone out, so a
|
|
25
|
+
tool that appears later (an MCP server that connects slowly, for example)
|
|
26
|
+
is announced to the model separately.
|
|
27
|
+
|
|
28
|
+
## Files and code
|
|
29
|
+
|
|
30
|
+
| Tool | What it does |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `read` | Reads a file. Shown as `● Read(path)` in the transcript. |
|
|
33
|
+
| `write` | Creates or overwrites a file. The model must have read an existing file in this conversation before writing it. |
|
|
34
|
+
| `edit` | Replaces an exact string in a file. Shown as `● Update(path)`. The same read-before-write rule applies, and the edit is refused if the file changed on disk since the model last read it. |
|
|
35
|
+
| `notebook_edit` | Edits a Jupyter notebook cell: replace, insert, append, or delete. Editing a code cell clears its outputs. Deferred. |
|
|
36
|
+
| `grep`, `find`, `ls` | pi's search tools. Active only for the smallest model tier; on other tiers, searching goes through `bash`, as in Claude Code. |
|
|
37
|
+
|
|
38
|
+
The read-before-write and stale-edit guards track file **content**, not tool
|
|
39
|
+
calls, so a file the model changed through a shell command is tracked too.
|
|
40
|
+
When a file changes outside the model's view (you edited it, a formatter
|
|
41
|
+
ran, a `git checkout` happened) the model is told, with the changed lines,
|
|
42
|
+
and must re-read the file before editing it. A file that disappears is
|
|
43
|
+
reported as deleted or moved.
|
|
44
|
+
|
|
45
|
+
## Shell
|
|
46
|
+
|
|
47
|
+
`bash` runs a shell command. Its `run_in_background` option starts the
|
|
48
|
+
command detached and returns a task id; output spools to a log file under
|
|
49
|
+
the session directory, and completion is reported to the model as a
|
|
50
|
+
notification. A background shell shows up in the shells section of the
|
|
51
|
+
panel below the editor. See
|
|
52
|
+
[Tasks and background work](tasks-and-background-work.md).
|
|
53
|
+
|
|
54
|
+
Some command shapes are refused before they run, with a message that steers
|
|
55
|
+
the model to a better route:
|
|
56
|
+
|
|
57
|
+
- A foreground command that starts with `sleep`, or a polling loop that
|
|
58
|
+
sleeps, when the wait is not provably short. The model is told to use
|
|
59
|
+
`run_in_background` or `monitor` instead.
|
|
60
|
+
- A command that would orphan a process (`nohup`, `setsid`, or a trailing
|
|
61
|
+
`&` with no `wait`).
|
|
62
|
+
- An interactive program that would stop responding without a terminal:
|
|
63
|
+
`vim`, `git rebase -i`, `git add -p`, `watch`, and similar.
|
|
64
|
+
- Inside a worktree session, a git command aimed at a different checkout.
|
|
65
|
+
|
|
66
|
+
## Web
|
|
67
|
+
|
|
68
|
+
| Tool | What it does |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `web_search` | Searches the web. Uses your provider's own search when it has one (Anthropic, OpenAI, Gemini, xAI); otherwise falls back to Brave, then Tavily, then Exa's free keyless endpoint. Results from the keyless endpoint are labelled, and the first use in a session shows a warning. See [Web search](providers-and-models.md#web-search-on-providers-without-a-search-api). Deferred. |
|
|
71
|
+
| `web_fetch` | Fetches a URL and converts it to readable Markdown. Follows same-host redirects; reports cross-host redirects instead of following them. Responses are cached for 15 minutes. With a `prompt`, a small reader model on your provider answers the question against the page, so the page itself stays out of your context; if the reader fails, the raw page is returned with a note. Deferred. |
|
|
72
|
+
| `url_context` | Gemini's page-context tool, available only when a Gemini model is in use. Deferred. |
|
|
73
|
+
|
|
74
|
+
## Delegation
|
|
75
|
+
|
|
76
|
+
| Tool | What it does |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `Agent` | Starts a subagent with its own context window. Runs in the background and returns a task id; the result arrives as a notification. Supports forking the current conversation and isolating the agent in a git worktree. |
|
|
79
|
+
| `SendMessage` | Sends a message to an agent that was started earlier: a running one receives it live, a finished one is resumed from its saved session. Deferred. |
|
|
80
|
+
| `list_agents` | Lists the agents started in this session and their status. Deferred. |
|
|
81
|
+
| `workflow` | Runs a JavaScript script that coordinates many agents. This is the `ultracode` mechanism. |
|
|
82
|
+
|
|
83
|
+
See [Subagents and workflows](subagents-and-workflows.md).
|
|
84
|
+
|
|
85
|
+
## Planning and asking
|
|
86
|
+
|
|
87
|
+
| Tool | What it does |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `enter_plan_mode`, `exit_plan_mode` | Switch into plan mode and ask you to approve the plan file. Deferred. See [Plan mode](permissions-modes-and-auto-mode.md#plan-mode). |
|
|
90
|
+
| `ask_user_question` | Asks you up to four structured questions in a tabbed dialog. See [The terminal interface](terminal-interface.md#the-question-dialog). |
|
|
91
|
+
| `skill` | Runs a skill by name. See [Skills](skills-plugins-and-mcp.md#skills). |
|
|
92
|
+
|
|
93
|
+
## Tasks and background work
|
|
94
|
+
|
|
95
|
+
| Tool | What it does |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `task_create`, `task_get`, `task_list`, `task_update` | Maintain the structured task list shown in the pinned widget. Deferred. |
|
|
98
|
+
| `monitor` | Watches a long-running command or a WebSocket and reports each output line as an event. Deferred. |
|
|
99
|
+
| `task_output`, `task_stop` | Read the output of a background task or stop it. Deferred. |
|
|
100
|
+
| `schedule_wakeup` | Schedules a prompt for later; the mechanism behind self-paced `/loop`. Deferred. |
|
|
101
|
+
|
|
102
|
+
See [Tasks and background work](tasks-and-background-work.md).
|
|
103
|
+
|
|
104
|
+
## Worktrees
|
|
105
|
+
|
|
106
|
+
`enter_worktree` creates a git worktree under `.claude/worktrees/`, branched
|
|
107
|
+
from the current `HEAD`, and moves the session into it: every shell command
|
|
108
|
+
and relative path then resolves there, and your main working tree is
|
|
109
|
+
untouched. `exit_worktree` leaves it, either keeping the worktree or
|
|
110
|
+
removing it; removal is refused while the worktree has uncommitted or
|
|
111
|
+
unmerged work unless the model passes `discard_changes`. The worktrees
|
|
112
|
+
directory ignores itself in git. Both tools are deferred.
|
|
113
|
+
|
|
114
|
+
## Diagnostics
|
|
115
|
+
|
|
116
|
+
`lsp_diagnostics` asks a language server for the diagnostics of one file.
|
|
117
|
+
Separately, after every round of edits, new diagnostics from every running
|
|
118
|
+
server are attached to the last tool result as a `<new-diagnostics>` block,
|
|
119
|
+
including diagnostics in other files that the edit broke. See
|
|
120
|
+
[Language-server diagnostics](configuration.md#language-server-diagnostics).
|
|
121
|
+
Deferred.
|
|
122
|
+
|
|
123
|
+
## MCP
|
|
124
|
+
|
|
125
|
+
Every tool an MCP server provides appears as `mcp__<server>__<tool>`,
|
|
126
|
+
deferred until needed. `list_mcp_resources`, `read_mcp_resource`, and
|
|
127
|
+
`read_mcp_resource_dir` read the resources servers expose. See
|
|
128
|
+
[MCP servers](skills-plugins-and-mcp.md#mcp-servers).
|
|
129
|
+
|
|
130
|
+
## Tool discovery
|
|
131
|
+
|
|
132
|
+
`tool_search` loads deferred tools. The model passes exact names
|
|
133
|
+
(`select:monitor,task_output`), a required term (`+notebook`), or free
|
|
134
|
+
keywords. If the model calls a tool it has not loaded yet, the call fails
|
|
135
|
+
and the model is steered to `tool_search`.
|
|
136
|
+
|
|
137
|
+
## Behavior in non-interactive runs
|
|
138
|
+
|
|
139
|
+
In `-p` and `--mode json` runs the process exits when the turn settles, so
|
|
140
|
+
nothing can run in the background. Tools that would detach work run to
|
|
141
|
+
completion instead and return the output in their result: `bash` with
|
|
142
|
+
`run_in_background`, `Agent`, `monitor`, and `workflow`. Timers such as
|
|
143
|
+
`schedule_wakeup` and `/loop` never fire in these modes.
|
|
144
|
+
|
|
145
|
+
## Claude Code tool names
|
|
146
|
+
|
|
147
|
+
Claude Code's tool names are accepted in permission rules and hook
|
|
148
|
+
matchers, and mapped to One Code's names. Case is ignored.
|
|
149
|
+
|
|
150
|
+
| Claude Code | One Code |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `Bash` | `bash` |
|
|
153
|
+
| `Read`, `Write`, `Edit` | `read`, `write`, `edit` |
|
|
154
|
+
| `Grep`, `Glob`, `LS` | `grep`, `find`, `ls` |
|
|
155
|
+
| `NotebookEdit` | `notebook_edit` |
|
|
156
|
+
| `WebFetch`, `WebSearch` | `web_fetch`, `web_search` |
|
|
157
|
+
| `Task`, `Agent` | `Agent` |
|
|
158
|
+
| `SendMessage` | `SendMessage` |
|
|
159
|
+
| `ListAgents` | `list_agents` |
|
|
160
|
+
| `Skill` | `skill` |
|
|
161
|
+
| `ToolSearch` | `tool_search` |
|
|
162
|
+
| `AskUserQuestion` | `ask_user_question` |
|
|
163
|
+
| `Workflow` | `workflow` |
|
|
164
|
+
| `TaskCreate`, `TaskGet`, `TaskList`, `TaskUpdate` | `task_create`, `task_get`, `task_list`, `task_update` |
|
|
165
|
+
| `TodoWrite` | `task_create` |
|
|
166
|
+
| `TaskOutput`, `TaskStop` | `task_output`, `task_stop` |
|
|
167
|
+
| `Monitor` | `monitor` |
|
|
168
|
+
| `ScheduleWakeup` | `schedule_wakeup` |
|
|
169
|
+
| `EnterWorktree`, `ExitWorktree` | `enter_worktree`, `exit_worktree` |
|
|
170
|
+
| `LSP` | `lsp_diagnostics` |
|
|
171
|
+
| `ListMcpResourcesTool`, `ReadMcpResourceTool`, `ReadMcpResourceDirTool` | `list_mcp_resources`, `read_mcp_resource`, `read_mcp_resource_dir` |
|
|
172
|
+
| `mcp__<server>__<tool>` | Unchanged |
|
|
173
|
+
|
|
174
|
+
Claude Code tools that have no One Code equivalent are listed in
|
|
175
|
+
[Differences from Claude Code](differences-from-claude-code.md#tools-that-are-not-provided).
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Symptoms you might hit, what causes them, and what to do.
|
|
4
|
+
|
|
5
|
+
## Start with the doctor
|
|
6
|
+
|
|
7
|
+
Most setup problems show up in the report:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
onecode doctor
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Inside a session, `/doctor report` shows the same report and `/doctor` has
|
|
14
|
+
the model fix what it finds. See [Check your setup with doctor](doctor.md).
|
|
15
|
+
|
|
16
|
+
## Installation and startup
|
|
17
|
+
|
|
18
|
+
**`onecode requires Node >= 22.19`.** The bundled app refuses to start on
|
|
19
|
+
older Node, because pi crashes at import time there. Install Node 22.19 or
|
|
20
|
+
later, or use the Homebrew formula, which installs Node for you.
|
|
21
|
+
|
|
22
|
+
**`brew install` says no matching version was found.** Homebrew refuses
|
|
23
|
+
npm packages published less than a day ago. Wait a day after a release, or
|
|
24
|
+
install with `npm install -g @one-ai/one-code` in the meantime.
|
|
25
|
+
|
|
26
|
+
**The banner shows `model none`.** No provider has credentials. Run
|
|
27
|
+
`/login`, or set a provider key such as `ANTHROPIC_API_KEY` before
|
|
28
|
+
launching. Two providers offer free models; see
|
|
29
|
+
[Connect your first provider](providers-and-models.md#connect-your-first-provider).
|
|
30
|
+
|
|
31
|
+
**A warning says the pi version is outside the tested range.** This appears
|
|
32
|
+
on the extension installation when your pi is newer or older than the
|
|
33
|
+
versions One Code was tested against. Most things keep working; if
|
|
34
|
+
something breaks, pin pi to a tested version or use the bundled app, which
|
|
35
|
+
pins pi itself.
|
|
36
|
+
|
|
37
|
+
**`Failed to load extension` on startup.** The extension package and the
|
|
38
|
+
pi it runs on are out of step. On the bundled app, reinstall it. On your own
|
|
39
|
+
pi, run `pi update --extensions`.
|
|
40
|
+
|
|
41
|
+
**The stock pi first-run wizard did not appear.** The bundled app seeds
|
|
42
|
+
pi's settings with the One Code theme, quiet startup, and full-screen mode
|
|
43
|
+
on first run, so there is nothing to ask.
|
|
44
|
+
|
|
45
|
+
## Permissions
|
|
46
|
+
|
|
47
|
+
**Auto mode is missing from the ctrl+q cycle.** Auto mode needs a model to
|
|
48
|
+
run its classifier. Connect a provider.
|
|
49
|
+
|
|
50
|
+
**ctrl+q does something else.** On Windows and WSL, pi's default
|
|
51
|
+
keybindings also bind ctrl+q, to queue a follow-up message. Rebind one of
|
|
52
|
+
them in pi's keybindings file.
|
|
53
|
+
|
|
54
|
+
**Everything prompts, even in auto mode.** Auto mode pauses after several
|
|
55
|
+
blocked actions in a row and prompts you once; approving resumes it. Also
|
|
56
|
+
check `/permissions`: an `ask` rule prompts in every mode.
|
|
57
|
+
|
|
58
|
+
**An allow rule I wrote has no effect in auto mode.** Broad execution rules
|
|
59
|
+
(`Bash(*)`, wildcarded interpreters, delegation rules) are suspended in
|
|
60
|
+
auto mode so they cannot bypass the classifier. Session grants from the
|
|
61
|
+
approval prompt are also ignored there. Narrow the rule or switch to
|
|
62
|
+
accept-edits or manual mode.
|
|
63
|
+
|
|
64
|
+
**A project's `defaultMode: "auto"` is ignored.** Project-scope settings
|
|
65
|
+
may not select auto or bypass mode. Set it in `~/.claude/settings.json`
|
|
66
|
+
or pass `--permission-mode auto`.
|
|
67
|
+
|
|
68
|
+
**`defaultMode` in `~/.onecode/settings.json` does nothing.** The
|
|
69
|
+
permission loader does not read that key from One Code's file. Use a Claude
|
|
70
|
+
Code settings file or the flag.
|
|
71
|
+
|
|
72
|
+
**The model is denied a write to `.claude/settings.json`.** The auto-mode
|
|
73
|
+
safety floor never lets the model change the gate's own configuration
|
|
74
|
+
unattended. Approve the prompt, or make the edit yourself.
|
|
75
|
+
|
|
76
|
+
**Every action is denied in a `-p` run.** Nothing can prompt in a
|
|
77
|
+
non-interactive run, so anything that would have prompted is denied. Add
|
|
78
|
+
allow rules, or use auto mode with a provider that can run the classifier.
|
|
79
|
+
|
|
80
|
+
## Auto-mode classifier
|
|
81
|
+
|
|
82
|
+
**Actions are blocked with a message about the classifier being
|
|
83
|
+
unavailable.** The classifier model could not be reached or returned
|
|
84
|
+
nothing usable; the gate fails closed. Check `/auto-mode config` for the
|
|
85
|
+
model in use, and `/doctor report` for provider credentials. Set
|
|
86
|
+
`CC_AUTO_MODE_DEBUG=1` to see each verdict on stderr.
|
|
87
|
+
|
|
88
|
+
**The classifier approves or blocks something it should not.** Choose a
|
|
89
|
+
stronger classifier with `/auto-mode model <provider/model-id>`. A
|
|
90
|
+
Haiku-class classifier is a measurably weaker boundary than a Sonnet-class
|
|
91
|
+
one.
|
|
92
|
+
|
|
93
|
+
## Models and providers
|
|
94
|
+
|
|
95
|
+
**The subagent model is stale after switching providers.** A saved
|
|
96
|
+
`/subagent` choice from another provider no longer applies. Run
|
|
97
|
+
`/subagent status`, then `/subagent clear` or pick a model on the current
|
|
98
|
+
provider.
|
|
99
|
+
|
|
100
|
+
**Cache-hit in the footer is low.** Changing the model or the effort level
|
|
101
|
+
re-caches the conversation once. A `-p` run and every subagent use the
|
|
102
|
+
provider's short cache lifetime. A persistent low rate on an interactive
|
|
103
|
+
session is worth reporting.
|
|
104
|
+
|
|
105
|
+
**A side call failed on a Gemini or OpenAI model with a message about
|
|
106
|
+
reasoning or temperature.** Some models reject an option others accept.
|
|
107
|
+
One Code avoids these options in its side calls; if you still see this,
|
|
108
|
+
choose a different classifier or reader model and report the model.
|
|
109
|
+
|
|
110
|
+
## Web search
|
|
111
|
+
|
|
112
|
+
**A warning about Exa's free keyless endpoint.** Your provider has no
|
|
113
|
+
search of its own and you set no Brave or Tavily key, so search fell back
|
|
114
|
+
to a rate-limited endpoint. Set `BRAVE_SEARCH_API_KEY` or
|
|
115
|
+
`TAVILY_API_KEY`, or add the key to `~/.onecode/settings.json`. See
|
|
116
|
+
[Web search](providers-and-models.md#web-search-on-providers-without-a-search-api).
|
|
117
|
+
|
|
118
|
+
## Language servers
|
|
119
|
+
|
|
120
|
+
**No diagnostics appear after edits.** The language server must be on the
|
|
121
|
+
`PATH` One Code was launched with. Run `/lsp` for each server's status and
|
|
122
|
+
`/doctor report` for install hints.
|
|
123
|
+
|
|
124
|
+
**TypeScript diagnostics fail with a message about `lib/tsserver.js`.**
|
|
125
|
+
TypeScript 7's native compiler does not ship that file, and
|
|
126
|
+
`typescript-language-server` needs it. Install a TypeScript 5.x development
|
|
127
|
+
dependency in the project.
|
|
128
|
+
|
|
129
|
+
## MCP servers
|
|
130
|
+
|
|
131
|
+
**A server from `.mcp.json` is disabled.** Project servers run only after
|
|
132
|
+
you approve them. Open `/mcp`, select the server, and choose Enable.
|
|
133
|
+
|
|
134
|
+
**A server asks for approval again.** Its command or URL changed since you
|
|
135
|
+
approved it. Approvals are tied to the configuration.
|
|
136
|
+
|
|
137
|
+
**A server needs sign-in.** Open `/mcp`, select the server, and choose
|
|
138
|
+
Authenticate. Tokens are stored under `~/.onecode/mcp-auth/`.
|
|
139
|
+
|
|
140
|
+
## Hooks
|
|
141
|
+
|
|
142
|
+
**A project's hooks do not run.** They need one-time approval at startup.
|
|
143
|
+
Restart the session and accept, or check
|
|
144
|
+
`~/.onecode/hooks/project-approvals.json`.
|
|
145
|
+
|
|
146
|
+
**A hook blocks a call with no message.** A `PreToolUse` or
|
|
147
|
+
`UserPromptSubmit` hook that times out blocks by design. Set
|
|
148
|
+
`CC_HOOKS_DEBUG=1` to see each dispatch and outcome.
|
|
149
|
+
|
|
150
|
+
## Sessions
|
|
151
|
+
|
|
152
|
+
**My background shells are gone after `/clear`.** Background work ends
|
|
153
|
+
with the session. The new session lists what was stopped.
|
|
154
|
+
|
|
155
|
+
**A resumed session is in a different permission mode.** Modes are not
|
|
156
|
+
saved with the session. Pass `--permission-mode` or set a default.
|
|
157
|
+
|
|
158
|
+
**The `/effort` level reset after a restart.** `/effort` does not save the
|
|
159
|
+
level. Open pi's `/thinking` picker and press **ctrl+s** to save a startup
|
|
160
|
+
default, or pass `--thinking <level>` at launch.
|
|
161
|
+
|
|
162
|
+
## Interface
|
|
163
|
+
|
|
164
|
+
**PgUp and PgDn do nothing in a panel.** In full-screen mode pi uses them
|
|
165
|
+
for its scrollback. Use the keys the panel's footer names (**Space** and
|
|
166
|
+
**b** page in the doctor report, for example).
|
|
167
|
+
|
|
168
|
+
**I want pi's own banner, footer, or spinner back.** Set `CC_NO_BANNER=1`,
|
|
169
|
+
`CC_FOOTER=0`, or the other toggles listed in
|
|
170
|
+
[Environment variables](reference.md#environment-variables).
|
|
171
|
+
|
|
172
|
+
## Getting help
|
|
173
|
+
|
|
174
|
+
Report problems at the project's GitHub repository. Include the output of
|
|
175
|
+
`onecode doctor`, your platform, and the model and provider in use.
|
|
@@ -1,64 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ask-user extension — Claude Code's AskUserQuestion.
|
|
3
3
|
*
|
|
4
|
-
* Asks the user up to four multiple-choice questions
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Asks the user up to four multiple-choice questions in one tabbed dialog
|
|
5
|
+
* (widget.ts): a tab per question plus Submit, option previews rendered
|
|
6
|
+
* beside the list, per-question notes, multi-select checkboxes, an inline
|
|
7
|
+
* free-text row, and "Chat about this" to decline and discuss in chat
|
|
8
|
+
* instead. The collected answers come back as one tool result.
|
|
8
9
|
*
|
|
9
10
|
* Replaces the community `pi-ask-user`, which asked one question per call and
|
|
10
11
|
* pulled in a second, conflicting TypeBox.
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
|
-
import type { ExtensionAPI
|
|
14
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
14
15
|
import { Type } from "typebox";
|
|
15
|
-
import { ccToolRenderers } from "../lib/tui-render.ts";
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
buildChoices,
|
|
19
|
-
DONE_LABEL,
|
|
20
|
-
formatAnswers,
|
|
21
|
-
OTHER_LABEL,
|
|
22
|
-
type Question,
|
|
23
|
-
resolveSelection,
|
|
24
|
-
stripMark,
|
|
25
|
-
} from "./questions.ts";
|
|
16
|
+
import { ccToolRenderers, safeThemeBold, safeThemeInverse, safeThemePaint } from "../lib/tui-render.ts";
|
|
17
|
+
import { type Answer, formatAnswers, formatDecline, type Question } from "./questions.ts";
|
|
18
|
+
import { applyWidgetKey, createWidgetState, decodeWidgetKey, renderWidget, type WidgetResult } from "./widget.ts";
|
|
26
19
|
|
|
27
20
|
const NON_INTERACTIVE =
|
|
28
21
|
"This session has no interactive UI, so the user cannot be shown a dialog. Ask your question in your reply instead and stop, or proceed under a stated assumption.";
|
|
29
22
|
|
|
30
|
-
async function askOne(question: Question, ctx: ExtensionContext): Promise<Answer | undefined> {
|
|
31
|
-
const selected: string[] = [];
|
|
32
|
-
const title = `${question.header}\n\n${question.question}`;
|
|
33
|
-
|
|
34
|
-
// Multi-select loops until the user is done; single-select runs once.
|
|
35
|
-
for (let round = 0; round < question.options.length + 1; round++) {
|
|
36
|
-
const choice = await ctx.ui.select(title, buildChoices(question, selected));
|
|
37
|
-
if (choice === undefined) return undefined; // cancelled
|
|
38
|
-
|
|
39
|
-
if (choice === DONE_LABEL) break;
|
|
40
|
-
|
|
41
|
-
if (choice === OTHER_LABEL) {
|
|
42
|
-
const typed = await ctx.ui.input(question.question, "Type your answer");
|
|
43
|
-
if (typed === undefined) return undefined;
|
|
44
|
-
return { question: question.question, header: question.header, selected: [typed], freeform: true };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const label = resolveSelection(stripMark(choice), question.options);
|
|
48
|
-
if (!label) break;
|
|
49
|
-
|
|
50
|
-
if (!question.multiSelect) {
|
|
51
|
-
return { question: question.question, header: question.header, selected: [label], freeform: false };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const existing = selected.indexOf(label);
|
|
55
|
-
if (existing >= 0) selected.splice(existing, 1);
|
|
56
|
-
else selected.push(label);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return { question: question.question, header: question.header, selected, freeform: false };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
23
|
export default function askUserExtension(pi: ExtensionAPI) {
|
|
63
24
|
pi.registerTool({
|
|
64
25
|
name: "ask_user_question",
|
|
@@ -67,7 +28,7 @@ export default function askUserExtension(pi: ExtensionAPI) {
|
|
|
67
28
|
title: (a) => a?.questions?.[0]?.question,
|
|
68
29
|
}),
|
|
69
30
|
description:
|
|
70
|
-
"Ask the user to choose between options when you are blocked on a decision that is genuinely theirs — one you cannot resolve from the request, the code, or a sensible default. Ask up to four questions in one call;
|
|
31
|
+
"Ask the user to choose between options when you are blocked on a decision that is genuinely theirs — one you cannot resolve from the request, the code, or a sensible default. Ask up to four questions in one call; the user answers them in one tabbed dialog and can decline into a chat discussion instead. Options on single-select questions may carry a `preview` — an ASCII mockup, diagram, or code snippet rendered beside the list while the user compares choices; use previews when seeing the alternatives helps (UI layouts, code style variants), never for plain preference questions. Non-preview questions get a free-text 'Other' row automatically, so never add an 'Other' option yourself. If you recommend a specific option, make it the first in the list and end its label with '(Recommended)'. To switch into plan mode use enter_plan_mode (not this tool); once in plan mode, use this tool only to clarify requirements or choose between approaches before finalizing the plan. Do not use this tool for choices with an obvious default or for facts you can verify yourself.",
|
|
71
32
|
promptSnippet: "Ask the user to decide between options when genuinely blocked",
|
|
72
33
|
parameters: Type.Object({
|
|
73
34
|
questions: Type.Array(
|
|
@@ -81,6 +42,12 @@ export default function askUserExtension(pi: ExtensionAPI) {
|
|
|
81
42
|
Type.Object({
|
|
82
43
|
label: Type.String({ description: "Short choice text" }),
|
|
83
44
|
description: Type.Optional(Type.String({ description: "What choosing this means" })),
|
|
45
|
+
preview: Type.Optional(
|
|
46
|
+
Type.String({
|
|
47
|
+
description:
|
|
48
|
+
"Preview shown beside the options while this option is focused: an ASCII mockup, diagram, or code snippet that helps the user compare choices. Single-select questions only.",
|
|
49
|
+
}),
|
|
50
|
+
),
|
|
84
51
|
}),
|
|
85
52
|
{ minItems: 2, maxItems: 4 },
|
|
86
53
|
),
|
|
@@ -93,31 +60,58 @@ export default function askUserExtension(pi: ExtensionAPI) {
|
|
|
93
60
|
return { content: [{ type: "text", text: NON_INTERACTIVE }], details: {}, isError: true };
|
|
94
61
|
}
|
|
95
62
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
63
|
+
const questions = params.questions as Question[];
|
|
64
|
+
const outcome = await ctx.ui.custom<WidgetResult>((tui, theme, _keybindings, done) => {
|
|
65
|
+
const style = {
|
|
66
|
+
paint: safeThemePaint(theme),
|
|
67
|
+
bold: safeThemeBold(theme),
|
|
68
|
+
inverse: safeThemeInverse(theme),
|
|
69
|
+
};
|
|
70
|
+
const state = createWidgetState(questions);
|
|
71
|
+
// The output only changes on input or resize, but pi-tui calls
|
|
72
|
+
// render every frame — cache by width, drop the cache per keypress.
|
|
73
|
+
let cache: { width: number; lines: string[] } | undefined;
|
|
74
|
+
return {
|
|
75
|
+
render: (width: number) => {
|
|
76
|
+
if (cache?.width !== width) cache = { width, lines: renderWidget(state, style, width) };
|
|
77
|
+
return cache.lines;
|
|
78
|
+
},
|
|
79
|
+
handleInput: (data: string) => {
|
|
80
|
+
const key = decodeWidgetKey(data);
|
|
81
|
+
if (!key) return;
|
|
82
|
+
const resolved = applyWidgetKey(state, key);
|
|
83
|
+
if (resolved) return done(resolved);
|
|
84
|
+
cache = undefined;
|
|
85
|
+
tui.requestRender();
|
|
86
|
+
},
|
|
87
|
+
invalidate: () => {
|
|
88
|
+
cache = undefined;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (!outcome || outcome.kind === "cancel") {
|
|
94
|
+
const partial = outcome?.kind === "cancel" ? outcome.answers : [];
|
|
95
|
+
const text =
|
|
96
|
+
partial.length > 0
|
|
97
|
+
? `The user cancelled without submitting. They had made these selections before cancelling (NOT submitted — do not treat them as final answers):\n\n${formatAnswers(partial)}`
|
|
98
|
+
: "The user cancelled without answering.";
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text }],
|
|
101
|
+
details: { answers: partial, cancelled: true },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (outcome.kind === "chat") {
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: "text", text: formatDecline(questions) }],
|
|
108
|
+
details: { answers: [] as Answer[], declined: true },
|
|
109
|
+
};
|
|
116
110
|
}
|
|
117
111
|
|
|
118
112
|
return {
|
|
119
|
-
content: [{ type: "text", text: formatAnswers(answers) }],
|
|
120
|
-
details: { answers },
|
|
113
|
+
content: [{ type: "text", text: formatAnswers(outcome.answers) }],
|
|
114
|
+
details: { answers: outcome.answers },
|
|
121
115
|
};
|
|
122
116
|
},
|
|
123
117
|
});
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
export interface QuestionOption {
|
|
6
6
|
label: string;
|
|
7
7
|
description?: string;
|
|
8
|
+
/** Rendered beside the options while this option is focused (single-select only). */
|
|
9
|
+
preview?: string;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export interface Question {
|
|
@@ -20,33 +22,8 @@ export interface Answer {
|
|
|
20
22
|
selected: string[];
|
|
21
23
|
/** True when the user typed their own answer instead of picking. */
|
|
22
24
|
freeform: boolean;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export const OTHER_LABEL = "Other (type your own answer)";
|
|
26
|
-
export const DONE_LABEL = "Done selecting";
|
|
27
|
-
|
|
28
|
-
/** `label — description`, so the description is visible in a plain select list. */
|
|
29
|
-
export function formatOptionLabel(option: QuestionOption): string {
|
|
30
|
-
return option.description ? `${option.label} — ${option.description}` : option.label;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Maps a chosen display string back to the option label it came from. */
|
|
34
|
-
export function resolveSelection(display: string, options: QuestionOption[]): string | undefined {
|
|
35
|
-
return options.find((option) => formatOptionLabel(option) === display)?.label;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function buildChoices(question: Question, alreadySelected: string[] = []): string[] {
|
|
39
|
-
const marked = question.options.map((option) => {
|
|
40
|
-
const label = formatOptionLabel(option);
|
|
41
|
-
return question.multiSelect && alreadySelected.includes(option.label) ? `✓ ${label}` : label;
|
|
42
|
-
});
|
|
43
|
-
const extras = question.multiSelect ? [DONE_LABEL, OTHER_LABEL] : [OTHER_LABEL];
|
|
44
|
-
return [...marked, ...extras];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Strips the multi-select tick so the choice can be matched against options. */
|
|
48
|
-
export function stripMark(display: string): string {
|
|
49
|
-
return display.startsWith("✓ ") ? display.slice(2) : display;
|
|
25
|
+
/** Free-text notes the user attached to this answer. */
|
|
26
|
+
notes?: string;
|
|
50
27
|
}
|
|
51
28
|
|
|
52
29
|
export function formatAnswers(answers: Answer[]): string {
|
|
@@ -54,7 +31,17 @@ export function formatAnswers(answers: Answer[]): string {
|
|
|
54
31
|
return answers
|
|
55
32
|
.map((answer) => {
|
|
56
33
|
const value = answer.selected.length > 0 ? answer.selected.join(", ") : "(no answer)";
|
|
57
|
-
|
|
34
|
+
const typed = answer.freeform ? " (typed by the user)" : "";
|
|
35
|
+
const notes = answer.notes ? `\n→ notes: ${answer.notes}` : "";
|
|
36
|
+
return `${answer.question}\n→ ${value}${typed}${notes}`;
|
|
58
37
|
})
|
|
59
38
|
.join("\n\n");
|
|
60
39
|
}
|
|
40
|
+
|
|
41
|
+
/** Tool result when the user picks "Chat about this" instead of answering. */
|
|
42
|
+
export function formatDecline(questions: Question[]): string {
|
|
43
|
+
const list = questions
|
|
44
|
+
.map((q) => `· ${q.question} (${q.options.map((o) => o.label).join(" / ")})`)
|
|
45
|
+
.join("\n");
|
|
46
|
+
return `The user declined to answer and wants to chat about these questions instead:\n\n${list}\n\nAsk them in your reply what they'd like to clarify; don't call ask_user_question again until the discussion resolves it.`;
|
|
47
|
+
}
|