one-code-extension 0.4.1 → 0.5.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/README.md +16 -5
- package/agents/general-purpose.md +2 -2
- package/docs/guide/README.md +2 -1
- package/docs/guide/bring-your-claude-code-setup.md +60 -9
- package/docs/guide/configuration.md +48 -14
- package/docs/guide/differences-from-claude-code.md +32 -23
- package/docs/guide/doctor.md +20 -13
- package/docs/guide/hooks.md +18 -3
- package/docs/guide/installation.md +27 -4
- package/docs/guide/permissions-modes-and-auto-mode.md +225 -49
- package/docs/guide/providers-and-models.md +137 -54
- package/docs/guide/reference.md +27 -15
- package/docs/guide/sessions-and-context.md +69 -16
- package/docs/guide/skills-plugins-and-mcp.md +57 -20
- package/docs/guide/subagents-and-workflows.md +95 -29
- package/docs/guide/tasks-and-background-work.md +101 -26
- package/docs/guide/terminal-interface.md +24 -12
- package/docs/guide/tools.md +46 -5
- package/docs/guide/troubleshooting.md +13 -9
- package/docs/guide/windows.md +58 -31
- package/extensions/artifacts/gallery.ts +227 -0
- package/extensions/artifacts/index.ts +288 -0
- package/extensions/artifacts/store.ts +570 -0
- package/extensions/artifacts/viewer.ts +199 -0
- package/extensions/ask-user/description.ts +67 -0
- package/extensions/ask-user/dialogs.ts +80 -0
- package/extensions/ask-user/index.ts +37 -33
- package/extensions/ask-user/questions.ts +32 -7
- package/extensions/ask-user/widget.ts +45 -25
- package/extensions/auto-mode/actions.ts +6 -0
- package/extensions/auto-mode/cache.ts +88 -0
- package/extensions/auto-mode/classifier-prompt.ts +5 -4
- package/extensions/auto-mode/classifier.ts +290 -65
- package/extensions/auto-mode/config.ts +72 -20
- package/extensions/auto-mode/decision-log.ts +2 -0
- package/extensions/auto-mode/defaults.ts +1 -1
- package/extensions/auto-mode/denials.ts +123 -0
- package/extensions/auto-mode/git-checkout-programs.ts +187 -0
- package/extensions/auto-mode/git-status-meta.ts +159 -0
- package/extensions/auto-mode/history.ts +189 -0
- package/extensions/auto-mode/instructions.ts +58 -52
- package/extensions/auto-mode/model-select.ts +159 -134
- package/extensions/auto-mode/paths.ts +57 -5
- package/extensions/auto-mode/pause.ts +57 -2
- package/extensions/auto-mode/prompt.ts +37 -21
- package/extensions/auto-mode/read-only-options.ts +724 -0
- package/extensions/auto-mode/resolved-paths-meta.ts +133 -0
- package/extensions/auto-mode/rules.ts +18 -1
- package/extensions/auto-mode/safety-floor.ts +361 -18
- package/extensions/auto-mode/setup-run.ts +20 -14
- package/extensions/auto-mode/shell-analysis.ts +764 -490
- package/extensions/auto-mode/shell-parse.ts +885 -0
- package/extensions/auto-mode/system-note.ts +33 -0
- package/extensions/auto-mode/transcript.ts +80 -51
- package/extensions/background/cron.ts +515 -0
- package/extensions/background/index.ts +514 -236
- package/extensions/background/loop-fire.ts +136 -0
- package/extensions/background/loop-preamble.ts +59 -0
- package/extensions/background/loop-skill.ts +163 -0
- package/extensions/background/monitor-batch.ts +53 -0
- package/extensions/background/noop-fold.ts +128 -0
- package/extensions/background/switch-guard.ts +52 -0
- package/extensions/background/wakeup.ts +159 -55
- package/extensions/bash/background.ts +53 -17
- package/extensions/bash/child.ts +7 -0
- package/extensions/bash/description.ts +188 -0
- package/extensions/bash/guards.ts +15 -67
- package/extensions/bash/index.ts +88 -35
- package/extensions/branding/compaction-keep.ts +63 -0
- package/extensions/branding/declined.ts +22 -0
- package/extensions/branding/index.ts +133 -9
- package/extensions/branding/prompt-editor.ts +53 -6
- package/extensions/branding/queued-edit.ts +31 -0
- package/extensions/branding/replaced-builtins.ts +68 -0
- package/extensions/branding/startup.ts +33 -71
- package/extensions/btw/index.ts +229 -71
- package/extensions/btw/panel.ts +228 -100
- package/extensions/btw/prompt.ts +41 -4
- package/extensions/claude-compat/index.ts +7 -11
- package/extensions/claude-context/index.ts +446 -58
- package/extensions/compaction/cut.ts +157 -0
- package/extensions/compaction/index.ts +216 -75
- package/extensions/compaction/kept-thinking.ts +62 -0
- package/extensions/compaction/prompt.ts +15 -12
- package/extensions/context-budget/index.ts +24 -5
- package/extensions/context-management/index.ts +25 -0
- package/extensions/doctor/build.ts +59 -8
- package/extensions/doctor/builtins.ts +84 -0
- package/extensions/doctor/cli.ts +7 -1
- package/extensions/doctor/compat.ts +88 -23
- package/extensions/doctor/dependencies.ts +41 -5
- package/extensions/doctor/fix-prompt.ts +9 -2
- package/extensions/doctor/index.ts +102 -58
- package/extensions/doctor/models.ts +102 -63
- package/extensions/doctor/presets.ts +42 -27
- package/extensions/doctor/report.ts +19 -2
- package/extensions/doctor/viewer.ts +49 -27
- package/extensions/effort/index.ts +72 -19
- package/extensions/effort/settings.ts +21 -0
- package/extensions/effort/slider.ts +24 -20
- package/extensions/exit/index.ts +32 -1
- package/extensions/file-tracker/index.ts +337 -26
- package/extensions/file-tracker/replay.ts +96 -10
- package/extensions/file-tracker/restore.ts +63 -0
- package/extensions/file-tracker/results.ts +66 -0
- package/extensions/file-tracker/shell-reads.ts +211 -0
- package/extensions/file-tracker/tracker.ts +32 -15
- package/extensions/footer/footer-line.ts +45 -24
- package/extensions/footer/index.ts +47 -2
- package/extensions/footer/pr.ts +34 -5
- package/extensions/hooks/compaction.ts +7 -0
- package/extensions/hooks/executor.ts +32 -30
- package/extensions/hooks/index.ts +198 -31
- package/extensions/hooks/matcher.ts +3 -0
- package/extensions/hooks/protocol.ts +41 -3
- package/extensions/hooks/settings.ts +50 -19
- package/extensions/hooks/subagent-bridge.ts +2 -0
- package/extensions/hooks/trust.ts +13 -5
- package/extensions/idle-compact/index.ts +119 -0
- package/extensions/idle-compact/policy.ts +143 -0
- package/extensions/init/index.ts +11 -10
- package/extensions/init/prompt.ts +25 -32
- package/extensions/interrupted/index.ts +13 -1
- package/extensions/kept-thinking/index.ts +27 -0
- package/extensions/lib/agent-cron.ts +130 -0
- package/extensions/lib/agent-loader.ts +15 -1
- package/extensions/lib/agent-view.ts +85 -0
- package/extensions/lib/anthropic-payload.ts +82 -1
- package/extensions/lib/anthropic-server-call.ts +230 -0
- package/extensions/lib/anthropic-server-tools.ts +485 -0
- package/extensions/lib/app-launch.mjs +94 -0
- package/extensions/lib/argument-hints.ts +190 -0
- package/extensions/lib/atomic-write.ts +6 -2
- package/extensions/lib/auto-memory.ts +75 -0
- package/extensions/lib/bash-parser.ts +84 -0
- package/extensions/lib/btw-fork.ts +93 -0
- package/extensions/lib/child-extensions.ts +42 -0
- package/extensions/lib/child-writes.ts +45 -0
- package/extensions/lib/claude-context.ts +515 -100
- package/extensions/lib/claude-external-includes.ts +68 -0
- package/extensions/lib/claude-id.ts +22 -0
- package/extensions/lib/claude-rules.ts +323 -0
- package/extensions/lib/claude-settings.ts +76 -4
- package/extensions/lib/compaction-boundary.ts +36 -0
- package/extensions/lib/compaction-keep.mjs +83 -0
- package/extensions/lib/config-mode.ts +112 -0
- package/extensions/lib/consent-dialogs.ts +63 -0
- package/extensions/lib/consent-preview.ts +5 -1
- package/extensions/lib/consent-stores.ts +48 -0
- package/extensions/lib/context-facts.ts +78 -0
- package/extensions/lib/context-stack.ts +81 -0
- package/extensions/lib/deferred.ts +219 -25
- package/extensions/lib/dock-rows.ts +60 -0
- package/extensions/lib/empty-tool-result.ts +27 -0
- package/extensions/lib/environment-block.ts +76 -0
- package/extensions/lib/fetch-timeout.ts +24 -6
- package/extensions/{system-prompt → lib}/git-status.ts +51 -13
- package/extensions/lib/git.ts +75 -13
- package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
- package/extensions/lib/grammars/README.md +2 -0
- package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
- package/extensions/lib/guide-docs.ts +45 -0
- package/extensions/lib/headless-output.ts +46 -0
- package/extensions/lib/hook-gate.ts +7 -7
- package/extensions/lib/interrupt.ts +20 -4
- package/extensions/lib/key-input.ts +455 -0
- package/extensions/lib/keys.ts +14 -1
- package/extensions/lib/local-command.ts +47 -13
- package/extensions/lib/mcp-overrides.ts +1 -1
- package/extensions/lib/mcp-share.ts +46 -0
- package/extensions/lib/memory-content.ts +146 -0
- package/extensions/lib/memory-index.ts +18 -0
- package/extensions/lib/memory.ts +134 -123
- package/extensions/lib/model-catalog/huggingface.json +174 -0
- package/extensions/lib/model-catalog/models-dev.json +18297 -0
- package/extensions/lib/model-catalog/openrouter.json +5252 -0
- package/extensions/lib/model-catalog-data.ts +513 -0
- package/extensions/lib/model-catalog.ts +462 -0
- package/extensions/lib/model-choice-warnings.ts +137 -0
- package/extensions/lib/model-pairings.ts +152 -0
- package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
- package/extensions/lib/model-policy.ts +112 -15
- package/extensions/lib/model-tier.ts +283 -355
- package/extensions/lib/model-unusable.ts +1 -1
- package/extensions/lib/newer-model.ts +100 -0
- package/extensions/lib/notices.ts +87 -0
- package/extensions/lib/notifications.ts +308 -64
- package/extensions/lib/one-code-settings.ts +74 -8
- package/extensions/lib/open-browser.ts +63 -0
- package/extensions/lib/openrouter-generation.ts +94 -0
- package/extensions/lib/operation-deadline.ts +30 -0
- package/extensions/lib/original-command.ts +4 -4
- package/extensions/lib/package-version.ts +1 -1
- package/extensions/lib/panel-focus.ts +134 -0
- package/extensions/lib/paths.ts +17 -2
- package/extensions/lib/permission-gate.ts +72 -6
- package/extensions/lib/persisted-output.ts +60 -8
- package/extensions/lib/pi-ai-estimate.ts +19 -3
- package/extensions/lib/pi-version.ts +21 -2
- package/extensions/lib/plan-mode-channels.ts +20 -5
- package/extensions/lib/plugins.ts +26 -17
- package/extensions/lib/powershell-parse-script.ts +208 -0
- package/extensions/lib/powershell-parser.ts +344 -0
- package/extensions/lib/process-tree.ts +131 -8
- package/extensions/lib/prompt-options.ts +82 -0
- package/extensions/lib/queued-delivery.ts +44 -0
- package/extensions/lib/reminders.ts +364 -58
- package/extensions/lib/replaced-builtins.mjs +199 -0
- package/extensions/lib/replay-call.ts +70 -0
- package/extensions/lib/request-replay.ts +439 -0
- package/extensions/lib/scratchpad.ts +81 -14
- package/extensions/lib/send-now-channel.ts +7 -0
- package/extensions/lib/session-model-tier.ts +51 -0
- package/extensions/lib/session-work.ts +64 -0
- package/extensions/lib/settings-channels.ts +4 -4
- package/extensions/lib/shell-exit-semantics.ts +170 -0
- package/extensions/lib/shell-quote.ts +11 -0
- package/extensions/lib/shell-result.ts +70 -0
- package/extensions/lib/shell-spawn.ts +70 -6
- package/extensions/lib/shell-tool.ts +75 -25
- package/extensions/lib/side-call-cache.ts +124 -0
- package/extensions/lib/side-call-run.ts +96 -0
- package/extensions/lib/side-call-usage.ts +38 -0
- package/extensions/lib/side-call.ts +13 -1
- package/extensions/lib/single-flight.ts +18 -0
- package/extensions/lib/skill-body.ts +42 -0
- package/extensions/lib/skill-scan.ts +63 -24
- package/extensions/lib/spill-file.ts +140 -0
- package/extensions/lib/subagent-handback.ts +113 -0
- package/extensions/lib/system-role.ts +156 -0
- package/extensions/lib/terminal-text.ts +114 -0
- package/extensions/lib/text-width.ts +47 -16
- package/extensions/lib/timer-ops.ts +20 -0
- package/extensions/lib/tool-additions.ts +149 -0
- package/extensions/lib/tool-call-corruption.ts +134 -0
- package/extensions/lib/tool-path.ts +66 -0
- package/extensions/lib/tool-variants.ts +69 -0
- package/extensions/lib/tui-render.ts +255 -27
- package/extensions/lib/turn-budget-layout.ts +143 -0
- package/extensions/lib/update-check.mjs +15 -2
- package/extensions/lib/usage-bus.ts +1 -1
- package/extensions/lib/user-denial.ts +38 -0
- package/extensions/lib/workspace-channel.ts +16 -0
- package/extensions/lib/worktree-channel.ts +31 -3
- package/extensions/lib/worktree-isolation.ts +40 -10
- package/extensions/lsp/client.ts +8 -9
- package/extensions/lsp/index.ts +70 -4
- package/extensions/lsp/keep-alive.ts +1 -1
- package/extensions/lsp/trust.ts +119 -0
- package/extensions/lsp/watcher.ts +1 -1
- package/extensions/mcp/announce.ts +87 -5
- package/extensions/mcp/client.ts +161 -48
- package/extensions/mcp/config.ts +132 -8
- package/extensions/mcp/discovery.ts +19 -0
- package/extensions/mcp/index.ts +209 -71
- package/extensions/mcp/oauth/browser.ts +38 -17
- package/extensions/mcp/oauth/flow.ts +25 -17
- package/extensions/mcp/oauth/provider.ts +14 -8
- package/extensions/mcp/oauth/store.ts +34 -16
- package/extensions/mcp/panel/keys.ts +12 -11
- package/extensions/mcp/panel/render.ts +9 -6
- package/extensions/mcp/schema.ts +104 -5
- package/extensions/mcp/trust.ts +151 -67
- package/extensions/memory/entries.ts +23 -14
- package/extensions/memory/index.ts +134 -28
- package/extensions/memory/open-external.ts +33 -18
- package/extensions/memory/panel.ts +135 -26
- package/extensions/newer-model/index.ts +31 -0
- package/extensions/notebook/description.ts +18 -0
- package/extensions/notebook/index.ts +6 -5
- package/extensions/notebook/notebook.ts +1 -1
- package/extensions/permissions/index.ts +1300 -381
- package/extensions/permissions/matcher.ts +425 -74
- package/extensions/permissions/modes.ts +6 -4
- package/extensions/permissions/panel/host.ts +130 -0
- package/extensions/permissions/panel/keys.ts +48 -0
- package/extensions/permissions/panel/render.ts +450 -0
- package/extensions/permissions/panel/state.ts +550 -0
- package/extensions/permissions/powershell-cmdlets.ts +198 -0
- package/extensions/permissions/powershell-paths.ts +197 -0
- package/extensions/permissions/powershell-rules.ts +207 -280
- package/extensions/permissions/powershell-tree.ts +557 -0
- package/extensions/permissions/project-trust.ts +27 -11
- package/extensions/permissions/protected-paths.ts +14 -2
- package/extensions/permissions/session-grant.ts +6 -0
- package/extensions/permissions/settings.ts +166 -31
- package/extensions/permissions/subagent-gate.ts +25 -0
- package/extensions/permissions/workspace.ts +78 -0
- package/extensions/plan-mode/index.ts +156 -69
- package/extensions/plan-mode/reminder.ts +89 -21
- package/extensions/plan-mode/texts.ts +177 -0
- package/extensions/plan-mode/viewer.ts +92 -27
- package/extensions/plugins/counts.ts +3 -3
- package/extensions/plugins/index.ts +61 -46
- package/extensions/plugins/install/install.ts +16 -0
- package/extensions/plugins/marketplace/sync.ts +9 -3
- package/extensions/plugins/marketplace/types.ts +3 -1
- package/extensions/plugins/panel/keys.ts +21 -24
- package/extensions/plugins/panel/render.ts +12 -6
- package/extensions/plugins/shell-expand.ts +107 -0
- package/extensions/plugins/template.ts +32 -15
- package/extensions/powershell/child.ts +7 -0
- package/extensions/powershell/description.ts +38 -6
- package/extensions/powershell/guards.ts +1 -1
- package/extensions/powershell/index.ts +12 -7
- package/extensions/recap/index.ts +65 -60
- package/extensions/recap/prompt.ts +2 -2
- package/extensions/recap/scheduler.ts +3 -5
- package/extensions/search-tools/grep-merge.ts +39 -0
- package/extensions/search-tools/index.ts +0 -0
- package/extensions/send-now/chord.ts +62 -0
- package/extensions/send-now/index.ts +133 -0
- package/extensions/session-title/index.ts +3 -0
- package/extensions/session-title/title.ts +4 -1
- package/extensions/skill/code-review.ts +97 -0
- package/extensions/skill/index.ts +421 -101
- package/extensions/skill/invoke.ts +128 -18
- package/extensions/skill/listing.ts +133 -9
- package/extensions/skill/panel/keys.ts +15 -16
- package/extensions/skill/panel/render.ts +5 -2
- package/extensions/skill/panel/state.ts +12 -1
- package/extensions/subagents/agent-args.ts +39 -0
- package/extensions/subagents/agent-description.ts +132 -0
- package/extensions/subagents/agents.ts +116 -23
- package/extensions/subagents/announce.ts +69 -0
- package/extensions/subagents/default-model.ts +2 -3
- package/extensions/subagents/delegation-steer.ts +4 -4
- package/extensions/subagents/fork-cache.ts +76 -0
- package/extensions/subagents/guide-agent.ts +189 -0
- package/extensions/subagents/hand-back-review.ts +3 -0
- package/extensions/subagents/index.ts +1493 -824
- package/extensions/subagents/live-runs.ts +26 -6
- package/extensions/subagents/model-select.ts +38 -25
- package/extensions/subagents/outcome.ts +2 -2
- package/extensions/subagents/panel-keys.ts +73 -31
- package/extensions/subagents/panel-render.ts +120 -96
- package/extensions/subagents/panel-widget.ts +60 -89
- package/extensions/subagents/runner.ts +108 -80
- package/extensions/subagents/runs.ts +39 -5
- package/extensions/subagents/send-to-main-tool.ts +1 -1
- package/extensions/subagents/session-turns.ts +32 -8
- package/extensions/subagents/shell-panel.ts +36 -178
- package/extensions/subagents/tasks-dialog.ts +170 -0
- package/extensions/subagents/viewport-mirror.ts +95 -0
- package/extensions/subagents/worktree.ts +57 -13
- package/extensions/system-prompt/environment.ts +19 -19
- package/extensions/system-prompt/idle-turn.ts +65 -0
- package/extensions/system-prompt/index.ts +131 -47
- package/extensions/system-prompt/template.ts +24 -50
- package/extensions/system-prompt/tiers/common.ts +23 -64
- package/extensions/system-prompt/tiers/frontier.ts +32 -11
- package/extensions/system-prompt/tiers/low.ts +67 -45
- package/extensions/system-prompt/tiers/mid.ts +96 -38
- package/extensions/system-reminder/index.ts +175 -13
- package/extensions/tasks/descriptions.ts +190 -0
- package/extensions/tasks/index.ts +120 -41
- package/extensions/tasks/store.ts +83 -16
- package/extensions/tool-call-corruption/child.ts +7 -0
- package/extensions/tool-call-corruption/index.ts +237 -0
- package/extensions/tool-search/announce.ts +16 -0
- package/extensions/tool-search/index.ts +189 -41
- package/extensions/tool-style/index.ts +68 -10
- package/extensions/tool-style/write-description.ts +40 -0
- package/extensions/tool-style/write-render.ts +237 -0
- package/extensions/turn-duration/index.ts +7 -3
- package/extensions/turn-duration/line.ts +47 -4
- package/extensions/web/backends.ts +6 -9
- package/extensions/web/description.ts +50 -0
- package/extensions/web/index.ts +118 -53
- package/extensions/web/native-call.ts +15 -0
- package/extensions/web/native-results.ts +41 -0
- package/extensions/web-fetch/description.ts +42 -0
- package/extensions/web-fetch/extract.ts +53 -6
- package/extensions/web-fetch/index.ts +125 -76
- package/extensions/web-fetch/page-content.ts +19 -0
- package/extensions/web-fetch/response.ts +49 -0
- package/extensions/web-fetch/summarize.ts +9 -10
- package/extensions/workflow/agent-session.ts +105 -18
- package/extensions/workflow/args.ts +24 -0
- package/extensions/workflow/description.ts +67 -0
- package/extensions/workflow/globals.ts +17 -3
- package/extensions/workflow/index.ts +145 -162
- package/extensions/workflow/records.ts +1 -0
- package/extensions/workflow/run-manager.ts +29 -6
- package/extensions/workflow/saved-workflows.ts +3 -2
- package/extensions/workflow/types.ts +22 -1
- package/extensions/workflow/viewer.ts +54 -24
- package/extensions/workflow/widget.ts +20 -0
- package/extensions/worktree/descriptions.ts +91 -0
- package/extensions/worktree/guards.ts +316 -54
- package/extensions/worktree/index.ts +121 -39
- package/extensions/worktree/powershell-guards.ts +167 -0
- package/extensions/worktree/rewrite.ts +14 -16
- package/package.json +18 -7
- package/skills/artifact-design/SKILL.md +85 -0
- package/skills/code-review/SKILL.md +20 -20
- package/skills/code-review/cells/arguments-and-flags.md +19 -0
- package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
- package/skills/code-review/cells/high-8-inline.md +122 -0
- package/skills/code-review/cells/low-1-pass-max4.md +27 -0
- package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
- package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
- package/skills/code-review/cells/medium-3x5-verify.md +132 -0
- package/skills/code-review/cells/minimal-prompt.md +32 -0
- package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
- package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
- package/skills/fewer-permission-prompts/SKILL.md +1 -1
- package/skills/loop/SKILL.md +11 -0
- package/skills/security-review/SKILL.md +2 -5
- package/skills/simplify/SKILL.md +7 -5
- package/skills/workflow-authoring/SKILL.md +143 -0
- package/themes/onecode-light.json +1 -1
- package/themes/onecode.json +1 -1
- package/types/app.d.ts +58 -0
- package/types/community-packages.d.ts +26 -1
- package/extensions/auto-mode/recoverability.ts +0 -229
- package/extensions/lib/capability-index.ts +0 -466
- package/extensions/lib/model-facts.generated.json +0 -2675
- package/extensions/lib/model-facts.ts +0 -162
|
@@ -4,23 +4,30 @@
|
|
|
4
4
|
* The doctor does not re-decide anything: it calls the SAME resolvers the
|
|
5
5
|
* session uses — `resolveSubagentModel` for delegated work, `classifierCandidates`
|
|
6
6
|
* for auto mode's screener, `pickEconomicalContainedModel` for the web-fetch /
|
|
7
|
-
* recap reader
|
|
8
|
-
*
|
|
9
|
-
* Haiku?" gets the resolver's
|
|
7
|
+
* recap reader — and reports their answers next to their sources. The prompt
|
|
8
|
+
* register comes from the session's frozen tier, or `resolveModelTier` in the
|
|
9
|
+
* CLI. A user who asks "why did my subagent run on Haiku?" gets the resolver's
|
|
10
|
+
* own notice, not a paraphrase.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
13
14
|
import { modeCycleKey } from "../lib/keys.ts";
|
|
14
15
|
import { loadAutoModeConfig } from "../auto-mode/config.ts";
|
|
15
16
|
import { classifierCandidates, describeCandidate, type ClassifierNotice } from "../auto-mode/model-select.ts";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
17
|
+
import { chosenModelWarnings, type ChosenModelWarning } from "../lib/model-choice-warnings.ts";
|
|
18
|
+
import { loadCatalogSources, readCatalogRefreshEnabled } from "../lib/model-catalog-data.ts";
|
|
19
|
+
import { autoSelectSkipReason, catalogModelFor } from "../lib/model-catalog.ts";
|
|
20
|
+
import { DAY_MS, modelsContainedToSession, modelSpec, pricedInput, supportsImageInput } from "../lib/model-policy.ts";
|
|
21
|
+
import { newerModelSuggestion, type NewerModelSuggestion } from "../lib/newer-model.ts";
|
|
22
|
+
import { oneCodeSettingsPath, readSuggestNewerModels } from "../lib/one-code-settings.ts";
|
|
23
|
+
import { oneCodeStateDir } from "../lib/paths.ts";
|
|
18
24
|
import {
|
|
19
|
-
|
|
25
|
+
classifyModelTier,
|
|
20
26
|
intrinsicTier,
|
|
21
27
|
pickEconomicalContainedModel,
|
|
22
28
|
type PromptTier,
|
|
23
29
|
resolveModelTier,
|
|
30
|
+
servedCatalogIds,
|
|
24
31
|
tierOverride,
|
|
25
32
|
} from "../lib/model-tier.ts";
|
|
26
33
|
import { applicableSubagentDefault, loadSubagentDefault, type SubagentDefault } from "../subagents/default-model.ts";
|
|
@@ -30,6 +37,7 @@ import { contextLabel, type Finding, priceLabel, type ReportLine, type ReportSec
|
|
|
30
37
|
export interface ModelFacts {
|
|
31
38
|
session?: Model<Api>;
|
|
32
39
|
sessionTier?: PromptTier;
|
|
40
|
+
newerModel?: NewerModelSuggestion;
|
|
33
41
|
/** The register the system prompt is built in — the tier, or a CC_PROMPT_TIER override. */
|
|
34
42
|
promptTier: PromptTier;
|
|
35
43
|
promptTierForced: boolean;
|
|
@@ -37,20 +45,18 @@ export interface ModelFacts {
|
|
|
37
45
|
subagentConfigured?: SubagentDefault;
|
|
38
46
|
/** The configured default exists but does not apply to this session (Claude Code's env var on a non-Claude model). */
|
|
39
47
|
subagentConfiguredInapplicable: boolean;
|
|
48
|
+
/** What the configured subagent default costs (newer model, far weaker than the session), when it is in effect. */
|
|
49
|
+
subagentWarnings: ChosenModelWarning[];
|
|
50
|
+
/** `configured`: the user's `autoMode.classifierModel`, as written. */
|
|
40
51
|
classifier: { model?: Model<Api>; description?: string; notices: ClassifierNotice[]; configured?: string };
|
|
41
52
|
reader?: { model: Model<Api>; via: "tier" | "session" };
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
snapshot?: { fetchedAt: string; rows: number };
|
|
50
|
-
subagent?: FloorVerdict;
|
|
51
|
-
classifier?: FloorVerdict;
|
|
52
|
-
reader?: FloorVerdict;
|
|
53
|
-
};
|
|
53
|
+
/** The session model's own tier and the rule that decided it (`classifyModelTier`, no CC_PROMPT_TIER). */
|
|
54
|
+
tierReason?: string;
|
|
55
|
+
/** Whether the public model catalogs know the session model, and why automatic picks skip it, if they do. */
|
|
56
|
+
inCatalog: boolean;
|
|
57
|
+
skipReason?: string;
|
|
58
|
+
/** The model catalogs in use (lib/model-catalog-data.ts). */
|
|
59
|
+
catalog: { fetchedAt: string; refreshed: boolean; refreshEnabled: boolean };
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
export const TIER_LABEL: Record<PromptTier, string> = {
|
|
@@ -64,35 +70,42 @@ export function collectModelFacts(available: Model<Api>[], session: SessionView,
|
|
|
64
70
|
const sessionModel = session.model;
|
|
65
71
|
const configuredAll = loadSubagentDefault(home, env);
|
|
66
72
|
const configured = applicableSubagentDefault(configuredAll, sessionModel);
|
|
67
|
-
|
|
73
|
+
// The live resolver's image gate (subagents/index.ts), so the preview names what a spawn gets.
|
|
74
|
+
const subagent = resolveSubagentModel({ configuredDefault: configured, sessionModel, available, requireImageInput: supportsImageInput(sessionModel) });
|
|
75
|
+
const suggestNewer = readSuggestNewerModels(home, env);
|
|
68
76
|
const autoConfig = loadAutoModeConfig(home);
|
|
69
77
|
const chain = classifierCandidates({
|
|
70
78
|
available,
|
|
71
79
|
sessionModel,
|
|
72
80
|
configured: autoConfig.classifierModel,
|
|
73
81
|
configuredSetForContainment: autoConfig.classifierModelSetFor,
|
|
82
|
+
suggestNewer,
|
|
74
83
|
});
|
|
75
84
|
const first = chain.candidates[0];
|
|
76
85
|
const reader = pickEconomicalContainedModel(available, sessionModel);
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
snapshot && sessionModel && pick && modelSpec(pick) !== modelSpec(sessionModel) ? capabilityFloor(snapshot, pick, sessionModel, role) : undefined;
|
|
80
|
-
const capability: ModelFacts["capability"] = {
|
|
81
|
-
keyConfigured: configuredCapabilityKey(home, env) !== undefined,
|
|
82
|
-
snapshot: snapshot ? { fetchedAt: snapshot.fetchedAt, rows: snapshot.rows.length } : undefined,
|
|
83
|
-
subagent: verdict(subagent.source === "automatic" ? subagent.model : undefined, "subagent"),
|
|
84
|
-
classifier: verdict(first?.source === "economical" ? first.model : undefined, "classifier"),
|
|
85
|
-
reader: verdict(reader?.via === "tier" ? reader.model : undefined, "reader"),
|
|
86
|
-
};
|
|
86
|
+
const sources = loadCatalogSources(oneCodeStateDir(env, home));
|
|
87
|
+
const entry = sessionModel ? catalogModelFor(sessionModel) : undefined;
|
|
87
88
|
return {
|
|
88
|
-
|
|
89
|
+
catalog: {
|
|
90
|
+
fetchedAt: sources.modelsDev.fetchedAt,
|
|
91
|
+
refreshed: sources.refreshed === true,
|
|
92
|
+
refreshEnabled: readCatalogRefreshEnabled(oneCodeSettingsPath(home, env), env),
|
|
93
|
+
},
|
|
94
|
+
tierReason: sessionModel ? classifyModelTier(sessionModel, {}, "capability").reason : undefined,
|
|
95
|
+
inCatalog: entry !== undefined,
|
|
96
|
+
skipReason: entry && sessionModel ? autoSelectSkipReason(entry, servedCatalogIds(modelsContainedToSession(available, sessionModel))) : undefined,
|
|
97
|
+
newerModel: suggestNewer ? newerModelSuggestion(available, sessionModel) : undefined,
|
|
89
98
|
session: sessionModel,
|
|
90
99
|
sessionTier: sessionModel ? intrinsicTier(sessionModel) : undefined,
|
|
91
|
-
promptTier: resolveModelTier(sessionModel, env),
|
|
100
|
+
promptTier: session.promptTier ?? resolveModelTier(sessionModel, env),
|
|
92
101
|
promptTierForced: tierOverride(env) !== undefined,
|
|
93
102
|
subagent,
|
|
94
103
|
subagentConfigured: configuredAll,
|
|
95
104
|
subagentConfiguredInapplicable: configuredAll !== undefined && configured === undefined,
|
|
105
|
+
subagentWarnings:
|
|
106
|
+
subagent.source === "default" && subagent.model
|
|
107
|
+
? chosenModelWarnings({ available, sessionModel, chosen: subagent.model, role: "subagent", suggestNewer })
|
|
108
|
+
: [],
|
|
96
109
|
classifier: {
|
|
97
110
|
model: first?.model,
|
|
98
111
|
description: first ? describeCandidate(first) : undefined,
|
|
@@ -107,8 +120,8 @@ const SUBAGENT_SOURCE: Record<SubagentModelResolution["source"], string> = {
|
|
|
107
120
|
call: "named per call",
|
|
108
121
|
agent: "from the agent file",
|
|
109
122
|
default: "the configured default",
|
|
110
|
-
automatic: "automatic: cheapest
|
|
111
|
-
session: "the main model — nothing cheaper
|
|
123
|
+
automatic: "automatic: cheapest model on this provider in the main model's tier or above, cheaper than it",
|
|
124
|
+
session: "the main model — nothing cheaper on this provider in its tier or above",
|
|
112
125
|
};
|
|
113
126
|
|
|
114
127
|
export function modelsSection(facts: ModelFacts, session: SessionView, findings: Finding[]): ReportSection {
|
|
@@ -133,11 +146,25 @@ export function modelsSection(facts: ModelFacts, session: SessionView, findings:
|
|
|
133
146
|
: "";
|
|
134
147
|
const details = [priceLabel(main), contextLabel(main.contextWindow), sourceNote].filter(Boolean).join(" · ");
|
|
135
148
|
lines.push({ text: `Main: ${modelSpec(main)} — ${details}`, level: "ok" });
|
|
149
|
+
if (facts.newerModel) {
|
|
150
|
+
findings.push({ level: "warn", text: facts.newerModel.text, fix: facts.newerModel.fix });
|
|
151
|
+
}
|
|
136
152
|
lines.push({
|
|
137
153
|
text: `Prompt register: ${TIER_LABEL[facts.promptTier]}${facts.promptTierForced ? " (forced by CC_PROMPT_TIER)" : ""}`,
|
|
138
154
|
indent: 1,
|
|
139
155
|
level: "dim",
|
|
140
156
|
});
|
|
157
|
+
if (facts.sessionTier && facts.tierReason) {
|
|
158
|
+
lines.push({ text: `Tier: ${facts.sessionTier} — ${facts.tierReason}`, indent: 1, level: "dim" });
|
|
159
|
+
}
|
|
160
|
+
if (facts.skipReason) lines.push({ text: `Automatic picks skip this model: ${facts.skipReason}`, indent: 1, level: "dim" });
|
|
161
|
+
if (!facts.inCatalog && facts.tierReason !== "modelTiers setting" && facts.sessionTier !== "frontier") {
|
|
162
|
+
findings.push({
|
|
163
|
+
level: "warn",
|
|
164
|
+
text: `${modelSpec(main)} is not in the public model catalogs (models.dev, OpenRouter), so its tier is a guess (${facts.sessionTier}) and automatic picks never choose it.`,
|
|
165
|
+
fix: `Set its tier in ~/.onecode/settings.json: { "modelTiers": { "${modelSpec(main)}": "workhorse" } } (frontier, workhorse, cheap or tiny).`,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
141
168
|
if (session.thinkingLevel) lines.push({ text: `Effort: ${session.thinkingLevel} (/effort or shift+tab to change)`, indent: 1, level: "dim" });
|
|
142
169
|
|
|
143
170
|
const sub = facts.subagent;
|
|
@@ -150,11 +177,23 @@ export function modelsSection(facts: ModelFacts, session: SessionView, findings:
|
|
|
150
177
|
indent: 1,
|
|
151
178
|
level: facts.subagentConfiguredInapplicable ? "warn" : "dim",
|
|
152
179
|
});
|
|
180
|
+
// A warning line is a finding too, so the summary never says "No issues found" beside it.
|
|
181
|
+
if (facts.subagentConfiguredInapplicable) {
|
|
182
|
+
findings.push({
|
|
183
|
+
level: "warn",
|
|
184
|
+
text: `${knob} sets "${facts.subagentConfigured.spec}" for subagents, but it applies only when the main model is a Claude model, so it is not used here.`,
|
|
185
|
+
fix: "Choose the subagent model with /subagent (it writes subagentModel in ~/.onecode/settings.json), or unset the variable.",
|
|
186
|
+
});
|
|
187
|
+
}
|
|
153
188
|
}
|
|
154
189
|
for (const notice of sub.notices) {
|
|
155
190
|
lines.push({ text: notice, indent: 1, level: "warn" });
|
|
156
191
|
findings.push({ level: "warn", text: `Subagent model: ${notice}`, fix: "Re-set the default with /subagent on this session, or /subagent clear." });
|
|
157
192
|
}
|
|
193
|
+
for (const warning of facts.subagentWarnings) {
|
|
194
|
+
lines.push({ text: warning.text, indent: 1, level: "warn" });
|
|
195
|
+
findings.push({ level: "warn", text: warning.text, fix: warning.fix });
|
|
196
|
+
}
|
|
158
197
|
} else {
|
|
159
198
|
lines.push({ text: "Subagents: no model resolves", level: "error" });
|
|
160
199
|
}
|
|
@@ -164,50 +203,50 @@ export function modelsSection(facts: ModelFacts, session: SessionView, findings:
|
|
|
164
203
|
const live = session.permission?.classifier;
|
|
165
204
|
const pinned = session.permission?.pinned && live ? ` — screening this session on ${live}` : "";
|
|
166
205
|
lines.push({ text: `Auto-mode classifier: ${classifier.description ?? modelSpec(classifier.model)}${pinned}`, level: "ok" });
|
|
206
|
+
if (classifier.configured) {
|
|
207
|
+
lines.push({ text: `Setting: "${classifier.configured}" via autoMode.classifierModel in ~/.onecode/settings.json (/auto-mode model clear returns to automatic)`, indent: 1, level: "dim" });
|
|
208
|
+
}
|
|
209
|
+
lines.push({
|
|
210
|
+
text: "Classifier policy: for the models One Code's pairing table names, the table's pick on this provider (or this session's model), unless it costs more than this session's model or its window is smaller; otherwise the cheapest model on this provider in this session's tier or above, strictly cheaper than it, with a context window at least as large, not an experimental build and not a moving -latest alias, else this session's model; /auto-mode model chooses one by hand.",
|
|
211
|
+
indent: 1,
|
|
212
|
+
level: "dim",
|
|
213
|
+
});
|
|
167
214
|
} else {
|
|
168
215
|
lines.push({ text: "Auto-mode classifier: none — auto mode stays out of the mode cycle until a model is available", level: "warn" });
|
|
216
|
+
findings.push({
|
|
217
|
+
level: "warn",
|
|
218
|
+
text: "No auto-mode classifier model resolves, so auto mode stays out of the mode cycle.",
|
|
219
|
+
fix: "Choose one with /auto-mode model, or connect a provider with /login.",
|
|
220
|
+
});
|
|
169
221
|
}
|
|
170
222
|
for (const notice of classifier.notices) {
|
|
171
223
|
lines.push({ text: notice.text, indent: 1, level: notice.level === "warning" ? "warn" : "dim" });
|
|
172
224
|
if (notice.level === "warning") {
|
|
173
|
-
findings.push({
|
|
225
|
+
findings.push({
|
|
226
|
+
level: "warn",
|
|
227
|
+
text: `Classifier: ${notice.text}`,
|
|
228
|
+
fix: classifier.configured
|
|
229
|
+
? "Change it with /auto-mode model, or /auto-mode model clear for the automatic choice."
|
|
230
|
+
: "Check provider authentication and model availability, or choose one with /auto-mode model.",
|
|
231
|
+
});
|
|
174
232
|
}
|
|
175
233
|
}
|
|
176
234
|
|
|
177
235
|
if (facts.reader) {
|
|
178
236
|
lines.push({
|
|
179
|
-
text: `Web-fetch and recap reader: ${modelSpec(facts.reader.model)} — ${facts.reader.via === "tier" ? "cheapest
|
|
237
|
+
text: `Web-fetch and recap reader: ${modelSpec(facts.reader.model)} — ${facts.reader.via === "tier" ? "the cheapest cheap-tier model on this provider that costs no more than the main model (a workhorse or frontier one when there is none)" : "the main model"}`,
|
|
180
238
|
level: "dim",
|
|
181
239
|
});
|
|
182
240
|
}
|
|
183
241
|
|
|
184
|
-
// The
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
text: `${label}: coding index ${v.candidate?.coding} vs floor ${v.floor?.toFixed(1)} (${basis}; session ${v.session?.coding}, Sonnet 5 ${v.reference?.coding}) — ${v.verdict === "pass" ? "measured capable" : "below the floor"}`,
|
|
193
|
-
indent: 1,
|
|
194
|
-
level: "dim",
|
|
195
|
-
};
|
|
196
|
-
};
|
|
197
|
-
if (cap.snapshot) {
|
|
198
|
-
const ageH = Math.round(snapshotAgeMs({ fetchedAt: cap.snapshot.fetchedAt, source: "", rows: [] }) / 3_600_000);
|
|
199
|
-
lines.push({ text: `Capability scores: Artificial Analysis snapshot, ${cap.snapshot.rows} models, ${ageH} h old — measured picks for subagents and the classifier`, level: "ok" });
|
|
200
|
-
for (const line of [verdictLine("Subagent pick", cap.subagent), verdictLine("Classifier pick", cap.classifier), verdictLine("Reader pick", cap.reader)]) {
|
|
201
|
-
if (line) lines.push(line);
|
|
202
|
-
}
|
|
203
|
-
lines.push({ text: ATTRIBUTION, indent: 1, level: "dim" });
|
|
204
|
-
} else if (cap.keyConfigured) {
|
|
205
|
-
lines.push({ text: "Capability scores: key configured, snapshot not fetched yet — it downloads in the background on the next interactive start", level: "dim" });
|
|
206
|
-
} else {
|
|
207
|
-
lines.push({ text: "Capability scores: none — automatic picks use model names and generations only", level: "warn" });
|
|
208
|
-
findings.push({ level: "warn", text: "No Artificial Analysis key: subagent and classifier picks cannot be judged by measured coding ability.", fix: KEY_ADVICE });
|
|
209
|
-
}
|
|
210
|
-
|
|
242
|
+
// The catalogs every tier below frontier comes from, and how fresh they are.
|
|
243
|
+
const cat = facts.catalog;
|
|
244
|
+
const ageDays = Math.floor((Date.now() - Date.parse(cat.fetchedAt)) / DAY_MS);
|
|
245
|
+
const age = ageDays <= 0 ? "today" : ageDays === 1 ? "1 day ago" : `${ageDays} days ago`;
|
|
246
|
+
lines.push({
|
|
247
|
+
text: `Model catalogs: models.dev, OpenRouter and Hugging Face, fetched ${age} (${cat.refreshed ? "refreshed by One Code" : "bundled with this release"})${cat.refreshEnabled ? "; refreshed daily from interactive sessions" : "; daily refresh off (refreshModelCatalog: false, or PI_OFFLINE)"}`,
|
|
248
|
+
level: "dim",
|
|
249
|
+
});
|
|
211
250
|
if (session.permission) {
|
|
212
251
|
const mode = session.permission.mode;
|
|
213
252
|
const from = session.permission.source ? ` (${session.permission.source})` : "";
|
|
@@ -217,7 +256,7 @@ export function modelsSection(facts: ModelFacts, session: SessionView, findings:
|
|
|
217
256
|
if (facts.sessionTier === "tiny") {
|
|
218
257
|
findings.push({
|
|
219
258
|
level: "warn",
|
|
220
|
-
text: `${modelSpec(main)} is classed as a tiny-tier model
|
|
259
|
+
text: `${modelSpec(main)} is classed as a tiny-tier model (a small model); automatic alternatives exclude tiny models, but the session model remains the classifier fallback.`,
|
|
221
260
|
fix: "For coding work pick a cheap- or workhorse-tier model with /model; see /doctor presets.",
|
|
222
261
|
});
|
|
223
262
|
}
|
|
@@ -6,30 +6,22 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Presets never leave the current provider family: every automatic model choice
|
|
8
8
|
* in One Code is contained to the session's provider (a subagent inherits the
|
|
9
|
-
* transcript, the classifier reads the prompts — docs/decisions/model-policy.md),
|
|
9
|
+
* transcript, the classifier reads the prompts — working-docs/decisions/model-policy.md),
|
|
10
10
|
* and a preset is a bundle of those same choices. A user who wants another
|
|
11
11
|
* provider switches with /model first and reruns /doctor presets there.
|
|
12
12
|
*
|
|
13
|
-
* Each preset pins
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* balanced main = cheapest workhorse-tier model; subagents automatic (the
|
|
18
|
-
* cheapest model at the main's floor — often the main itself,
|
|
19
|
-
* since subagents share the classifier's workhorse floor);
|
|
20
|
-
* classifier automatic (workhorse floor)
|
|
21
|
-
* maximum quality main = the strongest (frontier, else priciest workhorse);
|
|
22
|
-
* subagents inherit it; classifier automatic
|
|
23
|
-
* so applying a preset is three settings writes the user can each undo by hand
|
|
24
|
-
* (/model, /subagent, /auto-mode model). The rows display what the resolvers
|
|
25
|
-
* would pick for that main model, computed with the resolvers themselves.
|
|
13
|
+
* Each preset pins the main model, sets the subagent default to the shape that
|
|
14
|
+
* matches its intent, and returns the classifier to the automatic choice
|
|
15
|
+
* (clearing `autoMode.classifierModel`); the rows display what its resolver
|
|
16
|
+
* would pick for that main model.
|
|
26
17
|
*/
|
|
27
18
|
|
|
28
19
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
29
20
|
import { classifierCandidates } from "../auto-mode/model-select.ts";
|
|
30
|
-
import {
|
|
31
|
-
import { isDatedDuplicate, modelsContainedToSession, modelSpec, pricedInput } from "../lib/model-policy.ts";
|
|
32
|
-
import { intrinsicTier, type PromptTier } from "../lib/model-tier.ts";
|
|
21
|
+
import { autoSelectable, catalogModelFor } from "../lib/model-catalog.ts";
|
|
22
|
+
import { isDatedDuplicate, isExperimentalBuild, modelsContainedToSession, modelSpec, pricedInput, supportsImageInput } from "../lib/model-policy.ts";
|
|
23
|
+
import { intrinsicTier, type PromptTier, servedCatalogIds } from "../lib/model-tier.ts";
|
|
24
|
+
import { newerModelSuggestion } from "../lib/newer-model.ts";
|
|
33
25
|
import { resolveSubagentModel } from "../subagents/model-select.ts";
|
|
34
26
|
import type { ReportLine, ReportSection } from "./report.ts";
|
|
35
27
|
|
|
@@ -44,7 +36,7 @@ export const PRESET_LABEL: Record<PresetName, string> = {
|
|
|
44
36
|
};
|
|
45
37
|
|
|
46
38
|
export const PRESET_INTENT: Record<PresetName, string> = {
|
|
47
|
-
economical: "lowest
|
|
39
|
+
economical: "lowest-cost main model, with subagents inheriting it",
|
|
48
40
|
balanced: "a capable main model, delegated work on the cheapest model at its floor",
|
|
49
41
|
quality: "the strongest model for the main session and its subagents",
|
|
50
42
|
};
|
|
@@ -71,10 +63,26 @@ export type PresetsUnavailable = "no-model" | "no-priced-models";
|
|
|
71
63
|
* to `claude-haiku-4-5`). Tiny-tier rows stay in the pool only as a last resort.
|
|
72
64
|
*/
|
|
73
65
|
export function presetPool(available: Model<Api>[], sessionModel: Model<Api>): Model<Api>[] {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
const all = modelsContainedToSession(available, sessionModel);
|
|
67
|
+
const served = servedCatalogIds(all);
|
|
68
|
+
// The newer-model check flags a main model with a newer model of its line at
|
|
69
|
+
// no more than 1.1× its price; supersession's band is 0.6–1.5×, so GPT-5.6
|
|
70
|
+
// Sol survives it against the half-price GPT-6.1 Sol. A preset never
|
|
71
|
+
// recommends a model /doctor would then call outdated, nor an alias of one
|
|
72
|
+
// (`gpt-daybreak-blue-latest` serves gpt-5.6-sol today).
|
|
73
|
+
const identity = (m: Model<Api>): string => catalogModelFor(m)?.id ?? modelSpec(m);
|
|
74
|
+
const outdated = new Set(all.filter((m) => newerModelSuggestion(available, m)).map(identity));
|
|
75
|
+
const contained = all.filter(
|
|
76
|
+
// A preset recommends a MAIN model: never one automatic selection skips
|
|
77
|
+
// (superseded by a model this provider serves, legacy, deprecated, unable
|
|
78
|
+
// to call tools, not a text model: model-catalog.ts), whatever its tier.
|
|
79
|
+
// A model no catalog knows stays, judged by its tier alone.
|
|
80
|
+
(m) => {
|
|
81
|
+
// An experimental build is out whether or not a catalog knows it.
|
|
82
|
+
if (pricedInput(m) === undefined || outdated.has(identity(m)) || isExperimentalBuild(m.id)) return false;
|
|
83
|
+
const entry = catalogModelFor(m);
|
|
84
|
+
return !entry || autoSelectable(entry, served);
|
|
85
|
+
},
|
|
78
86
|
);
|
|
79
87
|
return contained.filter((m) => !isDatedDuplicate(m, contained));
|
|
80
88
|
}
|
|
@@ -97,7 +105,10 @@ function pickMain(name: PresetName, pool: Model<Api>[]): { model: Model<Api>; no
|
|
|
97
105
|
return tiny ? { model: tiny, note: "only tiny-tier models on this provider — expect weaker results" } : undefined;
|
|
98
106
|
}
|
|
99
107
|
case "balanced": {
|
|
100
|
-
|
|
108
|
+
// The cheapest workhorse-or-better model: a frontier model cheaper than
|
|
109
|
+
// every workhorse one (GPT-6.1 Sol against the GPT-5.5 Pro SKU) is the
|
|
110
|
+
// better buy, not a reason to pay for the premium SKU.
|
|
111
|
+
const pick = cheapest([...workhorse, ...frontier]) ?? priciest(cheap);
|
|
101
112
|
if (pick) return { model: pick, note: workhorse.length === 0 ? "no workhorse-tier model on this provider" : undefined };
|
|
102
113
|
const any = priciest(pool);
|
|
103
114
|
return any ? { model: any, note: "only tiny-tier models on this provider — expect weaker results" } : undefined;
|
|
@@ -139,7 +150,7 @@ export function computePresets(
|
|
|
139
150
|
// what applying the preset produces.
|
|
140
151
|
const subagentModel = inherit
|
|
141
152
|
? main.model
|
|
142
|
-
: (resolveSubagentModel({ sessionModel: main.model, available }).model ?? main.model);
|
|
153
|
+
: (resolveSubagentModel({ sessionModel: main.model, available, requireImageInput: supportsImageInput(main.model) }).model ?? main.model);
|
|
143
154
|
const classifier = classifierCandidates({ available, sessionModel: main.model }).candidates[0]?.model;
|
|
144
155
|
presets.push({
|
|
145
156
|
name,
|
|
@@ -173,6 +184,10 @@ export function presetsSection(result: ReturnType<typeof computePresets>, sessio
|
|
|
173
184
|
lines.push({ text: "No priced models on this provider, so tiers cannot be told apart and no preset is offered.", level: "dim" });
|
|
174
185
|
return { title: "Presets", lines };
|
|
175
186
|
}
|
|
187
|
+
lines.push({
|
|
188
|
+
text: "Classifier previews use each preset's main model: the cheapest model in its tier or above that is strictly cheaper than the main model, else the main model itself.",
|
|
189
|
+
level: "dim",
|
|
190
|
+
});
|
|
176
191
|
const family = sessionModel ? sessionModel.provider : "";
|
|
177
192
|
for (const preset of result.presets) {
|
|
178
193
|
const sub = preset.subagents.setting === "inherit" ? "same" : shortId(preset.subagents.model);
|
|
@@ -193,9 +208,9 @@ export function presetsSection(result: ReturnType<typeof computePresets>, sessio
|
|
|
193
208
|
}
|
|
194
209
|
|
|
195
210
|
/**
|
|
196
|
-
* The three settings
|
|
197
|
-
*
|
|
198
|
-
*
|
|
211
|
+
* The three settings changes a preset makes, each with its undo — the text
|
|
212
|
+
* `/doctor preset` reports after applying. `mainSwitched` false means the
|
|
213
|
+
* session already ran the preset's main model, so that line says so.
|
|
199
214
|
*/
|
|
200
215
|
export function describePresetChanges(preset: PresetPlan, mainSwitched = true): string[] {
|
|
201
216
|
return [
|
|
@@ -9,17 +9,22 @@
|
|
|
9
9
|
* Claude Code never has to explain: which provider is ready, which model each
|
|
10
10
|
* role (main, subagents, classifier, reader) resolves to and why, what of the
|
|
11
11
|
* imported Claude Code configuration is honoured, and which external programs
|
|
12
|
-
* are missing. Rationale: docs/decisions/doctor.md.
|
|
12
|
+
* are missing. Rationale: working-docs/decisions/doctor.md.
|
|
13
13
|
*
|
|
14
14
|
* No pi imports. The wiring (index.ts, cli.ts) gathers the live inputs and hands
|
|
15
15
|
* them to `buildDoctorReport`; everything below is deterministic given them.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
19
|
+
import type { PromptTier } from "../lib/model-tier.ts";
|
|
19
20
|
import { tildify } from "../lib/paths.ts";
|
|
20
21
|
import type { McpStatusEvent } from "../lib/mcp-status.ts";
|
|
21
|
-
import {
|
|
22
|
+
import type { ReplacedBuiltinsView } from "./builtins.ts";
|
|
23
|
+
import type { CompactionKeepView } from "../lib/compaction-keep.mjs";
|
|
24
|
+
import type { RegisteredServer } from "../mcp/config.ts";
|
|
25
|
+
import { wrapProse } from "../lib/tui-render.ts";
|
|
22
26
|
import { countNoun } from "../lib/tui-render.ts";
|
|
27
|
+
import type { ConfigMode } from "../lib/config-mode.ts";
|
|
23
28
|
export { countNoun };
|
|
24
29
|
|
|
25
30
|
export type LineLevel = "ok" | "info" | "warn" | "error" | "dim";
|
|
@@ -63,6 +68,8 @@ export interface DoctorEnvironment {
|
|
|
63
68
|
agentDir: string;
|
|
64
69
|
/** One Code's own state dir (~/.onecode or ONECODE_STATE_DIR). */
|
|
65
70
|
stateDir: string;
|
|
71
|
+
/** Where configuration is read from (lib/config-mode.ts). */
|
|
72
|
+
configMode: ConfigMode;
|
|
66
73
|
env: NodeJS.ProcessEnv;
|
|
67
74
|
platform: string;
|
|
68
75
|
arch: string;
|
|
@@ -71,6 +78,14 @@ export interface DoctorEnvironment {
|
|
|
71
78
|
/** How One Code was launched: the bundled `onecode` app or the extension on the user's own pi. */
|
|
72
79
|
install: "app" | "pi-package";
|
|
73
80
|
piVersion?: string;
|
|
81
|
+
/** pi's built-ins One Code replaces and whether pi still loads them; undefined before pi 0.99 (doctor/builtins.ts). */
|
|
82
|
+
replacedBuiltins?: ReplacedBuiltinsView;
|
|
83
|
+
/** pi's compaction keep window and where it is set (lib/compaction-keep.mjs); undefined when the settings could not be read. */
|
|
84
|
+
compactionKeep?: CompactionKeepView & { paths: { user: string; project: string } };
|
|
85
|
+
/** pi's `CONFIG_DIR_NAME`, the project folder its own `mcp.json` sits in (`.pi` when absent). */
|
|
86
|
+
piConfigDirName?: string;
|
|
87
|
+
/** MCP servers other extensions registered in this session (`pi.getMcpServers()`); the CLI has none. */
|
|
88
|
+
registeredMcpServers?: RegisteredServer[];
|
|
74
89
|
/** Result of the registry lookup for the newest release, when one was attempted. */
|
|
75
90
|
latest?: { status: "current" | "behind" | "unknown" | "skipped"; version?: string; reason?: string };
|
|
76
91
|
}
|
|
@@ -88,6 +103,8 @@ export interface RegistryView {
|
|
|
88
103
|
/** Live session facts; the CLI fills what it can from settings and leaves the rest undefined. */
|
|
89
104
|
export interface SessionView {
|
|
90
105
|
model?: Model<Api>;
|
|
106
|
+
/** The running session's frozen register; absent in the standalone CLI. */
|
|
107
|
+
promptTier?: PromptTier;
|
|
91
108
|
/** Where `model` came from: the running session, pi's saved default, or nowhere. */
|
|
92
109
|
modelSource: "session" | "default-setting" | "first-available" | "none";
|
|
93
110
|
thinkingLevel?: string;
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
* an undiscoverable key). The wiring owns repaint and the fix/close effects.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { panelTopRule } from "../lib/tui-render.ts";
|
|
7
|
+
import { panelTopRule, wrapHints } from "../lib/tui-render.ts";
|
|
8
|
+
import { keyId, keyText } from "../lib/key-input.ts";
|
|
8
9
|
|
|
9
10
|
export interface DoctorViewerState {
|
|
10
11
|
offset: number;
|
|
12
|
+
/** Body rows the last render showed (the hint row can wrap); the keys page by it. */
|
|
13
|
+
visibleRows?: number;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export type DoctorViewerKey =
|
|
@@ -21,38 +24,43 @@ export type DoctorViewerKey =
|
|
|
21
24
|
| { kind: "close" };
|
|
22
25
|
|
|
23
26
|
export function decodeDoctorKey(data: string): DoctorViewerKey | undefined {
|
|
24
|
-
switch (data) {
|
|
25
|
-
case "
|
|
26
|
-
|
|
27
|
+
switch (keyId(data)) {
|
|
28
|
+
case "up":
|
|
29
|
+
return { kind: "up" };
|
|
30
|
+
case "down":
|
|
31
|
+
return { kind: "down" };
|
|
32
|
+
case "pageUp":
|
|
33
|
+
case "ctrl+b":
|
|
34
|
+
return { kind: "pageUp" };
|
|
35
|
+
case "pageDown":
|
|
36
|
+
case "ctrl+f":
|
|
37
|
+
case "space":
|
|
38
|
+
return { kind: "pageDown" };
|
|
39
|
+
case "home":
|
|
40
|
+
return { kind: "home" };
|
|
41
|
+
case "end":
|
|
42
|
+
return { kind: "end" };
|
|
43
|
+
case "escape":
|
|
44
|
+
case "ctrl+c":
|
|
45
|
+
case "enter":
|
|
46
|
+
return { kind: "close" };
|
|
47
|
+
default:
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
switch (keyText(data)) {
|
|
27
51
|
case "k":
|
|
28
52
|
return { kind: "up" };
|
|
29
|
-
case "\x1b[B":
|
|
30
|
-
case "\x1bOB":
|
|
31
53
|
case "j":
|
|
32
54
|
return { kind: "down" };
|
|
33
|
-
case "\x1b[5~":
|
|
34
|
-
case "\x02": // ctrl+b
|
|
35
55
|
case "b":
|
|
36
56
|
return { kind: "pageUp" };
|
|
37
|
-
case "\x1b[6~":
|
|
38
|
-
case "\x06": // ctrl+f
|
|
39
|
-
case " ":
|
|
40
|
-
return { kind: "pageDown" };
|
|
41
|
-
case "\x1b[H":
|
|
42
|
-
case "\x1b[1~":
|
|
43
57
|
case "g":
|
|
44
58
|
return { kind: "home" };
|
|
45
|
-
case "\x1b[F":
|
|
46
|
-
case "\x1b[4~":
|
|
47
59
|
case "G":
|
|
48
60
|
return { kind: "end" };
|
|
49
61
|
case "f":
|
|
50
62
|
return { kind: "fix" };
|
|
51
|
-
case "\x1b":
|
|
52
|
-
case "\x03": // ctrl+c
|
|
53
63
|
case "q":
|
|
54
|
-
case "\r":
|
|
55
|
-
case "\n":
|
|
56
64
|
return { kind: "close" };
|
|
57
65
|
default:
|
|
58
66
|
return undefined;
|
|
@@ -102,7 +110,7 @@ export interface DoctorViewerInput {
|
|
|
102
110
|
canFix: boolean;
|
|
103
111
|
}
|
|
104
112
|
|
|
105
|
-
/** Rows taken by the top rule
|
|
113
|
+
/** Rows taken by the top rule, the blank above the hints and a one-line hint row. */
|
|
106
114
|
export const VIEWER_CHROME_ROWS = 3;
|
|
107
115
|
|
|
108
116
|
export function visibleBodyRows(height: number): number {
|
|
@@ -111,14 +119,28 @@ export function visibleBodyRows(height: number): number {
|
|
|
111
119
|
|
|
112
120
|
export function renderDoctorViewer(input: DoctorViewerInput, paint: (color: string, text: string) => string): string[] {
|
|
113
121
|
const { lines, state, width, height } = input;
|
|
114
|
-
|
|
122
|
+
// PageUp/PageDown are pi-tui's own scrollback keys in fullscreen mode and never
|
|
123
|
+
// reach a component, so the hint names keys that do. On a narrow terminal the
|
|
124
|
+
// hints wrap at their separators (so "esc close" is never the part cut off)
|
|
125
|
+
// and the body gives up the rows; the position text depends on the body
|
|
126
|
+
// height, so the layout settles in a second pass.
|
|
127
|
+
const hintLines = (visible: number): string[] => {
|
|
128
|
+
const max = Math.max(0, lines.length - visible);
|
|
129
|
+
const offset = Math.min(state.offset, max);
|
|
130
|
+
const position = lines.length > visible ? ` · ${offset + 1}-${Math.min(lines.length, offset + visible)} of ${lines.length}` : "";
|
|
131
|
+
const hints = [`↑/↓ scroll · space/b page · g/G top/end${position}`, ...(input.canFix ? ["f run the checkup (the model fixes the findings)"] : []), "esc close"].join(" · ");
|
|
132
|
+
return wrapHints(hints, Math.max(1, width - 1));
|
|
133
|
+
};
|
|
134
|
+
let visible = visibleBodyRows(height);
|
|
135
|
+
let footer = hintLines(visible);
|
|
136
|
+
if (footer.length > 1) {
|
|
137
|
+
visible = Math.max(1, visible - (footer.length - 1));
|
|
138
|
+
footer = hintLines(visible);
|
|
139
|
+
}
|
|
140
|
+
state.visibleRows = visible;
|
|
115
141
|
const max = Math.max(0, lines.length - visible);
|
|
116
142
|
if (state.offset > max) state.offset = max;
|
|
117
143
|
const window = lines.slice(state.offset, state.offset + visible);
|
|
118
144
|
while (window.length < visible) window.push("");
|
|
119
|
-
|
|
120
|
-
// PageUp/PageDown are pi-tui's own scrollback keys in fullscreen mode and never
|
|
121
|
-
// reach a component, so the hint names keys that do.
|
|
122
|
-
const hints = [`↑/↓ scroll · space/b page · g/G top/end${position}`, ...(input.canFix ? ["f run the checkup (the model fixes the findings)"] : []), "esc close"].join(" · ");
|
|
123
|
-
return [panelTopRule(paint, width), ...window, "", paint("dim", ` ${hints}`)];
|
|
145
|
+
return [panelTopRule(paint, width), ...window, "", ...footer.map((line) => paint("dim", ` ${line}`))];
|
|
124
146
|
}
|