@gajae-code/coding-agent 0.14.2 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -1
- package/dist/types/async/job-manager.d.ts +4 -1
- package/dist/types/autoresearch/dashboard.d.ts +29 -4
- package/dist/types/autoresearch/data-context.d.ts +25 -0
- package/dist/types/autoresearch/git.d.ts +65 -7
- package/dist/types/autoresearch/harness.d.ts +58 -0
- package/dist/types/autoresearch/prompts.d.ts +51 -0
- package/dist/types/autoresearch/runs.d.ts +173 -0
- package/dist/types/autoresearch/types.d.ts +9 -139
- package/dist/types/capability/types.d.ts +20 -0
- package/dist/types/cli/accounts-cli.d.ts +1 -0
- package/dist/types/commands/{rlm.d.ts → autoresearch.d.ts} +2 -4
- package/dist/types/config/autorouting-contract.d.ts +146 -0
- package/dist/types/config/autorouting-generator.d.ts +40 -0
- package/dist/types/config/autorouting-tier-map.d.ts +16844 -0
- package/dist/types/config/autorouting.d.ts +35 -0
- package/dist/types/config/model-discovery-manager.d.ts +8 -1
- package/dist/types/config/model-registry.d.ts +30 -1
- package/dist/types/config/provider-selection-policy.d.ts +23 -0
- package/dist/types/config/settings-schema.d.ts +61 -3
- package/dist/types/config/settings.d.ts +3 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/coordinator-mcp/durability.d.ts +29 -0
- package/dist/types/coordinator-mcp/event-webhook.d.ts +50 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +1 -1
- package/dist/types/coordinator-mcp/server.d.ts +14 -0
- package/dist/types/crash/index-store.d.ts +3 -0
- package/dist/types/crash/record-loader.d.ts +2 -0
- package/dist/types/crash/upstream/relay.d.ts +5 -3
- package/dist/types/cursor.d.ts +12 -0
- package/dist/types/defaults/gjc-defaults.d.ts +35 -1
- package/dist/types/defaults/gjc-skills.generated.d.ts +1 -1
- package/dist/types/discovery/helpers.d.ts +1 -1
- package/dist/types/edit/index.d.ts +2 -1
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/extensibility/extensions/loader.d.ts +32 -0
- package/dist/types/extensibility/gjc-plugins/types.d.ts +1 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +194 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/psmux-detect.d.ts +1 -1
- package/dist/types/gjc-runtime/python-transcript.d.ts +19 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +2 -8
- package/dist/types/gjc-runtime/session-layout.d.ts +6 -3
- package/dist/types/gjc-runtime/state-renderer.d.ts +0 -22
- package/dist/types/gjc-runtime/state-schema.d.ts +7 -7
- package/dist/types/gjc-runtime/tmux-common.d.ts +2 -2
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +38 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +2 -24
- package/dist/types/gjc-runtime/ultragoal-validation-policy.d.ts +73 -0
- package/dist/types/gjc-runtime/workflow-recovery-projection.d.ts +100 -0
- package/dist/types/hooks/skill-keywords.d.ts +1 -1
- package/dist/types/main.d.ts +0 -10
- package/dist/types/modes/acp/acp-agent.d.ts +13 -6
- package/dist/types/modes/components/model-selector.d.ts +14 -0
- package/dist/types/modes/components/skill-hud/render.d.ts +6 -1
- package/dist/types/modes/components/smart-routing-panel.d.ts +82 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +14 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/types.d.ts +9 -0
- package/dist/types/rlm/artifacts.d.ts +4 -4
- package/dist/types/runtime/optional-runtime-services.d.ts +2 -1
- package/dist/types/runtime/workspace-tree-service.d.ts +5 -1
- package/dist/types/runtime-mcp/config.d.ts +6 -0
- package/dist/types/runtime-mcp/manager.d.ts +10 -0
- package/dist/types/sdk/acp/adapter.d.ts +0 -4
- package/dist/types/sdk/broker/broker.d.ts +1 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +57 -2
- package/dist/types/sdk/broker/session-index.d.ts +15 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/index.d.ts +8 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -2
- package/dist/types/sdk/client/client.d.ts +39 -4
- package/dist/types/sdk/host/host.d.ts +1 -0
- package/dist/types/sdk/host/internal-autorouting-state.d.ts +3 -0
- package/dist/types/sdk/host/model-pin.d.ts +29 -0
- package/dist/types/sdk/host/session-runtime.d.ts +2 -1
- package/dist/types/sdk/lifecycle-session.d.ts +13 -0
- package/dist/types/sdk/router/session-router.d.ts +27 -1
- package/dist/types/sdk/session.d.ts +11 -1
- package/dist/types/session/agent-session.d.ts +36 -6
- package/dist/types/session/artifacts.d.ts +16 -1
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
- package/dist/types/session/session-manager.d.ts +84 -2
- package/dist/types/session/session-staging-paths.d.ts +3 -0
- package/dist/types/skill-state/canonical-skills.d.ts +1 -1
- package/dist/types/skill-state/workflow-hud.d.ts +12 -21
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +1 -0
- package/dist/types/slash-commands/helpers/autorouting-status.d.ts +8 -0
- package/dist/types/system-prompt.d.ts +23 -0
- package/dist/types/task/executor.d.ts +35 -4
- package/dist/types/task/index.d.ts +17 -3
- package/dist/types/task/receipt.d.ts +3 -1
- package/dist/types/task/types.d.ts +144 -0
- package/dist/types/tools/atomic-file-write.d.ts +72 -0
- package/dist/types/tools/descriptors.d.ts +1 -0
- package/dist/types/tools/index.d.ts +36 -1
- package/dist/types/tools/move-session.d.ts +40 -0
- package/dist/types/tools/python.d.ts +12 -0
- package/dist/types/tools/resource-gc.d.ts +0 -3
- package/dist/types/tools/search.d.ts +8 -1
- package/dist/types/tools/skill.d.ts +9 -4
- package/dist/types/tools/subagent.d.ts +33 -3
- package/dist/types/utils/xml-escape.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +2 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +1 -1
- package/package.json +11 -12
- package/scripts/build-sdk-package-smoke.ts +7 -5
- package/scripts/check-autorouting-tier-map.ts +183 -0
- package/scripts/generate-sdk-operation-inventory.ts +12 -0
- package/scripts/generate-tool-catalog.ts +40 -5
- package/src/async/job-manager.ts +5 -2
- package/src/autoresearch/dashboard.ts +134 -314
- package/src/autoresearch/data-context.ts +35 -0
- package/src/autoresearch/git.ts +186 -26
- package/src/autoresearch/{helpers.ts → harness.ts} +65 -40
- package/src/autoresearch/{prompt-setup.md → prompts/prompt-setup.md} +7 -7
- package/src/autoresearch/prompts/prompt.md +103 -0
- package/src/autoresearch/prompts.ts +126 -0
- package/src/autoresearch/runs.ts +708 -0
- package/src/autoresearch/types.ts +9 -150
- package/src/capability/index.ts +4 -4
- package/src/capability/types.ts +20 -0
- package/src/cli/accounts-cli.ts +21 -5
- package/src/cli/config-cli.ts +25 -1
- package/src/cli/fast-help.ts +1 -2
- package/src/cli/list-models.ts +5 -8
- package/src/cli/setup-cli.ts +8 -0
- package/src/cli.ts +2 -21
- package/src/commands/autoresearch.ts +33 -0
- package/src/commands/coordinator.ts +15 -0
- package/src/commands/launch.ts +2 -4
- package/src/commands/quick-lane.ts +1 -1
- package/src/commands/sdk.ts +24 -0
- package/src/commands/state.ts +1 -1
- package/src/config/autorouting-contract.ts +474 -0
- package/src/config/autorouting-generator.ts +238 -0
- package/src/config/autorouting-tier-map.ts +6108 -0
- package/src/config/autorouting.ts +120 -0
- package/src/config/model-discovery-manager.ts +42 -11
- package/src/config/model-registry.ts +348 -68
- package/src/config/provider-selection-policy.ts +60 -9
- package/src/config/settings-schema.ts +195 -6
- package/src/config/settings.ts +62 -1
- package/src/config.ts +2 -3
- package/src/coordinator/contract.ts +0 -1
- package/src/coordinator-mcp/codex-handoff.ts +68 -42
- package/src/coordinator-mcp/durability.ts +200 -0
- package/src/coordinator-mcp/event-webhook.ts +278 -0
- package/src/coordinator-mcp/question-state.ts +109 -46
- package/src/coordinator-mcp/server.ts +932 -504
- package/src/crash/index-store.ts +126 -22
- package/src/crash/record-loader.ts +7 -0
- package/src/crash/upstream/relay.ts +82 -34
- package/src/cursor.ts +84 -1
- package/src/debug/index.ts +26 -0
- package/src/defaults/gjc/skills/autoresearch/SKILL.md +116 -0
- package/src/defaults/gjc/skills/autoresearch/auto-critic.md +46 -0
- package/src/defaults/gjc/skills/autoresearch/auto-iterate.md +42 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +17 -37
- package/src/defaults/gjc/skills/ralplan/SKILL.md +21 -18
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +6 -17
- package/src/defaults/gjc/skills/ultragoal/ai-slop-cleaner.md +2 -2
- package/src/defaults/gjc-defaults.ts +89 -2
- package/src/defaults/gjc-skills.generated.ts +24 -17
- package/src/discovery/builtin.ts +18 -5
- package/src/discovery/helpers.ts +6 -6
- package/src/edit/index.ts +5 -2
- package/src/eval/py/executor.ts +8 -0
- package/src/extensibility/extensions/loader.ts +135 -13
- package/src/extensibility/extensions/wrapper.ts +1 -2
- package/src/extensibility/gjc-plugins/schema.ts +1 -1
- package/src/extensibility/runtime-skill-discovery.ts +2 -2
- package/src/extensibility/skill-management.ts +2 -3
- package/src/extensibility/skills.ts +16 -8
- package/src/gjc-runtime/autoresearch-runtime.ts +1509 -0
- package/src/gjc-runtime/gc-render.ts +0 -1
- package/src/gjc-runtime/gc-runtime.ts +1 -11
- package/src/gjc-runtime/launch-tmux.ts +3 -3
- package/src/gjc-runtime/psmux-detect.ts +2 -2
- package/src/gjc-runtime/python-transcript.ts +58 -0
- package/src/gjc-runtime/ralplan-runtime.ts +6 -18
- package/src/gjc-runtime/session-layout.ts +18 -7
- package/src/gjc-runtime/session-state-sidecar.ts +58 -9
- package/src/gjc-runtime/state-renderer.ts +0 -38
- package/src/gjc-runtime/state-runtime.ts +43 -22
- package/src/gjc-runtime/state-schema.ts +1 -1
- package/src/gjc-runtime/tmux-common.ts +7 -7
- package/src/gjc-runtime/ultragoal-change-set.ts +232 -11
- package/src/gjc-runtime/ultragoal-runtime.ts +309 -114
- package/src/gjc-runtime/ultragoal-validation-policy.ts +247 -0
- package/src/gjc-runtime/workflow-command-ref.ts +15 -11
- package/src/gjc-runtime/workflow-manifest.generated.json +413 -532
- package/src/gjc-runtime/workflow-manifest.ts +43 -83
- package/src/gjc-runtime/workflow-recovery-projection.ts +616 -0
- package/src/hooks/skill-keywords.ts +3 -3
- package/src/hooks/skill-state.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +26 -24
- package/src/lsp/index.ts +25 -5
- package/src/main.ts +2 -27
- package/src/modes/acp/acp-agent.ts +200 -75
- package/src/modes/components/model-selector.ts +216 -13
- package/src/modes/components/oauth-selector.ts +5 -5
- package/src/modes/components/skill-hud/render.ts +173 -35
- package/src/modes/components/smart-routing-panel.ts +531 -0
- package/src/modes/components/tool-status-header.ts +6 -3
- package/src/modes/controllers/command-controller.ts +17 -7
- package/src/modes/controllers/input-controller.ts +44 -9
- package/src/modes/controllers/runtime-mcp-command-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +298 -65
- package/src/modes/interactive-mode.ts +8 -1
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +1 -1
- package/src/modes/types.ts +9 -1
- package/src/prompts/agents/planner.md +1 -1
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/volatile-project-context.md +2 -1
- package/src/prompts/tools/move-session.md +15 -0
- package/src/prompts/tools/python.md +12 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/prompts/tools/skill.md +2 -2
- package/src/prompts/tools/task-summary.md +1 -0
- package/src/prompts/tools/task.md +6 -0
- package/src/rlm/artifacts.ts +12 -10
- package/src/runtime/optional-runtime-services.ts +3 -2
- package/src/runtime/workspace-tree-service.ts +11 -3
- package/src/runtime-mcp/config.ts +8 -1
- package/src/runtime-mcp/manager.ts +33 -0
- package/src/sdk/acp/adapter.ts +48 -1
- package/src/sdk/broker/broker.ts +30 -2
- package/src/sdk/broker/discovery.ts +217 -2
- package/src/sdk/broker/lifecycle.ts +385 -59
- package/src/sdk/broker/session-index.ts +243 -48
- package/src/sdk/broker/transport.ts +1 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +5 -0
- package/src/sdk/bus/index.ts +208 -11
- package/src/sdk/bus/kind-aware-reconciliation.ts +16 -0
- package/src/sdk/bus/reconciliation-store.ts +27 -5
- package/src/sdk/bus/telegram-daemon-contract.ts +12 -2
- package/src/sdk/client/client.ts +204 -22
- package/src/sdk/host/host.ts +16 -0
- package/src/sdk/host/internal-autorouting-state.ts +13 -0
- package/src/sdk/host/model-pin.ts +101 -0
- package/src/sdk/host/reverse-leases.ts +2 -1
- package/src/sdk/host/session-runtime.test.ts +224 -1
- package/src/sdk/host/session-runtime.ts +125 -37
- package/src/sdk/lifecycle/service.ts +3 -1
- package/src/sdk/lifecycle-session.ts +42 -1
- package/src/sdk/protocol/operation-inventory.generated.json +66 -0
- package/src/sdk/router/session-router.ts +375 -36
- package/src/sdk/session.ts +547 -47
- package/src/session/account-inventory.ts +1 -1
- package/src/session/agent-session.ts +765 -189
- package/src/session/artifacts.ts +234 -4
- package/src/session/internal/managed-session-storage.ts +91 -4
- package/src/session/provider-safety-stop-hint.ts +3 -2
- package/src/session/session-manager.ts +775 -16
- package/src/session/session-staging-paths.ts +8 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +0 -1
- package/src/setup/host-plugin-setup.ts +2 -2
- package/src/skill-state/active-state.ts +2 -2
- package/src/skill-state/canonical-skills.ts +1 -1
- package/src/skill-state/initial-phase.ts +1 -1
- package/src/skill-state/workflow-hud.ts +41 -41
- package/src/skill-state/workflow-mutation-guard.ts +26 -7
- package/src/slash-commands/builtin-registry.ts +77 -0
- package/src/slash-commands/helpers/autorouting-status.ts +55 -0
- package/src/system-prompt.ts +102 -5
- package/src/task/discovery.ts +2 -3
- package/src/task/executor.ts +617 -43
- package/src/task/index.ts +262 -15
- package/src/task/receipt.ts +30 -0
- package/src/task/render.ts +11 -1
- package/src/task/types.ts +316 -0
- package/src/tools/atomic-file-write.ts +594 -0
- package/src/tools/bisect.ts +3 -2
- package/src/tools/descriptors.test.ts +3 -0
- package/src/tools/descriptors.ts +24 -0
- package/src/tools/image-gen.ts +5 -1
- package/src/tools/index.ts +62 -5
- package/src/tools/move-session.ts +107 -0
- package/src/tools/python.ts +205 -0
- package/src/tools/read.ts +88 -15
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resource-gc.ts +8 -177
- package/src/tools/search.ts +30 -6
- package/src/tools/skill-discovery.ts +1 -0
- package/src/tools/skill.ts +37 -7
- package/src/tools/subagent-render.ts +119 -13
- package/src/tools/subagent.ts +91 -74
- package/src/tools/tool-catalog.generated.ts +64 -2
- package/src/tools/write.ts +16 -12
- package/src/utils/xml-escape.ts +14 -0
- package/src/web/search/providers/codex.ts +2 -2
- package/src/workflow/workflow-intent-diff.ts +13 -12
- package/src/workflow/workflow-intent-report-consumer.ts +6 -6
- package/dist/types/autoresearch/helpers.d.ts +0 -24
- package/dist/types/autoresearch/index.d.ts +0 -2
- package/dist/types/autoresearch/state.d.ts +0 -17
- package/dist/types/autoresearch/storage.d.ts +0 -142
- package/dist/types/autoresearch/tools/init-experiment.d.ts +0 -31
- package/dist/types/autoresearch/tools/log-experiment.d.ts +0 -23
- package/dist/types/autoresearch/tools/run-experiment.d.ts +0 -8
- package/dist/types/autoresearch/tools/update-notes.d.ts +0 -12
- package/dist/types/commands/team.d.ts +0 -24
- package/dist/types/gjc-runtime/team-gc.d.ts +0 -7
- package/dist/types/gjc-runtime/team-launch.d.ts +0 -61
- package/dist/types/gjc-runtime/team-notify.d.ts +0 -45
- package/dist/types/gjc-runtime/team-runtime.d.ts +0 -336
- package/dist/types/gjc-runtime/team-store.d.ts +0 -168
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +0 -43
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +0 -92
- package/dist/types/gjc-runtime/team-workers.d.ts +0 -83
- package/dist/types/rlm/index.d.ts +0 -47
- package/dist/types/rlm/preset.d.ts +0 -23
- package/dist/types/rlm/python-tool.d.ts +0 -16
- package/src/autoresearch/command-resume.md +0 -14
- package/src/autoresearch/index.ts +0 -536
- package/src/autoresearch/prompt.md +0 -103
- package/src/autoresearch/resume-message.md +0 -10
- package/src/autoresearch/state.ts +0 -273
- package/src/autoresearch/storage.ts +0 -699
- package/src/autoresearch/tools/init-experiment.ts +0 -272
- package/src/autoresearch/tools/log-experiment.ts +0 -524
- package/src/autoresearch/tools/run-experiment.ts +0 -475
- package/src/autoresearch/tools/update-notes.ts +0 -109
- package/src/commands/rlm.ts +0 -19
- package/src/commands/team.ts +0 -238
- package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +0 -42
- package/src/defaults/gjc/skills/team/SKILL.md +0 -467
- package/src/gjc-runtime/team-gc.ts +0 -49
- package/src/gjc-runtime/team-launch.ts +0 -404
- package/src/gjc-runtime/team-notify.ts +0 -326
- package/src/gjc-runtime/team-runtime.ts +0 -5923
- package/src/gjc-runtime/team-store.ts +0 -878
- package/src/gjc-runtime/team-worker-heartbeat.ts +0 -149
- package/src/gjc-runtime/team-worker-memory-guard.ts +0 -363
- package/src/gjc-runtime/team-workers.ts +0 -1123
- package/src/prompts/system/rlm-report-command.md +0 -1
- package/src/prompts/system/rlm-research.md +0 -23
- package/src/rlm/index.ts +0 -365
- package/src/rlm/preset.ts +0 -76
- package/src/rlm/python-tool.ts +0 -68
|
@@ -504,6 +504,10 @@ export class MCPCommandController {
|
|
|
504
504
|
);
|
|
505
505
|
|
|
506
506
|
// Replace editor with wizard
|
|
507
|
+
// The composer is reusable across overlays; detach it before clearing so
|
|
508
|
+
// clear() disposes only the transient wizard, not the editor's
|
|
509
|
+
// tab-width listener / paste state (disposal is terminal).
|
|
510
|
+
this.ctx.editorContainer.detachChild(this.ctx.editor);
|
|
507
511
|
this.ctx.editorContainer.clear();
|
|
508
512
|
this.ctx.editorContainer.addChild(wizard);
|
|
509
513
|
this.ctx.ui.setFocus(wizard);
|
|
@@ -12,6 +12,16 @@ import type { OAuthProvider } from "@gajae-code/ai/utils/oauth/types";
|
|
|
12
12
|
import type { Component, OverlayHandle, SlashCommand } from "@gajae-code/tui";
|
|
13
13
|
import { Input, Loader, resolvePetMode, Spacer, Text } from "@gajae-code/tui";
|
|
14
14
|
import { getAgentDbPath, getProjectDir, logger, VERSION } from "@gajae-code/utils";
|
|
15
|
+
import {
|
|
16
|
+
type AutoroutingProvenance,
|
|
17
|
+
type AutoroutingSetup,
|
|
18
|
+
buildAutoroutingEnabledPatch,
|
|
19
|
+
buildAutoroutingSettingsBatch,
|
|
20
|
+
evaluateAutoroutingProvenanceState,
|
|
21
|
+
validateAutoroutingSetup,
|
|
22
|
+
} from "../../config/autorouting-contract";
|
|
23
|
+
import { canonicalJsonBytes, generateTierChains } from "../../config/autorouting-generator";
|
|
24
|
+
import { CURATED_TIER_MAP } from "../../config/autorouting-tier-map";
|
|
15
25
|
import type { AppKeybinding } from "../../config/keybindings";
|
|
16
26
|
import {
|
|
17
27
|
activateModelProfile,
|
|
@@ -26,7 +36,7 @@ import { GJC_MODEL_ASSIGNMENT_TARGETS, type GjcModelAssignmentTargetId } from ".
|
|
|
26
36
|
import { formatModelSelectorValue } from "../../config/model-resolver";
|
|
27
37
|
import { selectorHead } from "../../config/model-selector-value";
|
|
28
38
|
import type { ModelProfileConfig } from "../../config/models-config-schema";
|
|
29
|
-
import { type Settings, type SettingsAtomicReceipt, settings } from "../../config/settings";
|
|
39
|
+
import { type RawSettings, type Settings, type SettingsAtomicReceipt, settings } from "../../config/settings";
|
|
30
40
|
import type { SettingValue } from "../../config/settings-schema";
|
|
31
41
|
import { DebugSelectorComponent } from "../../debug";
|
|
32
42
|
import { disableProvider, enableProvider } from "../../discovery";
|
|
@@ -167,7 +177,6 @@ import {
|
|
|
167
177
|
PlanPreviewOverlay,
|
|
168
178
|
type PlanPreviewResult,
|
|
169
179
|
} from "../components/plan-preview-overlay";
|
|
170
|
-
|
|
171
180
|
import { PluginSelectorComponent } from "../components/plugin-selector";
|
|
172
181
|
import {
|
|
173
182
|
type ProviderOnboardingAction,
|
|
@@ -179,6 +188,7 @@ import { SessionObserverOverlayComponent } from "../components/session-observer-
|
|
|
179
188
|
import { SessionSelectorComponent } from "../components/session-selector";
|
|
180
189
|
import { dashboardSessions, SessionsDashboardComponent } from "../components/sessions-dashboard";
|
|
181
190
|
import { SettingsSelectorComponent } from "../components/settings-selector";
|
|
191
|
+
import type { SmartRoutingPreview } from "../components/smart-routing-panel";
|
|
182
192
|
import { TasksPaneComponent } from "../components/tasks-pane";
|
|
183
193
|
import { ThemeSelectorComponent } from "../components/theme-selector";
|
|
184
194
|
import { ThinkingSelectorComponent } from "../components/thinking-selector";
|
|
@@ -1176,7 +1186,36 @@ interface DefaultAssignmentRollbackSnapshot {
|
|
|
1176
1186
|
resumeDefaultSelector: string | undefined;
|
|
1177
1187
|
fallbackRuntimeState: DefaultFallbackRuntimeState;
|
|
1178
1188
|
}
|
|
1189
|
+
|
|
1190
|
+
function sameCanonicalAutoroutingValue(left: unknown, right: unknown): boolean {
|
|
1191
|
+
const leftBytes = canonicalJsonBytes(left);
|
|
1192
|
+
const rightBytes = canonicalJsonBytes(right);
|
|
1193
|
+
if (leftBytes.length !== rightBytes.length) return false;
|
|
1194
|
+
for (let index = 0; index < leftBytes.length; index++) {
|
|
1195
|
+
if (leftBytes[index] !== rightBytes[index]) return false;
|
|
1196
|
+
}
|
|
1197
|
+
return true;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
function rawAutoroutingState(current: RawSettings): {
|
|
1201
|
+
provenance?: AutoroutingProvenance;
|
|
1202
|
+
setup?: AutoroutingSetup;
|
|
1203
|
+
tiers?: unknown;
|
|
1204
|
+
} {
|
|
1205
|
+
const task = current.task;
|
|
1206
|
+
if (!task || typeof task !== "object" || Array.isArray(task)) return {};
|
|
1207
|
+
const autorouting = (task as Record<string, unknown>).autorouting;
|
|
1208
|
+
if (!autorouting || typeof autorouting !== "object" || Array.isArray(autorouting)) return {};
|
|
1209
|
+
const record = autorouting as Record<string, unknown>;
|
|
1210
|
+
return {
|
|
1211
|
+
provenance: record.provenance as AutoroutingProvenance | undefined,
|
|
1212
|
+
setup: record.setup as AutoroutingSetup | undefined,
|
|
1213
|
+
tiers: record.tiers,
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1179
1217
|
export class SelectorController {
|
|
1218
|
+
#smartRoutingInFlight?: Promise<unknown>;
|
|
1180
1219
|
#transcriptViewerOpen = false;
|
|
1181
1220
|
#transcriptViewer?: TranscriptViewerOverlay;
|
|
1182
1221
|
#sessionsDashboardOpen = false;
|
|
@@ -1338,6 +1377,10 @@ export class SelectorController {
|
|
|
1338
1377
|
}
|
|
1339
1378
|
};
|
|
1340
1379
|
const { component, focus } = create(done);
|
|
1380
|
+
// The composer is reusable across overlays; detach it before clearing so
|
|
1381
|
+
// clear() disposes only the transient overlay, not the editor's
|
|
1382
|
+
// tab-width listener / paste state (disposal is terminal).
|
|
1383
|
+
this.ctx.editorContainer.detachChild(this.ctx.editor);
|
|
1341
1384
|
this.ctx.editorContainer.clear();
|
|
1342
1385
|
this.ctx.editorContainer.addChild(component);
|
|
1343
1386
|
this.ctx.ui.setFocus(focus);
|
|
@@ -2274,7 +2317,208 @@ export class SelectorController {
|
|
|
2274
2317
|
this.ctx.showStatus(persistDefault ? `Default model profile: ${profileLabel}` : `Model profile: ${profileLabel}`);
|
|
2275
2318
|
}
|
|
2276
2319
|
|
|
2277
|
-
|
|
2320
|
+
/** Generate the immutable preview used by the smart-routing panel. */
|
|
2321
|
+
previewSmartRouting(draft: AutoroutingSetup): SmartRoutingPreview {
|
|
2322
|
+
const issues = validateAutoroutingSetup(draft);
|
|
2323
|
+
if (issues.length > 0)
|
|
2324
|
+
throw new Error(issues.map(issue => `${issue.path || "setup"}: ${issue.detail}`).join("; "));
|
|
2325
|
+
const setup = structuredClone(draft);
|
|
2326
|
+
const generated = generateTierChains(setup, CURATED_TIER_MAP, [...this.ctx.session.modelRegistry.getAll()]);
|
|
2327
|
+
const provenance: AutoroutingProvenance = {
|
|
2328
|
+
schema: 1,
|
|
2329
|
+
source: structuredClone(generated.sourceIdentity),
|
|
2330
|
+
declarationFingerprint: generated.declarationFingerprint,
|
|
2331
|
+
tiersFingerprint: generated.tiersFingerprint,
|
|
2332
|
+
};
|
|
2333
|
+
return {
|
|
2334
|
+
setup,
|
|
2335
|
+
tiers: structuredClone(generated.tiers),
|
|
2336
|
+
provenance,
|
|
2337
|
+
sourceIdentity: structuredClone(generated.sourceIdentity),
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
#assertSmartRoutingWritable(): void {
|
|
2342
|
+
if ((this.ctx.session.scopedModels?.length ?? 0) > 0) {
|
|
2343
|
+
throw new Error("Smart-routing settings are read-only in a --models-scoped session.");
|
|
2344
|
+
}
|
|
2345
|
+
if (!this.ctx.settings.canWriteDurableConfig()) {
|
|
2346
|
+
throw new Error("Cannot change smart-routing settings while durable config is unavailable.");
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
#assertSmartRoutingNotHandEdited(
|
|
2351
|
+
preview: SmartRoutingPreview,
|
|
2352
|
+
allowHandEdit: boolean,
|
|
2353
|
+
current?: { provenance?: AutoroutingProvenance; tiers?: unknown },
|
|
2354
|
+
): void {
|
|
2355
|
+
if (allowHandEdit) return;
|
|
2356
|
+
const provenance = current?.provenance ?? this.ctx.settings.get("task.autorouting.provenance");
|
|
2357
|
+
const currentTiers = current?.tiers ?? this.ctx.settings.get("task.autorouting.tiers");
|
|
2358
|
+
if (!provenance || currentTiers === undefined) return;
|
|
2359
|
+
const state = evaluateAutoroutingProvenanceState(provenance, {
|
|
2360
|
+
catalogFingerprint: preview.sourceIdentity.catalogFingerprint,
|
|
2361
|
+
mapFingerprint: preview.sourceIdentity.mapFingerprint,
|
|
2362
|
+
tiers: currentTiers,
|
|
2363
|
+
});
|
|
2364
|
+
if (!state.handEdited) return;
|
|
2365
|
+
throw Object.assign(
|
|
2366
|
+
new Error("Generated autorouting tiers were hand-edited; explicit confirmation is required."),
|
|
2367
|
+
{ code: "autorouting-hand-edited" },
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
async #runSmartRoutingIntent<T>(label: string, operation: () => Promise<T>): Promise<T> {
|
|
2372
|
+
if (this.#smartRoutingInFlight) throw new Error("Another smart-routing operation is already in progress.");
|
|
2373
|
+
const task = (async () => {
|
|
2374
|
+
this.ctx.showStatus(`${label} smart-routing settings…`);
|
|
2375
|
+
try {
|
|
2376
|
+
const result = await operation();
|
|
2377
|
+
await this.ctx.notifyConfigChanged?.();
|
|
2378
|
+
this.ctx.showStatus(`${label} smart-routing settings saved.`);
|
|
2379
|
+
this.ctx.ui.requestRender();
|
|
2380
|
+
return result;
|
|
2381
|
+
} catch (error) {
|
|
2382
|
+
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
2383
|
+
this.ctx.ui.requestRender();
|
|
2384
|
+
throw error;
|
|
2385
|
+
} finally {
|
|
2386
|
+
this.#smartRoutingInFlight = undefined;
|
|
2387
|
+
}
|
|
2388
|
+
})();
|
|
2389
|
+
this.#smartRoutingInFlight = task;
|
|
2390
|
+
return task;
|
|
2391
|
+
}
|
|
2392
|
+
#reportSmartRoutingValidationError(error: unknown): never {
|
|
2393
|
+
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
2394
|
+
this.ctx.ui.requestRender();
|
|
2395
|
+
throw error;
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
async applySmartRouting(
|
|
2399
|
+
draft: AutoroutingSetup,
|
|
2400
|
+
options?: { preview?: SmartRoutingPreview; confirmHandEdit?: boolean },
|
|
2401
|
+
): Promise<SmartRoutingPreview> {
|
|
2402
|
+
let preview: SmartRoutingPreview;
|
|
2403
|
+
try {
|
|
2404
|
+
this.#assertSmartRoutingWritable();
|
|
2405
|
+
const issues = validateAutoroutingSetup(draft);
|
|
2406
|
+
if (issues.length > 0) {
|
|
2407
|
+
throw new Error(issues.map(issue => `${issue.path || "setup"}: ${issue.detail}`).join("; "));
|
|
2408
|
+
}
|
|
2409
|
+
preview = options?.preview ?? this.previewSmartRouting(draft);
|
|
2410
|
+
const regenerated = this.previewSmartRouting(draft);
|
|
2411
|
+
if (!sameCanonicalAutoroutingValue(preview.setup, regenerated.setup)) {
|
|
2412
|
+
throw new Error("Smart-routing preview does not match the draft being applied.");
|
|
2413
|
+
}
|
|
2414
|
+
if (
|
|
2415
|
+
!sameCanonicalAutoroutingValue(preview.tiers, regenerated.tiers) ||
|
|
2416
|
+
!sameCanonicalAutoroutingValue(preview.provenance, regenerated.provenance)
|
|
2417
|
+
) {
|
|
2418
|
+
// Never persist caller-supplied tier/provenance bytes that diverge from
|
|
2419
|
+
// the declaration. Continue with the fresh canonical payload so Apply
|
|
2420
|
+
// remains exactly the generated preview for legitimate callers.
|
|
2421
|
+
preview = regenerated;
|
|
2422
|
+
}
|
|
2423
|
+
this.#assertSmartRoutingNotHandEdited(preview, options?.confirmHandEdit === true);
|
|
2424
|
+
} catch (error) {
|
|
2425
|
+
return this.#reportSmartRoutingValidationError(error);
|
|
2426
|
+
}
|
|
2427
|
+
return this.#runSmartRoutingIntent("Apply", async () => {
|
|
2428
|
+
await this.ctx.settings.commitAtomicBatchWithCurrent(current => {
|
|
2429
|
+
this.#assertSmartRoutingNotHandEdited(
|
|
2430
|
+
preview,
|
|
2431
|
+
options?.confirmHandEdit === true,
|
|
2432
|
+
rawAutoroutingState(current),
|
|
2433
|
+
);
|
|
2434
|
+
return buildAutoroutingSettingsBatch({
|
|
2435
|
+
tiers: preview.tiers,
|
|
2436
|
+
setup: preview.setup,
|
|
2437
|
+
provenance: preview.provenance,
|
|
2438
|
+
});
|
|
2439
|
+
});
|
|
2440
|
+
return preview;
|
|
2441
|
+
});
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
/**
|
|
2445
|
+
* Reorder a recorded declaration into current provider priority and drop entries
|
|
2446
|
+
* the catalog no longer offers. Comparison uses normalized ids while the result
|
|
2447
|
+
* keeps the catalog's spelling, because the generator matches provider prefixes
|
|
2448
|
+
* case-sensitively.
|
|
2449
|
+
*/
|
|
2450
|
+
#reseedProvidersFromPolicy(setup: AutoroutingSetup): AutoroutingSetup {
|
|
2451
|
+
const order = this.ctx.session.modelRegistry.autoroutingProviderOrder();
|
|
2452
|
+
const declared = new Set(setup.providers.map(provider => provider.trim().toLowerCase()));
|
|
2453
|
+
const providers = order.filter(provider => declared.has(provider.trim().toLowerCase()));
|
|
2454
|
+
return { ...structuredClone(setup), providers };
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
async refreshSmartRouting(options?: { confirmHandEdit?: boolean }): Promise<SmartRoutingPreview> {
|
|
2458
|
+
let preview: SmartRoutingPreview;
|
|
2459
|
+
let expectedSetup: AutoroutingSetup;
|
|
2460
|
+
try {
|
|
2461
|
+
this.#assertSmartRoutingWritable();
|
|
2462
|
+
const setup = this.ctx.settings.get("task.autorouting.setup");
|
|
2463
|
+
const issues = validateAutoroutingSetup(setup);
|
|
2464
|
+
if (issues.length > 0 || setup === undefined) {
|
|
2465
|
+
throw new Error("Cannot refresh smart routing without a valid recorded setup.");
|
|
2466
|
+
}
|
|
2467
|
+
expectedSetup = setup;
|
|
2468
|
+
// Reseed the recorded declaration against the current provider priority:
|
|
2469
|
+
// reorder to policy order and drop providers the catalog no longer offers.
|
|
2470
|
+
// Refusing an empty result keeps a dead declaration from being persisted.
|
|
2471
|
+
const reseeded = this.#reseedProvidersFromPolicy(setup);
|
|
2472
|
+
if (reseeded.providers.length === 0) {
|
|
2473
|
+
throw new Error("No declared providers remain in the catalog; smart routing was not updated.");
|
|
2474
|
+
}
|
|
2475
|
+
preview = this.previewSmartRouting(reseeded);
|
|
2476
|
+
this.#assertSmartRoutingNotHandEdited(preview, options?.confirmHandEdit === true);
|
|
2477
|
+
} catch (error) {
|
|
2478
|
+
return this.#reportSmartRoutingValidationError(error);
|
|
2479
|
+
}
|
|
2480
|
+
return this.#runSmartRoutingIntent("Refresh", async () => {
|
|
2481
|
+
await this.ctx.settings.commitAtomicBatchWithCurrent(current => {
|
|
2482
|
+
const currentState = rawAutoroutingState(current);
|
|
2483
|
+
if (!sameCanonicalAutoroutingValue(currentState.setup, expectedSetup)) {
|
|
2484
|
+
throw new Error(
|
|
2485
|
+
"Smart-routing setup changed while refresh was preparing; refresh again to use current settings.",
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2488
|
+
this.#assertSmartRoutingNotHandEdited(preview, options?.confirmHandEdit === true, currentState);
|
|
2489
|
+
return buildAutoroutingSettingsBatch({
|
|
2490
|
+
tiers: preview.tiers,
|
|
2491
|
+
setup: preview.setup,
|
|
2492
|
+
provenance: preview.provenance,
|
|
2493
|
+
});
|
|
2494
|
+
});
|
|
2495
|
+
return preview;
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
async clearGeneratedSetup(): Promise<void> {
|
|
2500
|
+
try {
|
|
2501
|
+
this.#assertSmartRoutingWritable();
|
|
2502
|
+
} catch (error) {
|
|
2503
|
+
return this.#reportSmartRoutingValidationError(error);
|
|
2504
|
+
}
|
|
2505
|
+
return this.#runSmartRoutingIntent("Clear", async () => {
|
|
2506
|
+
await this.ctx.settings.commitAtomicBatchWithCurrent(() => buildAutoroutingSettingsBatch({ clear: true }));
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
async setAutoroutingEnabled(enabled: boolean): Promise<void> {
|
|
2511
|
+
try {
|
|
2512
|
+
this.#assertSmartRoutingWritable();
|
|
2513
|
+
} catch (error) {
|
|
2514
|
+
return this.#reportSmartRoutingValidationError(error);
|
|
2515
|
+
}
|
|
2516
|
+
return this.#runSmartRoutingIntent("Toggle", async () => {
|
|
2517
|
+
await this.ctx.settings.commitAtomicBatchWithCurrent(() => [buildAutoroutingEnabledPatch(enabled)]);
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
showModelSelector(options?: { temporaryOnly?: boolean; smartRoutingOnly?: boolean }): void {
|
|
2278
2522
|
this.showSelector(done => {
|
|
2279
2523
|
let modelSelector: ModelSelectorComponent;
|
|
2280
2524
|
const refreshRoleAssignments = () => {
|
|
@@ -2292,6 +2536,27 @@ export class SelectorController {
|
|
|
2292
2536
|
this.ctx.session.modelRegistry,
|
|
2293
2537
|
this.ctx.session.scopedModels,
|
|
2294
2538
|
async selection => {
|
|
2539
|
+
if (selection.kind === "smartRouting") {
|
|
2540
|
+
switch (selection.intent.kind) {
|
|
2541
|
+
case "apply":
|
|
2542
|
+
await this.applySmartRouting(selection.intent.draft, {
|
|
2543
|
+
preview: selection.intent.preview,
|
|
2544
|
+
confirmHandEdit: selection.intent.confirmHandEdit,
|
|
2545
|
+
});
|
|
2546
|
+
break;
|
|
2547
|
+
case "refresh":
|
|
2548
|
+
await this.refreshSmartRouting({ confirmHandEdit: selection.intent.confirmHandEdit });
|
|
2549
|
+
break;
|
|
2550
|
+
case "clear":
|
|
2551
|
+
await this.clearGeneratedSetup();
|
|
2552
|
+
break;
|
|
2553
|
+
case "toggle":
|
|
2554
|
+
await this.setAutoroutingEnabled(selection.intent.enabled);
|
|
2555
|
+
break;
|
|
2556
|
+
}
|
|
2557
|
+
modelSelector.refreshSmartRoutingState();
|
|
2558
|
+
return;
|
|
2559
|
+
}
|
|
2295
2560
|
const isTrackedSingleAssignment =
|
|
2296
2561
|
selection.kind === "assignment" && selection.role !== null && selection.roles === undefined;
|
|
2297
2562
|
try {
|
|
@@ -2525,6 +2790,8 @@ export class SelectorController {
|
|
|
2525
2790
|
isFastForSubagentProvider: (provider, supportsServiceTier) =>
|
|
2526
2791
|
this.ctx.session.isFastForSubagentProvider(provider, supportsServiceTier),
|
|
2527
2792
|
isCurrentModelFastModeActive: () => this.ctx.session.isFastModeActive(),
|
|
2793
|
+
smartRoutingPreview: draft => this.previewSmartRouting(draft),
|
|
2794
|
+
smartRoutingOnly: options?.smartRoutingOnly,
|
|
2528
2795
|
},
|
|
2529
2796
|
);
|
|
2530
2797
|
return { component: modelSelector, focus: modelSelector };
|
|
@@ -3161,6 +3428,10 @@ export class SelectorController {
|
|
|
3161
3428
|
this.ctx.ui.setFocus(this.ctx.editor);
|
|
3162
3429
|
resolve(code);
|
|
3163
3430
|
};
|
|
3431
|
+
// The composer is reusable across overlays; detach it before
|
|
3432
|
+
// clearing so clear() disposes only the transient code input,
|
|
3433
|
+
// not the editor's tab-width listener (disposal is terminal).
|
|
3434
|
+
this.ctx.editorContainer.detachChild(this.ctx.editor);
|
|
3164
3435
|
this.ctx.editorContainer.clear();
|
|
3165
3436
|
this.ctx.editorContainer.addChild(codeInput);
|
|
3166
3437
|
this.ctx.ui.setFocus(codeInput);
|
|
@@ -3198,51 +3469,29 @@ export class SelectorController {
|
|
|
3198
3469
|
}
|
|
3199
3470
|
}
|
|
3200
3471
|
|
|
3201
|
-
async #
|
|
3472
|
+
async #handleLogout(providerId: string, targets?: readonly CredentialRemovalTarget[]): Promise<void> {
|
|
3202
3473
|
try {
|
|
3203
3474
|
const authStorage = this.ctx.session.modelRegistry.authStorage;
|
|
3204
|
-
const inventory = authStorage.listCredentialInventory(providerId);
|
|
3205
|
-
const oauthRows = inventory.filter(row => row.provider === providerId && row.credentialKind === "oauth");
|
|
3475
|
+
const inventory = authStorage.listCredentialInventory(providerId).filter(row => row.provider === providerId);
|
|
3206
3476
|
const removalTargetsById = new Map(
|
|
3207
3477
|
authStorage.listCredentialRemovalTargets(providerId).map(target => [target.id, target]),
|
|
3208
3478
|
);
|
|
3209
|
-
const
|
|
3479
|
+
const removable = inventory
|
|
3210
3480
|
.map(row => removalTargetsById.get(row.id))
|
|
3211
3481
|
.filter((target): target is CredentialRemovalTarget => target !== undefined);
|
|
3212
|
-
|
|
3482
|
+
// Credentials stored locally but not removable locally are broker-managed.
|
|
3483
|
+
if (inventory.length > 0 && removable.length === 0) {
|
|
3213
3484
|
this.ctx.showError(
|
|
3214
3485
|
`Logout is broker-managed for ${providerId}; run \`gjc auth-broker logout ${providerId}\` on the broker host.`,
|
|
3215
3486
|
);
|
|
3216
3487
|
return;
|
|
3217
3488
|
}
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
`No OAuth accounts to remove for ${providerId}; API-key credentials are not managed here.`,
|
|
3222
|
-
);
|
|
3223
|
-
return;
|
|
3224
|
-
}
|
|
3225
|
-
const result = authStorage.removeAuthCredentialsHard(providerId, targets);
|
|
3226
|
-
if (result.kind !== "removed") {
|
|
3227
|
-
this.ctx.showError(
|
|
3228
|
-
"Logout failed: account inventory changed; no credentials were removed. Retry /logout.",
|
|
3229
|
-
);
|
|
3230
|
-
return;
|
|
3231
|
-
}
|
|
3232
|
-
await clearPersistentPinForRemovedRows(this.ctx.settings, providerId, inventory, result.ids);
|
|
3233
|
-
await this.ctx.session.modelRegistry.refresh();
|
|
3234
|
-
this.ctx.showStatus(
|
|
3235
|
-
`Successfully removed ${result.ids.length} OAuth account${result.ids.length === 1 ? "" : "s"} from ${providerId}.`,
|
|
3236
|
-
);
|
|
3489
|
+
const selected = targets ? targets : removable;
|
|
3490
|
+
if (selected.length === 0) {
|
|
3491
|
+
this.ctx.showError(`No stored credentials to remove for ${providerId}.`);
|
|
3237
3492
|
return;
|
|
3238
3493
|
}
|
|
3239
|
-
|
|
3240
|
-
this.ctx.showError(
|
|
3241
|
-
`No OAuth accounts to remove for ${providerId}; API-key credentials are not managed here.`,
|
|
3242
|
-
);
|
|
3243
|
-
return;
|
|
3244
|
-
}
|
|
3245
|
-
const result = authStorage.removeAuthCredentialsHard(providerId, oauthRemovalTargets);
|
|
3494
|
+
const result = authStorage.removeAuthCredentialsHard(providerId, selected);
|
|
3246
3495
|
if (result.kind !== "removed") {
|
|
3247
3496
|
this.ctx.showError("Logout failed: account inventory changed; no credentials were removed. Retry /logout.");
|
|
3248
3497
|
return;
|
|
@@ -3250,7 +3499,7 @@ export class SelectorController {
|
|
|
3250
3499
|
await clearPersistentPinForRemovedRows(this.ctx.settings, providerId, inventory, result.ids);
|
|
3251
3500
|
await this.ctx.session.modelRegistry.refresh();
|
|
3252
3501
|
this.ctx.showStatus(
|
|
3253
|
-
`Successfully removed ${result.ids.length}
|
|
3502
|
+
`Successfully removed ${result.ids.length} stored credential${result.ids.length === 1 ? "" : "s"} from ${providerId}.`,
|
|
3254
3503
|
);
|
|
3255
3504
|
} catch (error: unknown) {
|
|
3256
3505
|
this.ctx.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -3273,11 +3522,11 @@ export class SelectorController {
|
|
|
3273
3522
|
const hasOAuthInventory = authStorage
|
|
3274
3523
|
.listCredentialInventory(selectedProviderId)
|
|
3275
3524
|
.some(row => row.provider === selectedProviderId && row.credentialKind === "oauth");
|
|
3276
|
-
const
|
|
3525
|
+
const hasRemovableCredential = authStorage
|
|
3277
3526
|
.listCredentialRemovalTargets(selectedProviderId)
|
|
3278
3527
|
.some(target => target.provider === selectedProviderId);
|
|
3279
|
-
if (mode === "logout" && hasOAuthInventory && !
|
|
3280
|
-
await this.#
|
|
3528
|
+
if (mode === "logout" && hasOAuthInventory && !hasRemovableCredential) {
|
|
3529
|
+
await this.#handleLogout(selectedProviderId);
|
|
3281
3530
|
return;
|
|
3282
3531
|
}
|
|
3283
3532
|
if (hasOAuthInventory && !options?.manualCode) {
|
|
@@ -3312,7 +3561,7 @@ export class SelectorController {
|
|
|
3312
3561
|
await this.#handleOAuthLogin(selectedProviderId, options);
|
|
3313
3562
|
},
|
|
3314
3563
|
onAccountRemove: async targets => {
|
|
3315
|
-
await this.#
|
|
3564
|
+
await this.#handleLogout(selectedProviderId, targets);
|
|
3316
3565
|
selector.stopValidation();
|
|
3317
3566
|
done();
|
|
3318
3567
|
},
|
|
@@ -3326,32 +3575,8 @@ export class SelectorController {
|
|
|
3326
3575
|
await this.#handleOAuthLogin(selectedProviderId, options);
|
|
3327
3576
|
return;
|
|
3328
3577
|
}
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
return;
|
|
3332
|
-
}
|
|
3333
|
-
this.showSelector(done => {
|
|
3334
|
-
let selector: OAuthSelectorComponent;
|
|
3335
|
-
selector = new OAuthSelectorComponent(
|
|
3336
|
-
"logout",
|
|
3337
|
-
authStorage,
|
|
3338
|
-
() => undefined,
|
|
3339
|
-
() => {
|
|
3340
|
-
selector.stopValidation();
|
|
3341
|
-
done();
|
|
3342
|
-
this.ctx.ui.requestRender();
|
|
3343
|
-
},
|
|
3344
|
-
{
|
|
3345
|
-
accountProviderId: selectedProviderId,
|
|
3346
|
-
onAccountRemove: async targets => {
|
|
3347
|
-
await this.#handleOAuthLogout(selectedProviderId, targets);
|
|
3348
|
-
selector.stopValidation();
|
|
3349
|
-
done();
|
|
3350
|
-
},
|
|
3351
|
-
},
|
|
3352
|
-
);
|
|
3353
|
-
return { component: selector, focus: selector };
|
|
3354
|
-
});
|
|
3578
|
+
// mode === "logout" with no OAuth accounts: remove stored api-key credentials directly.
|
|
3579
|
+
await this.#handleLogout(selectedProviderId);
|
|
3355
3580
|
return;
|
|
3356
3581
|
}
|
|
3357
3582
|
|
|
@@ -3662,6 +3887,10 @@ export class SelectorController {
|
|
|
3662
3887
|
this.ctx.ui.requestRender();
|
|
3663
3888
|
},
|
|
3664
3889
|
});
|
|
3890
|
+
// The composer is reusable across overlays; detach it before clearing so
|
|
3891
|
+
// clear() disposes only the transient overlay, not the editor's
|
|
3892
|
+
// tab-width listener / paste state (disposal is terminal).
|
|
3893
|
+
this.ctx.editorContainer.detachChild(this.ctx.editor);
|
|
3665
3894
|
this.ctx.editorContainer.clear();
|
|
3666
3895
|
this.ctx.editorContainer.addChild(overlay);
|
|
3667
3896
|
this.ctx.ui.setFocus(overlay.getFocus());
|
|
@@ -3692,6 +3921,10 @@ export class SelectorController {
|
|
|
3692
3921
|
},
|
|
3693
3922
|
});
|
|
3694
3923
|
unsubscribe = aggregator.onChange(() => this.#tasksPane?.refresh());
|
|
3924
|
+
// The composer is reusable across overlays; detach it before clearing so
|
|
3925
|
+
// clear() disposes only the transient pane, not the editor's
|
|
3926
|
+
// tab-width listener / paste state (disposal is terminal).
|
|
3927
|
+
this.ctx.editorContainer.detachChild(this.ctx.editor);
|
|
3695
3928
|
this.ctx.editorContainer.clear();
|
|
3696
3929
|
this.ctx.editorContainer.addChild(this.#tasksPane);
|
|
3697
3930
|
this.ctx.ui.setFocus(this.#tasksPane.getFocus());
|
|
@@ -1255,6 +1255,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1255
1255
|
this.ui.requestRender();
|
|
1256
1256
|
return true;
|
|
1257
1257
|
}
|
|
1258
|
+
hasPendingSubmission(): boolean {
|
|
1259
|
+
return this.#pendingSubmittedInput !== undefined;
|
|
1260
|
+
}
|
|
1258
1261
|
|
|
1259
1262
|
markPendingSubmissionStarted(input: SubmittedUserInput): boolean {
|
|
1260
1263
|
if (this.#pendingSubmittedInput !== input || input.cancelled) {
|
|
@@ -2348,10 +2351,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2348
2351
|
void this.#selectorController.showAgentsDashboard();
|
|
2349
2352
|
}
|
|
2350
2353
|
|
|
2351
|
-
showModelSelector(options?: { temporaryOnly?: boolean }): void {
|
|
2354
|
+
showModelSelector(options?: { temporaryOnly?: boolean; smartRoutingOnly?: boolean }): void {
|
|
2352
2355
|
this.#selectorController.showModelSelector(options);
|
|
2353
2356
|
}
|
|
2354
2357
|
|
|
2358
|
+
setAutoroutingEnabled(enabled: boolean): Promise<void> {
|
|
2359
|
+
return this.#selectorController.setAutoroutingEnabled(enabled);
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2355
2362
|
showEffortSelector(): void {
|
|
2356
2363
|
this.#selectorController.showEffortSelector();
|
|
2357
2364
|
}
|
|
@@ -9,7 +9,7 @@ export type WorkflowStage = "deep-interview" | "ralplan" | "ultragoal";
|
|
|
9
9
|
export const WORKFLOW_GATE_V1_STAGES: readonly WorkflowStage[] = ["deep-interview", "ralplan", "ultragoal"];
|
|
10
10
|
|
|
11
11
|
/** Reserved stage names that are explicitly not part of the v1 contract. */
|
|
12
|
-
export const RESERVED_WORKFLOW_STAGES: readonly string[] = ["
|
|
12
|
+
export const RESERVED_WORKFLOW_STAGES: readonly string[] = ["autoresearch"];
|
|
13
13
|
|
|
14
14
|
export type WorkflowGateKind = "question" | "approval" | "execution";
|
|
15
15
|
|
package/src/modes/types.ts
CHANGED
|
@@ -302,6 +302,13 @@ export interface InteractiveModeContext {
|
|
|
302
302
|
options?: ComposerSubmissionOptions,
|
|
303
303
|
): SubmittedUserInput;
|
|
304
304
|
cancelPendingSubmission(): boolean;
|
|
305
|
+
/**
|
|
306
|
+
* True while a submission is pending: not yet started, or started but still
|
|
307
|
+
* awaiting prompt delivery (`session.prompt()` has not flipped streaming yet).
|
|
308
|
+
* Interrupt handling uses this to keep a started-preflight submission
|
|
309
|
+
* cancellable instead of misclassifying its loader as stale (#4741).
|
|
310
|
+
*/
|
|
311
|
+
hasPendingSubmission(): boolean;
|
|
305
312
|
markPendingSubmissionStarted(input: SubmittedUserInput): boolean;
|
|
306
313
|
finishPendingSubmission(input: SubmittedUserInput): void;
|
|
307
314
|
/**
|
|
@@ -404,7 +411,8 @@ export interface InteractiveModeContext {
|
|
|
404
411
|
showExtensionsDashboard(): void;
|
|
405
412
|
showCustomizationDashboard(): void;
|
|
406
413
|
showAgentsDashboard(): void;
|
|
407
|
-
showModelSelector(options?: { temporaryOnly?: boolean }): void;
|
|
414
|
+
showModelSelector(options?: { temporaryOnly?: boolean; smartRoutingOnly?: boolean }): void;
|
|
415
|
+
setAutoroutingEnabled(enabled: boolean): Promise<void>;
|
|
408
416
|
showEffortSelector(): void;
|
|
409
417
|
showProviderOnboarding(): void;
|
|
410
418
|
showPluginSelector(mode?: "install" | "uninstall"): void;
|
|
@@ -43,7 +43,7 @@ Inspect relevant files, classify the task, identify resources/constraints/depend
|
|
|
43
43
|
- Codebase facts are backed by inspected files.
|
|
44
44
|
- Thin specs are expanded with explicit assumptions, additive options, missed sub-scope, and verification detail.
|
|
45
45
|
- Risks and verification commands are concrete.
|
|
46
|
-
- Handoff identifies when to use executor, architect, critic,
|
|
46
|
+
- Handoff identifies when to use executor, architect, critic, autoresearch, or ultragoal.
|
|
47
47
|
</success_criteria>
|
|
48
48
|
|
|
49
49
|
<output_contract>
|
|
@@ -28,7 +28,7 @@ Optimize for correctness first, maintainability second, and brevity third. Prefe
|
|
|
28
28
|
- Informational questions are answer-only/read-only unless the user explicitly requests a change, command, or execution.
|
|
29
29
|
- Vague or underspecified requirements: recommend `/skill:deep-interview` via `ask` (options: run the interview / proceed with stated assumptions) before mutating anything. Deep-interview is requirements-only and must not mutate product code. Its spec hands off as deep-interview → ralplan consensus → final receipt → approval or valid non-off runtime admission → separately authorized execution.
|
|
30
30
|
- Clear work with demonstrated architecture or sequencing risk suggests `/skill:ralplan --deliberate`; reconciliation must persist its final receipt before choosing approval or an admitted handoff. A valid non-off final runtime receipt enters the existing handoff chain; otherwise it stops pending approval.
|
|
31
|
-
- Use `/skill:ultragoal` for durable goal ledgers and `/skill:
|
|
31
|
+
- Use `/skill:ultragoal` for durable goal ledgers and `/skill:autoresearch` for goal-directed research missions that end on a structured verdict rather than an implementation.
|
|
32
32
|
- Delegate large implementation slices to `executor`; use `planner`, `architect`, or `critic` for bounded planning and review.
|
|
33
33
|
- An explicit user request to use a worktree (for example, "use worktree") overrides direct editing: delegate implementation through `task` with `isolated: true`. This is the in-session counterpart of launching `gjc --worktree`; if task isolation is unavailable, report that conflict instead of editing in the parent session.
|
|
34
34
|
- Active skills are authoritative: never ignore an invoked skill; read the full skill text and follow it exactly.
|
|
@@ -6,5 +6,6 @@ Working directory layout (sorted by mtime, recent first; depth ≤ 3):
|
|
|
6
6
|
(some entries elided to keep the tree short — use `find`/`read` to drill in)
|
|
7
7
|
{{/if}}
|
|
8
8
|
</workspace-tree>
|
|
9
|
-
{{/if}}Today is {{date}}, and the current working directory is '{{cwd}}'.
|
|
9
|
+
{{/if}}Today is {{date}}, the local time is {{localTime}}, and the current working directory is '{{cwd}}'.
|
|
10
|
+
Timestamps in files, logs, git history, and API responses are often UTC; convert timestamps that are explicitly UTC to the local timezone above when reporting times to the user. Preserve timestamps that already include an explicit offset or timezone, and do not treat this host wall clock as authenticated event-time evidence. The timezone follows the runtime's process timezone configuration (which may include project environment settings), so treat it as display context rather than trusted location evidence. The full IANA zone may reveal geographic information; do not infer more about the user than the displayed context states.
|
|
10
11
|
</system-reminder>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Rescope the session to a narrower working directory.
|
|
2
|
+
|
|
3
|
+
Use this only when the session's working directory is a broad launcher root (for example a
|
|
4
|
+
multi-repo workspace like `~/Projects`) and the task has clearly converged on one subdirectory
|
|
5
|
+
or repository: after this call, every later turn resolves relative paths and the bash default
|
|
6
|
+
cwd from the new directory, and project-scoped plugins/capabilities reload for it.
|
|
7
|
+
|
|
8
|
+
- `path` must be an existing directory; relative paths resolve against the current session cwd.
|
|
9
|
+
The canonical target must be strictly inside the current session directory — moves to a
|
|
10
|
+
parent, a sibling project, or an unrelated absolute path are refused.
|
|
11
|
+
- A session can be moved this way at most once, and never while another move is running; a
|
|
12
|
+
rejected call does not consume the move. Use it once the target repo is identified — not
|
|
13
|
+
speculatively — because the session file and caches move with the session.
|
|
14
|
+
- This tool is unavailable in subagent sessions and restricted profiles; ask the top-level
|
|
15
|
+
session to rescope instead.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Execute Python in a persistent per-session REPL kernel.
|
|
2
|
+
|
|
3
|
+
Variables, imports, and loaded data persist across calls in the current GJC session. The kernel runs in the session working directory. Each `execute` call is appended to a JSONL transcript under `.gjc/_session-{sessionid}/ipykernels/`; display artifacts are stored under `.gjc/_session-{sessionid}/ipykernels/artifacts/`.
|
|
4
|
+
|
|
5
|
+
## Actions
|
|
6
|
+
|
|
7
|
+
- `execute` (default) — run `code` in the persistent REPL. Requires `code`.
|
|
8
|
+
- `clear` — dispose this session's Python kernel. The next `execute` starts a fresh kernel with no retained state.
|
|
9
|
+
|
|
10
|
+
## Use
|
|
11
|
+
|
|
12
|
+
Use this tool for stateful Python work. It is distinct from `eval`: each has a separate kernel and owner, so state is not shared between them.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Discover project and user runtime skills without loading full skill content.
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
|
-
- Searches canonical GJC skill locations in precedence order: project `.gjc/skills` (ancestors from cwd to repo root, closest first), then user locations under the home directory: canonical `<config>/agent/skills`, configured legacy `<config>/skills`, and historical legacy `.gjc/skills`. `<config>` is the home-relative directory name from `GJC_CONFIG_DIR`, then `PI_CONFIG_DIR`, then `.gjc`; even an absolute-looking configured name is joined beneath `<home>`. Project scope shadows user scope; within a scope, earlier locations above win. Bundled GJC workflow skills (`deep-interview`, `ralplan`, `
|
|
4
|
+
- Searches canonical GJC skill locations in precedence order: project `.gjc/skills` (ancestors from cwd to repo root, closest first), then user locations under the home directory: canonical `<config>/agent/skills`, configured legacy `<config>/skills`, and historical legacy `.gjc/skills`. `<config>` is the home-relative directory name from `GJC_CONFIG_DIR`, then `PI_CONFIG_DIR`, then `.gjc`; even an absolute-looking configured name is joined beneath `<home>`. Project scope shadows user scope; within a scope, earlier locations above win. Bundled GJC workflow skills (`autoresearch`, `deep-interview`, `ralplan`, `ultragoal`) are always available and cannot be replaced by filesystem skills.
|
|
5
5
|
- Returns thin metadata only: name, description, source scope, path, and use conditions when present.
|
|
6
6
|
- Claude Code (`.claude/skills`) and Codex (`.codex/skills`) layouts are explicit import sources into `.gjc`, never invokable candidates. They are not returned as candidates; instead, each convention skill found in a trusted scope is reported in `diagnostics` with the exact copy command that enables it (copy into `.gjc/skills`), so a skill placed in a documented convention location is discoverable in a normal session without being silently loaded.
|
|
7
7
|
- Discovery is on by default in a normal session. When zero candidates are returned because discovery config is disabled (`skills.enabled` master switch, or `skills.trustProjectSkills` / `skills.trustUserSkills` scope trust), the result carries a `notice` explaining which setting blocked the search — an empty result without a `notice` means the searched scopes genuinely contain no matching skills.
|
|
@@ -6,10 +6,10 @@ Invoke another available skill in the current turn.
|
|
|
6
6
|
</conditions>
|
|
7
7
|
|
|
8
8
|
<instruction>
|
|
9
|
-
- `name` is the skill name as it appears in `/skill:<name>` (e.g. `ralplan`, `ultragoal`, `
|
|
9
|
+
- `name` is the skill name as it appears in `/skill:<name>` (e.g. `ralplan`, `ultragoal`, `autoresearch`, `deep-interview`)
|
|
10
10
|
- `args` is the free-form argument string the skill would receive after `/skill:<name>` on the command line
|
|
11
11
|
- The tool loads the callee's SKILL.md into the current turn and handles native workflow caller→callee state handoff when the caller is one of the built-in GJC workflows.
|
|
12
|
-
- The chain is refused while a native workflow caller is still
|
|
12
|
+
- The chain is refused while a native workflow caller is still mid-flight. `autoresearch` chains from any of its phases (`intake`/`research`/`verdict`) — a research mission is always handoff-ready. `deep-interview` chains once its final spec is persisted (phase `handoff`), and `ralplan` chains from `final` or `handoff`. Only a mid-flight `ralplan` or `ultragoal` needs preparation first: `gjc state <skill> write --input '{"current_phase":"handoff"}' --json`; no other handoff command is needed. Runtime project/user skills do not use `gjc state <skill>`.
|
|
13
13
|
- Call once per chain step. To chain `A → B → C`, A calls `skill(B)`; B's next agent turn calls `skill(C)`.
|
|
14
14
|
</instruction>
|
|
15
15
|
|