@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
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
|
|
3
|
+
export const SESSION_STAGING_DIRNAME = ".staging" as const;
|
|
4
|
+
|
|
5
|
+
/** True when a path is an immediate child of the reserved session staging directory. */
|
|
6
|
+
export function isStagedSessionPath(filePath: string): boolean {
|
|
7
|
+
return path.basename(path.dirname(path.resolve(filePath))) === SESSION_STAGING_DIRNAME;
|
|
8
|
+
}
|
|
@@ -21,7 +21,6 @@ When the goal is to hand GJC a whole workflow rather than micro-manage one promp
|
|
|
21
21
|
|
|
22
22
|
- `gjc_delegate_plan` — run consensus planning (`/skill:ralplan`) to a pending-approval plan.
|
|
23
23
|
- `gjc_delegate_execute` — run execution (`/skill:ultragoal`) to completion with verification.
|
|
24
|
-
- `gjc_delegate_team` — run parallel team execution (`/skill:team`) with internal tmux workers.
|
|
25
24
|
|
|
26
25
|
Each delegate starts (or reuses) a session, sends one workflow-tagged turn, and returns a durable `turn_id`. Pass `cwd` and `task`; set `allow_mutation: true` only when the bridge startup mutation class is enabled and the user has approved changes. Poll the returned `turn_id` with `{{TOOL_PREFIX}}_await_turn` or watch for the `delegation.started` event, exactly as with `send_prompt`. Drop to the manual start/send tools only for fine-grained control the delegate tools do not cover.
|
|
27
26
|
|
|
@@ -78,7 +78,7 @@ export function buildHostPluginSetup(host: HostPluginKind, flags: HostPluginSetu
|
|
|
78
78
|
installGuidance: [
|
|
79
79
|
`Add the local marketplace: /plugin marketplace add ${marketplaceRoot}`,
|
|
80
80
|
"Install the plugin: /plugin install gajae-code",
|
|
81
|
-
"Then call gjc_delegate_plan / gjc_delegate_execute
|
|
81
|
+
"Then call gjc_delegate_plan / gjc_delegate_execute from Claude Code.",
|
|
82
82
|
],
|
|
83
83
|
coordinatorConfigPreview: { command: "gjc", args: ["mcp-serve", "coordinator"], env },
|
|
84
84
|
mutationPolicy:
|
|
@@ -104,7 +104,7 @@ export function buildHostPluginSetup(host: HostPluginKind, flags: HostPluginSetu
|
|
|
104
104
|
installGuidance: [
|
|
105
105
|
`Add the local marketplace: codex plugin marketplace add ${marketplaceRoot}`,
|
|
106
106
|
"Install the plugin: codex plugin add gajae-code@gajae-code-local",
|
|
107
|
-
"Then call gjc_delegate_plan / gjc_delegate_execute
|
|
107
|
+
"Then call gjc_delegate_plan / gjc_delegate_execute from Codex.",
|
|
108
108
|
],
|
|
109
109
|
coordinatorConfigPreview: { command: "gjc", args: ["mcp-serve", "coordinator"], env },
|
|
110
110
|
mutationPolicy:
|
|
@@ -351,7 +351,7 @@ export function isCanonicalGjcWorkflowSkill(skill: string): skill is CanonicalGj
|
|
|
351
351
|
* rather than a generic synthetic compaction continuation.
|
|
352
352
|
*/
|
|
353
353
|
const CONTINUATION_INERT_WORKFLOW_PHASES: Readonly<Partial<Record<CanonicalGjcWorkflowSkill, ReadonlySet<string>>>> = {
|
|
354
|
-
|
|
354
|
+
autoresearch: new Set(["verdict"]),
|
|
355
355
|
};
|
|
356
356
|
|
|
357
357
|
/**
|
|
@@ -624,7 +624,7 @@ function dedupeVisibleBySkill(entries: SkillActiveEntry[], sessionId?: string):
|
|
|
624
624
|
* The planning pipeline advances one stage at a time: `deep-interview →
|
|
625
625
|
* ralplan → ultragoal`. Activating a downstream stage supersedes upstream
|
|
626
626
|
* stages so stale rows cannot keep owning the HUD, gate, or primary active
|
|
627
|
-
* snapshot. `
|
|
627
|
+
* snapshot. `autoresearch` is intentionally excluded — it runs alongside ultragoal —
|
|
628
628
|
* and every non-pipeline skill is left untouched.
|
|
629
629
|
*/
|
|
630
630
|
const PLANNING_PIPELINE_SKILLS = new Set<string>(["deep-interview", "ralplan", "ultragoal"]);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Native-free canonical GJC workflow skill identifiers. */
|
|
2
|
-
export const CANONICAL_GJC_WORKFLOW_SKILLS = ["deep-interview", "ralplan", "ultragoal", "
|
|
2
|
+
export const CANONICAL_GJC_WORKFLOW_SKILLS = ["deep-interview", "ralplan", "ultragoal", "autoresearch"] as const;
|
|
3
3
|
|
|
4
4
|
export type CanonicalGjcWorkflowSkill = (typeof CANONICAL_GJC_WORKFLOW_SKILLS)[number];
|
|
@@ -14,6 +14,6 @@ export function initialPhaseForSkill(skill: CanonicalGjcWorkflowSkill | string):
|
|
|
14
14
|
if (skill === "deep-interview") return "interviewing";
|
|
15
15
|
if (skill === "ultragoal") return "goal-planning";
|
|
16
16
|
if (skill === "ralplan") return "planner";
|
|
17
|
-
if (skill === "
|
|
17
|
+
if (skill === "autoresearch") return "intake";
|
|
18
18
|
return "planning";
|
|
19
19
|
}
|
|
@@ -53,21 +53,6 @@ interface UltragoalHudState extends WorkflowGateHudState {
|
|
|
53
53
|
updatedAt?: string;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
interface TeamHudWorker {
|
|
57
|
-
id: string;
|
|
58
|
-
status?: string;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface TeamHudState extends WorkflowGateHudState {
|
|
62
|
-
phase: string;
|
|
63
|
-
task_total: number;
|
|
64
|
-
task_counts: Record<string, number>;
|
|
65
|
-
workers: TeamHudWorker[];
|
|
66
|
-
updated_at?: string;
|
|
67
|
-
latestEvent?: { type?: string; worker?: string; message?: string };
|
|
68
|
-
latestMessage?: { from_worker?: string; body?: string };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
56
|
function percent(value: number | undefined): string | undefined {
|
|
72
57
|
if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
|
|
73
58
|
return `${Math.round(value * 100)}%`;
|
|
@@ -263,6 +248,47 @@ export function buildRalplanHudSummary(state: RalplanHudState): WorkflowHudSumma
|
|
|
263
248
|
};
|
|
264
249
|
}
|
|
265
250
|
|
|
251
|
+
export interface AutoresearchHudState extends WorkflowGateHudState {
|
|
252
|
+
phase: string;
|
|
253
|
+
mode?: string;
|
|
254
|
+
intake?: string;
|
|
255
|
+
slug?: string;
|
|
256
|
+
specPath?: string;
|
|
257
|
+
verdict?: string;
|
|
258
|
+
experimentCount?: number;
|
|
259
|
+
experimentStatuses?: string[];
|
|
260
|
+
updatedAt?: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function buildAutoresearchHudSummary(state: AutoresearchHudState): WorkflowHudSummary {
|
|
264
|
+
const statuses = state.experimentStatuses ?? [];
|
|
265
|
+
const total = Math.max(state.experimentCount ?? statuses.length, statuses.length);
|
|
266
|
+
const kept = statuses.filter(status => status === "keep").length;
|
|
267
|
+
const crash = statuses.filter(status => status === "crash").length;
|
|
268
|
+
const checksFailed = statuses.filter(status => status === "checks_failed").length;
|
|
269
|
+
const chips: Array<WorkflowHudChip | null> = [
|
|
270
|
+
...(state.phase === "verdict" ? [chip("verdict", state.verdict ?? "issued", 5)] : []),
|
|
271
|
+
chip("phase", state.phase, 10),
|
|
272
|
+
...(total > 0 ? [chip("exp", `${kept}/${total}`, 20)] : []),
|
|
273
|
+
crash > 0 ? { label: "crash", value: String(crash), priority: 4, severity: "warning" } : null,
|
|
274
|
+
checksFailed > 0
|
|
275
|
+
? { label: "checks_failed", value: String(checksFailed), priority: 5, severity: "warning" }
|
|
276
|
+
: null,
|
|
277
|
+
chip("mode", state.mode, 30),
|
|
278
|
+
chip("intake", state.intake, 40),
|
|
279
|
+
chip("spec", state.specPath, 45),
|
|
280
|
+
...gateChips(state, 50),
|
|
281
|
+
];
|
|
282
|
+
const visibleChips =
|
|
283
|
+
total === 0 && state.phase !== "verdict" ? compactChips([chip("phase", state.phase, 10)]) : compactChips(chips);
|
|
284
|
+
return {
|
|
285
|
+
version: 1,
|
|
286
|
+
...(state.slug ? { summary: `autoresearch mission ${state.slug}` } : {}),
|
|
287
|
+
chips: visibleChips,
|
|
288
|
+
...(state.updatedAt ? { updated_at: state.updatedAt } : {}),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
266
292
|
export function buildUltragoalHudSummary(state: UltragoalHudState): WorkflowHudSummary {
|
|
267
293
|
const total = state.goals.length;
|
|
268
294
|
const complete = state.counts.complete ?? 0;
|
|
@@ -288,29 +314,3 @@ export function buildUltragoalHudSummary(state: UltragoalHudState): WorkflowHudS
|
|
|
288
314
|
...(state.updatedAt ? { updated_at: state.updatedAt } : {}),
|
|
289
315
|
};
|
|
290
316
|
}
|
|
291
|
-
|
|
292
|
-
export function buildTeamHudSummary(state: TeamHudState): WorkflowHudSummary {
|
|
293
|
-
const failedWorkers = state.workers.filter(
|
|
294
|
-
worker => worker.status === "failed" || worker.status === "blocked",
|
|
295
|
-
).length;
|
|
296
|
-
const stoppedWorkers = state.workers.filter(worker => worker.status === "stopped").length;
|
|
297
|
-
const completed = state.task_counts.completed ?? 0;
|
|
298
|
-
const failedTasks = (state.task_counts.failed ?? 0) + (state.task_counts.blocked ?? 0);
|
|
299
|
-
const latest = state.latestEvent?.message ?? state.latestEvent?.type ?? state.latestMessage?.body;
|
|
300
|
-
return {
|
|
301
|
-
version: 1,
|
|
302
|
-
chips: compactChips([
|
|
303
|
-
failedWorkers > 0 || failedTasks > 0
|
|
304
|
-
? { label: "blocked", value: String(failedWorkers + failedTasks), priority: 5, severity: "blocked" }
|
|
305
|
-
: stoppedWorkers > 0
|
|
306
|
-
? { label: "stopped", value: String(stoppedWorkers), priority: 5, severity: "warning" }
|
|
307
|
-
: null,
|
|
308
|
-
chip("phase", state.phase, 10),
|
|
309
|
-
chip("workers", `${state.workers.length - failedWorkers}/${state.workers.length}`, 20),
|
|
310
|
-
chip("tasks", `${completed}/${state.task_total}`, 30),
|
|
311
|
-
...gateChips(state, 40),
|
|
312
|
-
chip("latest", latest, 70),
|
|
313
|
-
]),
|
|
314
|
-
...(state.updated_at ? { updated_at: state.updated_at } : {}),
|
|
315
|
-
};
|
|
316
|
-
}
|
|
@@ -3,6 +3,7 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import type { AgentTool } from "@gajae-code/agent-core";
|
|
5
5
|
import { logger } from "@gajae-code/utils";
|
|
6
|
+
import { isAutoresearchAuthorizedResearchPath } from "../autoresearch/git";
|
|
6
7
|
import { expandApplyPatchToEntries } from "../edit/modes/apply-patch";
|
|
7
8
|
import { GJC_SESSION_PREFIX, modeStatePath as sessionModeStatePath } from "../gjc-runtime/session-layout";
|
|
8
9
|
import { resolveGjcSessionForRead } from "../gjc-runtime/session-resolution";
|
|
@@ -26,10 +27,13 @@ export const RALPLAN_MUTATION_BLOCK_MESSAGE =
|
|
|
26
27
|
"Ralplan planning phase boundary: keep refining the consensus plan and persist plan artifacts through `gjc ralplan --write` (stage scratch files under a temp dir if needed). Product-code mutation tools and patch execution are blocked while ralplan is active; mutate only after the plan is approved and execution begins.";
|
|
27
28
|
export const ULTRAGOAL_GOAL_PLANNING_MUTATION_BLOCK_MESSAGE =
|
|
28
29
|
"Ultragoal goal-planning phase boundary: finish goal planning and record goals through `gjc ultragoal` before editing code. Product-code mutation tools and patch execution are blocked until goal planning completes and execution begins.";
|
|
30
|
+
export const AUTORESEARCH_MUTATION_BLOCK_MESSAGE =
|
|
31
|
+
"Autoresearch research-only boundary: this workflow produces findings, evidence, and a verdict — never product code. Product-code mutation tools and patch execution are blocked everywhere, on every branch. Mission research artifacts (`autoresearch.sh` at the workdir root and mission state through the sanctioned `gjc autoresearch` CLI) stay writable; run experiments through the `python` tool, or finish the mission and hand off to an approved implementation workflow.";
|
|
29
32
|
|
|
30
33
|
/** Resolve the phase-boundary block message for the active planning skill. */
|
|
31
34
|
function planningPhaseBlockMessage(skill: CanonicalGjcWorkflowSkill): string {
|
|
32
35
|
if (skill === "ralplan") return RALPLAN_MUTATION_BLOCK_MESSAGE;
|
|
36
|
+
if (skill === "autoresearch") return AUTORESEARCH_MUTATION_BLOCK_MESSAGE;
|
|
33
37
|
if (skill === "ultragoal") return ULTRAGOAL_GOAL_PLANNING_MUTATION_BLOCK_MESSAGE;
|
|
34
38
|
return DEEP_INTERVIEW_MUTATION_BLOCK_MESSAGE;
|
|
35
39
|
}
|
|
@@ -220,9 +224,12 @@ function modeStateMatchesContext(state: ModeState, sessionId?: string, threadId?
|
|
|
220
224
|
return true;
|
|
221
225
|
}
|
|
222
226
|
|
|
223
|
-
/**
|
|
224
|
-
|
|
225
|
-
|
|
227
|
+
/** Canonical workflow skills whose active posture gates product-code mutation. */
|
|
228
|
+
type MutationGatedSkill = "deep-interview" | "ralplan" | "ultragoal" | "autoresearch";
|
|
229
|
+
|
|
230
|
+
/** Workflow skills whose active posture this guard enforces against product-code mutation. */
|
|
231
|
+
function isPlanningSkill(skill: string): skill is MutationGatedSkill {
|
|
232
|
+
return skill === "deep-interview" || skill === "ralplan" || skill === "ultragoal" || skill === "autoresearch";
|
|
226
233
|
}
|
|
227
234
|
|
|
228
235
|
/**
|
|
@@ -233,14 +240,14 @@ function isPlanningSkill(skill: string): skill is "deep-interview" | "ralplan" |
|
|
|
233
240
|
* `ultragoal` only blocks during `goal-planning`; once goals are created it is an
|
|
234
241
|
* executor and mutates freely.
|
|
235
242
|
*/
|
|
236
|
-
function isBlockingPlanningPhase(skill:
|
|
243
|
+
function isBlockingPlanningPhase(skill: MutationGatedSkill, phase: string): boolean {
|
|
237
244
|
const normalized = phase.trim().toLowerCase();
|
|
238
245
|
if (skill === "ultragoal") return normalized === "goal-planning";
|
|
239
246
|
return !getSkillManifest(skill).stopReleasingPhases.includes(normalized);
|
|
240
247
|
}
|
|
241
248
|
|
|
242
249
|
interface ActivePlanningSkill {
|
|
243
|
-
skill:
|
|
250
|
+
skill: MutationGatedSkill;
|
|
244
251
|
phase: string;
|
|
245
252
|
}
|
|
246
253
|
|
|
@@ -251,7 +258,7 @@ interface ActivePlanningSkill {
|
|
|
251
258
|
* to `active:false`, which `listActiveSkills` already filters out). If several
|
|
252
259
|
* are momentarily active, prefer the most-recently-updated entry so a stale
|
|
253
260
|
* planning row (e.g. a still-active ralplan `final`) can never be selected over a
|
|
254
|
-
* newer executor (ultragoal/
|
|
261
|
+
* newer executor (ultragoal/autoresearch), and a planning *return* (newer `updated_at`)
|
|
255
262
|
* reliably wins. Ties fall back to the resolved top-level `skill`, then to the
|
|
256
263
|
* first entry, matching how the HUD/chain guard pick `activeSkills[0]`.
|
|
257
264
|
*/
|
|
@@ -1053,7 +1060,7 @@ function blockedWorkflowStateSkill(cwd: string, rawPath: string): CanonicalGjcWo
|
|
|
1053
1060
|
if (generatedRoot === "specs" || generatedRoot === "plans") return null;
|
|
1054
1061
|
if (generatedRoot !== "state") return null;
|
|
1055
1062
|
const fileName = segments.at(-1) ?? "";
|
|
1056
|
-
for (const skillName of ["deep-interview", "ralplan", "ultragoal"
|
|
1063
|
+
for (const skillName of ["deep-interview", "ralplan", "ultragoal"] as const) {
|
|
1057
1064
|
if (fileName === workflowModeStateFileName(skillName)) return skillName;
|
|
1058
1065
|
}
|
|
1059
1066
|
if (fileName === "skill-active-state.json") return "deep-interview";
|
|
@@ -1214,6 +1221,18 @@ export async function getWorkflowMutationDecision(
|
|
|
1214
1221
|
return { blocked: false, targets: [] };
|
|
1215
1222
|
}
|
|
1216
1223
|
if (input.forceOverride) return { blocked: false, targets: [] };
|
|
1224
|
+
// Autoresearch is research-only: it never edits product code, on any branch.
|
|
1225
|
+
// The only agent-writable surface is the mission's own research artifact —
|
|
1226
|
+
// the `autoresearch.sh` harness at the workdir root (mission state under
|
|
1227
|
+
// `.gjc/**` is runtime-owned and only the sanctioned CLI writes it). A branch
|
|
1228
|
+
// name is not authorization: an `autoresearch/*` branch isolates keep/discard
|
|
1229
|
+
// bookkeeping, it does not turn product edits into research.
|
|
1230
|
+
if (
|
|
1231
|
+
planning.skill === "autoresearch" &&
|
|
1232
|
+
targets.paths.every(p => isAutoresearchAuthorizedResearchPath(input.cwd, p))
|
|
1233
|
+
) {
|
|
1234
|
+
return { blocked: false, targets: targets.paths };
|
|
1235
|
+
}
|
|
1217
1236
|
const message = planningPhaseBlockMessage(planning.skill);
|
|
1218
1237
|
// Bash during a planning phase blocks only when a filesystem mutation was
|
|
1219
1238
|
// actually recognized. Inspection, reads, and CLI invocations the scanner does
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
} from "../setup/provider-onboarding";
|
|
45
45
|
import { parseThinkingLevel } from "../thinking";
|
|
46
46
|
import { getDisplayChangelogEntries } from "../utils/changelog";
|
|
47
|
+
import { buildAutoroutingStatusReport } from "./helpers/autorouting-status";
|
|
47
48
|
import { buildContextReportText } from "./helpers/context-report";
|
|
48
49
|
import { switchSessionCredentialCommand } from "./helpers/credential-switch";
|
|
49
50
|
import { buildFastStatusReport } from "./helpers/fast-status-report";
|
|
@@ -1117,6 +1118,82 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
1117
1118
|
runtime.ctx.editor.setText("");
|
|
1118
1119
|
},
|
|
1119
1120
|
},
|
|
1121
|
+
{
|
|
1122
|
+
name: "routing",
|
|
1123
|
+
description: "Show or set up sub-agent model autorouting",
|
|
1124
|
+
acpDescription: "Show or set up sub-agent model autorouting",
|
|
1125
|
+
inlineHint: "[on|off|status]",
|
|
1126
|
+
acpInputHint: "[on|off|status]",
|
|
1127
|
+
subcommands: [
|
|
1128
|
+
{ name: "on", description: "Enable autorouting" },
|
|
1129
|
+
{ name: "off", description: "Disable autorouting" },
|
|
1130
|
+
{ name: "status", description: "Show effective autorouting tiers" },
|
|
1131
|
+
],
|
|
1132
|
+
allowArgs: true,
|
|
1133
|
+
handle: async (command, runtime) => {
|
|
1134
|
+
const arg = command.args.trim().toLowerCase();
|
|
1135
|
+
if (arg === "on" || arg === "off") {
|
|
1136
|
+
try {
|
|
1137
|
+
// Mirror SelectorController#assertSmartRoutingWritable: the non-TUI (ACP/SDK)
|
|
1138
|
+
// dispatch path must honor the same scoped-session guard as the TUI controller,
|
|
1139
|
+
// otherwise a --models-scoped session can toggle routing through /routing on|off.
|
|
1140
|
+
if ((runtime.session.scopedModels?.length ?? 0) > 0) {
|
|
1141
|
+
throw new Error("Smart-routing settings are read-only in a --models-scoped session.");
|
|
1142
|
+
}
|
|
1143
|
+
runtime.settings.set("task.autorouting.enabled", arg === "on");
|
|
1144
|
+
} catch (err) {
|
|
1145
|
+
return usage(`Failed to change autorouting: ${errorMessage(err)}`, runtime);
|
|
1146
|
+
}
|
|
1147
|
+
await runtime.output(
|
|
1148
|
+
buildAutoroutingStatusReport({
|
|
1149
|
+
effective: runtime.settings.getEffectiveAutorouting(),
|
|
1150
|
+
tiers: runtime.settings.get("task.autorouting.tiers"),
|
|
1151
|
+
provenance: runtime.settings.get("task.autorouting.provenance"),
|
|
1152
|
+
}),
|
|
1153
|
+
);
|
|
1154
|
+
|
|
1155
|
+
return commandConsumed();
|
|
1156
|
+
}
|
|
1157
|
+
if (arg === "" || arg === "status") {
|
|
1158
|
+
await runtime.output(
|
|
1159
|
+
buildAutoroutingStatusReport({
|
|
1160
|
+
effective: runtime.settings.getEffectiveAutorouting(),
|
|
1161
|
+
tiers: runtime.settings.get("task.autorouting.tiers"),
|
|
1162
|
+
provenance: runtime.settings.get("task.autorouting.provenance"),
|
|
1163
|
+
}),
|
|
1164
|
+
);
|
|
1165
|
+
|
|
1166
|
+
return commandConsumed();
|
|
1167
|
+
}
|
|
1168
|
+
return usage("Usage: /routing [on|off|status]", runtime);
|
|
1169
|
+
},
|
|
1170
|
+
handleTui: async (command, runtime) => {
|
|
1171
|
+
const arg = command.args.trim().toLowerCase();
|
|
1172
|
+
runtime.ctx.editor.setText("");
|
|
1173
|
+
if (arg === "") {
|
|
1174
|
+
runtime.ctx.showModelSelector({ smartRoutingOnly: true });
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
if (arg === "on" || arg === "off") {
|
|
1178
|
+
// Route through the controller so the toggle honors the same
|
|
1179
|
+
// scoped-session and durable-config guards as the panel.
|
|
1180
|
+
await runtime.ctx.setAutoroutingEnabled(arg === "on");
|
|
1181
|
+
} else if (arg !== "status") {
|
|
1182
|
+
runtime.ctx.showStatus("Usage: /routing [on|off|status]");
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
const report = buildAutoroutingStatusReport({
|
|
1186
|
+
effective: runtime.ctx.settings.getEffectiveAutorouting(),
|
|
1187
|
+
tiers: runtime.ctx.settings.get("task.autorouting.tiers"),
|
|
1188
|
+
provenance: runtime.ctx.settings.get("task.autorouting.provenance"),
|
|
1189
|
+
});
|
|
1190
|
+
runtime.ctx.chatContainer.addChild(new Spacer(1));
|
|
1191
|
+
runtime.ctx.chatContainer.addChild(new DynamicBorder());
|
|
1192
|
+
runtime.ctx.chatContainer.addChild(new Text(report, 1, 0));
|
|
1193
|
+
runtime.ctx.chatContainer.addChild(new DynamicBorder());
|
|
1194
|
+
runtime.ctx.ui.requestRender();
|
|
1195
|
+
},
|
|
1196
|
+
},
|
|
1120
1197
|
{
|
|
1121
1198
|
name: "export",
|
|
1122
1199
|
priority: 50,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { replaceTabs, truncateToWidth } from "@gajae-code/tui";
|
|
2
|
+
import {
|
|
3
|
+
AUTOROUTING_TIERS,
|
|
4
|
+
type AutoroutingEffective,
|
|
5
|
+
type AutoroutingProvenance,
|
|
6
|
+
matchesRecordedTiersFingerprint,
|
|
7
|
+
validateAutoroutingProvenance,
|
|
8
|
+
} from "../../config/autorouting-contract";
|
|
9
|
+
import { validateDisplayLine } from "../../modes/components/ansi-display-validator";
|
|
10
|
+
|
|
11
|
+
/** Longest rendered chain/diagnostic before truncation. */
|
|
12
|
+
const MAX_STATUS_LINE_WIDTH = 200;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Selectors and diagnostics originate in user-editable config, so a hand-edited
|
|
16
|
+
* value can carry tabs or terminal control sequences. Strip them before the
|
|
17
|
+
* string reaches a renderer.
|
|
18
|
+
*/
|
|
19
|
+
function displaySafe(text: string): string {
|
|
20
|
+
return truncateToWidth(validateDisplayLine(replaceTabs(text)), MAX_STATUS_LINE_WIDTH);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type AutoroutingStatusSnapshot = {
|
|
24
|
+
effective: AutoroutingEffective;
|
|
25
|
+
tiers: unknown;
|
|
26
|
+
provenance: AutoroutingProvenance | undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** Render settings-derived autorouting state without consulting registry/auth. */
|
|
30
|
+
export function buildAutoroutingStatusReport(snapshot: AutoroutingStatusSnapshot): string {
|
|
31
|
+
const { effective, tiers, provenance } = snapshot;
|
|
32
|
+
if (!effective.active) {
|
|
33
|
+
const detail =
|
|
34
|
+
effective.issue?.detail ?? "Autorouting is disabled; every Task item uses manual model resolution.";
|
|
35
|
+
return `Autorouting: off\n${displaySafe(detail)}`;
|
|
36
|
+
}
|
|
37
|
+
const provenanceIssues = provenance === undefined ? [] : validateAutoroutingProvenance(provenance);
|
|
38
|
+
const malformed = provenanceIssues.length > 0;
|
|
39
|
+
const generated = !malformed && provenance !== undefined && matchesRecordedTiersFingerprint(provenance, tiers);
|
|
40
|
+
const label = malformed
|
|
41
|
+
? "hand-authored tiers"
|
|
42
|
+
: generated
|
|
43
|
+
? "generated"
|
|
44
|
+
: provenance === undefined
|
|
45
|
+
? "hand-authored tiers"
|
|
46
|
+
: "generated, hand-edited";
|
|
47
|
+
const lines = [`Autorouting: on (${label})`];
|
|
48
|
+
if (malformed) lines.push("Recorded generation provenance is invalid; treating tiers as hand-authored.");
|
|
49
|
+
for (const tier of AUTOROUTING_TIERS) {
|
|
50
|
+
const chain = effective.map[tier];
|
|
51
|
+
const rendered = chain && chain.length > 0 ? displaySafe(chain.join(" -> ")) : "(unmapped, falls back to manual)";
|
|
52
|
+
lines.push(` ${tier}: ${rendered}`);
|
|
53
|
+
}
|
|
54
|
+
return lines.join("\n");
|
|
55
|
+
}
|
package/src/system-prompt.ts
CHANGED
|
@@ -405,18 +405,116 @@ export interface BuildSystemPromptResult {
|
|
|
405
405
|
/** Context-file discovery warnings visible to SDK and session callers. */
|
|
406
406
|
warnings: string[];
|
|
407
407
|
}
|
|
408
|
+
/** Host wall-clock facts injected with every turn. */
|
|
409
|
+
export interface LocalTimeContext {
|
|
410
|
+
/** Local calendar date with weekday, e.g. `2026-08-19 (Wed)`. */
|
|
411
|
+
date: string;
|
|
412
|
+
/** Local clock time with UTC offset and IANA zone, e.g. `21:04 UTC+09:00 (Asia/Seoul)`. */
|
|
413
|
+
time: string;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Render the host's local date and clock time for the volatile turn context.
|
|
418
|
+
*
|
|
419
|
+
* Every field is derived from a single `Intl.DateTimeFormat` pass over one
|
|
420
|
+
* resolved zone, so the date, clock, offset, and zone name can never disagree
|
|
421
|
+
* with each other the way `Date`'s local getters can. Falls back to UTC only
|
|
422
|
+
* when the runtime has no usable ICU zone.
|
|
423
|
+
*
|
|
424
|
+
* @param timeZone IANA zone override. Default: the host zone.
|
|
425
|
+
*/
|
|
426
|
+
export function getLocalTimeContext(now: Date = new Date(), timeZone?: string): LocalTimeContext {
|
|
427
|
+
try {
|
|
428
|
+
const zone = timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
429
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
430
|
+
timeZone: zone,
|
|
431
|
+
year: "numeric",
|
|
432
|
+
month: "2-digit",
|
|
433
|
+
day: "2-digit",
|
|
434
|
+
weekday: "short",
|
|
435
|
+
hour: "2-digit",
|
|
436
|
+
minute: "2-digit",
|
|
437
|
+
hourCycle: "h23",
|
|
438
|
+
timeZoneName: "longOffset",
|
|
439
|
+
}).formatToParts(now);
|
|
440
|
+
const part = (type: Intl.DateTimeFormatPartTypes): string =>
|
|
441
|
+
parts.find(candidate => candidate.type === type)?.value ?? "";
|
|
442
|
+
const year = part("year");
|
|
443
|
+
const month = part("month");
|
|
444
|
+
const day = part("day");
|
|
445
|
+
const hour = part("hour");
|
|
446
|
+
const minute = part("minute");
|
|
447
|
+
if (!year || !month || !day || !hour || !minute) throw new Error("incomplete date parts");
|
|
448
|
+
// `longOffset` renders "GMT+09:00", or a bare "GMT" at zero offset.
|
|
449
|
+
const offset = part("timeZoneName").replace(/^GMT$/, "UTC+00:00").replace(/^GMT/, "UTC");
|
|
450
|
+
const weekday = part("weekday");
|
|
451
|
+
return {
|
|
452
|
+
date: weekday ? `${year}-${month}-${day} (${weekday})` : `${year}-${month}-${day}`,
|
|
453
|
+
time: `${hour}:${minute} ${offset}${zone ? ` (${zone})` : ""}`.trim(),
|
|
454
|
+
};
|
|
455
|
+
} catch (error) {
|
|
456
|
+
logger.warn("Could not resolve host timezone for volatile project context; falling back to UTC", {
|
|
457
|
+
error: String(error),
|
|
458
|
+
});
|
|
459
|
+
const fallbackNow = Number.isFinite(now.getTime()) ? now : new Date(0);
|
|
460
|
+
const iso = fallbackNow.toISOString();
|
|
461
|
+
return { date: iso.slice(0, 10), time: `${iso.slice(11, 16)} UTC+00:00 (UTC)` };
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
408
465
|
export interface BuildVolatileProjectContextOptions {
|
|
409
466
|
cwd?: string;
|
|
467
|
+
/** Clock source for the rendered local date/time. Default: `new Date()`. */
|
|
468
|
+
now?: Date;
|
|
469
|
+
/** Trusted/test-only override in the derived `YYYY-MM-DD (Www)` or `YYYY-MM-DD` format. */
|
|
410
470
|
date?: string;
|
|
471
|
+
/** Trusted/test-only override in the derived `HH:MM UTC±HH:MM (IANA/Zone)` format. */
|
|
472
|
+
localTime?: string;
|
|
411
473
|
workspaceTree?: WorkspaceTree;
|
|
412
474
|
}
|
|
413
475
|
|
|
476
|
+
const LOCAL_DATE_OVERRIDE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})(?: \(([A-Z][a-z]{2})\))?$/u;
|
|
477
|
+
const LOCAL_TIME_OVERRIDE_PATTERN =
|
|
478
|
+
/^(\d{2}):(\d{2}) UTC([+-])(\d{2}):(\d{2}) \(([A-Za-z0-9_+-]+(?:\/[A-Za-z0-9_+-]+)*)\)$/u;
|
|
479
|
+
|
|
480
|
+
function isValidLocalDateOverride(value: string): boolean {
|
|
481
|
+
const match = LOCAL_DATE_OVERRIDE_PATTERN.exec(value);
|
|
482
|
+
if (!match) return false;
|
|
483
|
+
const year = Number(match[1]);
|
|
484
|
+
const month = Number(match[2]);
|
|
485
|
+
const day = Number(match[3]);
|
|
486
|
+
const instant = new Date(Date.UTC(2000, month - 1, day));
|
|
487
|
+
instant.setUTCFullYear(year);
|
|
488
|
+
if (instant.getUTCFullYear() !== year || instant.getUTCMonth() !== month - 1 || instant.getUTCDate() !== day)
|
|
489
|
+
return false;
|
|
490
|
+
const weekday = match[4];
|
|
491
|
+
if (!weekday) return true;
|
|
492
|
+
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][instant.getUTCDay()] === weekday;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function isValidLocalTimeOverride(value: string): boolean {
|
|
496
|
+
const match = LOCAL_TIME_OVERRIDE_PATTERN.exec(value);
|
|
497
|
+
if (!match) return false;
|
|
498
|
+
const hour = Number(match[1]);
|
|
499
|
+
const minute = Number(match[2]);
|
|
500
|
+
const offsetHour = Number(match[4]);
|
|
501
|
+
const offsetMinute = Number(match[5]);
|
|
502
|
+
return hour < 24 && minute < 60 && offsetHour < 24 && offsetMinute < 60;
|
|
503
|
+
}
|
|
504
|
+
|
|
414
505
|
export function buildVolatileProjectContext(options: BuildVolatileProjectContextOptions = {}): string {
|
|
415
506
|
const resolvedCwd = options.cwd ?? getProjectDir();
|
|
416
|
-
const
|
|
507
|
+
const local = getLocalTimeContext(options.now ?? new Date());
|
|
508
|
+
const date = escapePromptMetadata(
|
|
509
|
+
options.date && isValidLocalDateOverride(options.date) ? options.date : local.date,
|
|
510
|
+
);
|
|
511
|
+
const localTime = escapePromptMetadata(
|
|
512
|
+
options.localTime && isValidLocalTimeOverride(options.localTime) ? options.localTime : local.time,
|
|
513
|
+
);
|
|
417
514
|
return prompt
|
|
418
515
|
.render(volatileProjectContextTemplate, {
|
|
419
516
|
date,
|
|
517
|
+
localTime,
|
|
420
518
|
cwd: escapePromptMetadata(shortenPath(resolvedCwd.replace(/\\/g, "/"))),
|
|
421
519
|
workspaceTree: {
|
|
422
520
|
...(options.workspaceTree ?? {
|
|
@@ -556,8 +654,9 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
556
654
|
}
|
|
557
655
|
}
|
|
558
656
|
|
|
559
|
-
|
|
560
|
-
|
|
657
|
+
// Date/time deliberately absent: volatile clock facts live in the per-turn
|
|
658
|
+
// volatile project context (see buildVolatileProjectContext), never in this
|
|
659
|
+
// cached stable prefix.
|
|
561
660
|
const promptCwd = shortenPath(resolvedCwd.replace(/\\/g, "/"));
|
|
562
661
|
|
|
563
662
|
// Build tool metadata for system prompt rendering
|
|
@@ -618,8 +717,6 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
618
717
|
workspaceTree,
|
|
619
718
|
rules: rules ?? [],
|
|
620
719
|
alwaysApplyRules: sanitizedAlwaysApplyRules,
|
|
621
|
-
date,
|
|
622
|
-
dateTime,
|
|
623
720
|
cwd: promptCwd,
|
|
624
721
|
intentTracing: !!intentField,
|
|
625
722
|
intentField: intentField ?? "",
|
package/src/task/discovery.ts
CHANGED
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
* Agent files use markdown with YAML frontmatter.
|
|
10
10
|
*/
|
|
11
11
|
import * as fs from "node:fs/promises";
|
|
12
|
-
import * as os from "node:os";
|
|
13
12
|
import * as path from "node:path";
|
|
14
|
-
import { logger } from "@gajae-code/utils";
|
|
13
|
+
import { getTrustedHomeDir, logger } from "@gajae-code/utils";
|
|
15
14
|
import { isProviderEnabled } from "../capability";
|
|
16
15
|
import { findAllNearestProjectConfigDirs, getConfigDirs } from "../config";
|
|
17
16
|
import type { Settings } from "../config/settings";
|
|
@@ -62,7 +61,7 @@ async function loadAgentsFromDir(dir: string, source: AgentSource): Promise<Agen
|
|
|
62
61
|
*/
|
|
63
62
|
export async function discoverAgents(
|
|
64
63
|
cwd: string,
|
|
65
|
-
home: string =
|
|
64
|
+
home: string = getTrustedHomeDir(),
|
|
66
65
|
activeSettings?: Settings,
|
|
67
66
|
): Promise<DiscoveryResult> {
|
|
68
67
|
const resolvedCwd = path.resolve(cwd);
|