@gajae-code/coding-agent 0.11.11 → 0.12.1
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 +131 -4
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +83 -1
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/exa/mcp-client.d.ts +10 -1
- package/dist/types/exec/bash-executor.d.ts +45 -12
- package/dist/types/extensibility/extensions/types.d.ts +38 -4
- package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
- package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
- package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
- package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
- package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +70 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +27 -1
- package/dist/types/gjc-runtime/team-store.d.ts +12 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +17 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +10 -19
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/session-observer-overlay.d.ts +22 -0
- package/dist/types/modes/components/settings-selector.d.ts +11 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/index.d.ts +44 -1
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +44 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
- package/dist/types/sdk/bus/reconciliation-store.d.ts +69 -0
- package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
- package/dist/types/sdk/bus/rich-render.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
- package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
- package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
- package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/prompt-status.d.ts +23 -3
- package/dist/types/sdk/session.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +82 -12
- package/dist/types/session/artifacts.d.ts +8 -0
- package/dist/types/session/blob-store.d.ts +57 -4
- package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +48 -19
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +96 -12
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -4
- package/dist/types/skill-state/workflow-hud.d.ts +9 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +7 -1
- package/dist/types/task/types.d.ts +23 -0
- package/dist/types/tools/ask-answer-registry.d.ts +2 -2
- package/dist/types/tools/bash-interactive.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +17 -1
- package/dist/types/tools/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/output-meta.d.ts +44 -3
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -7
- package/dist/types/tools/resource-gc.d.ts +4 -0
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/dist/types/utils/gh.d.ts +13 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +2 -0
- package/dist/types/web/search/providers/searxng.d.ts +7 -0
- package/dist/types/web/search/providers/xai.d.ts +2 -0
- package/package.json +11 -13
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/generate-sdk-operation-inventory.ts +5 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +285 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/async/job-manager.ts +78 -20
- package/src/capability/index.ts +8 -0
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- package/src/cli/read-cli.ts +2 -1
- package/src/cli.ts +1 -0
- package/src/commands/deep-interview.ts +29 -9
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/team.ts +20 -2
- package/src/config/file-lock.ts +11 -2
- package/src/config/model-registry.ts +21 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +74 -1
- package/src/config/settings.ts +246 -108
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +230 -82
- package/src/defaults/gjc/skills/ralplan/SKILL.md +77 -41
- package/src/defaults/gjc/skills/team/SKILL.md +3 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +62 -39
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- package/src/eval/py/executor.ts +7 -2
- package/src/exa/mcp-client.ts +12 -3
- package/src/exec/bash-executor.ts +144 -27
- package/src/extensibility/extensions/runner.ts +15 -0
- package/src/extensibility/extensions/types.ts +46 -5
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
- package/src/extensibility/gjc-plugins/index.ts +19 -2
- package/src/extensibility/gjc-plugins/installer.ts +189 -50
- package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
- package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
- package/src/extensibility/gjc-plugins/observability.ts +3 -3
- package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
- package/src/extensibility/gjc-plugins/schema.ts +84 -12
- package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
- package/src/extensibility/gjc-plugins/types.ts +141 -0
- package/src/extensibility/gjc-plugins/validation.ts +9 -0
- package/src/extensibility/shared-events.ts +5 -0
- package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
- package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
- package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
- package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
- package/src/gjc-runtime/deep-interview-state.ts +12 -943
- package/src/gjc-runtime/gc-render.ts +1 -0
- package/src/gjc-runtime/gc-runtime.ts +11 -1
- package/src/gjc-runtime/launch-tmux.ts +25 -6
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/gjc-runtime/ralplan-runtime.ts +1149 -98
- package/src/gjc-runtime/state-runtime.ts +2 -1
- package/src/gjc-runtime/state-writer.ts +70 -222
- package/src/gjc-runtime/team-launch.ts +42 -5
- package/src/gjc-runtime/team-runtime.ts +1085 -40
- package/src/gjc-runtime/team-store.ts +32 -0
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
- package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/gjc-runtime/team-workers.ts +1 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +28 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +414 -618
- package/src/gjc-runtime/workflow-manifest.generated.json +105 -449
- package/src/gjc-runtime/workflow-manifest.ts +38 -247
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/hooks/skill-state.ts +1 -23
- package/src/internal-urls/docs-index.generated.ts +21 -22
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/main.ts +9 -5
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +98 -0
- package/src/modes/acp/acp-agent.ts +339 -191
- package/src/modes/acp/acp-event-mapper.ts +14 -7
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +96 -28
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/session-observer-overlay.ts +457 -83
- package/src/modes/components/settings-selector.ts +116 -23
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/components/tool-status-header.ts +3 -14
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +4 -0
- package/src/modes/controllers/event-controller.ts +109 -27
- package/src/modes/controllers/extension-ui-controller.ts +26 -2
- package/src/modes/controllers/input-controller.ts +18 -3
- package/src/modes/controllers/selector-controller.ts +127 -36
- package/src/modes/interactive-mode.ts +62 -3
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/runtime-init.ts +22 -2
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +94 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/agents/architect.md +9 -1
- package/src/prompts/agents/critic.md +9 -0
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -5
- package/src/prompts/tools/bash.md +5 -5
- package/src/prompts/tools/read.md +4 -2
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/reminders/star-reminder.ts +4 -42
- package/src/runtime-mcp/manager.ts +19 -4
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/lifecycle.ts +25 -6
- package/src/sdk/broker/transport.ts +35 -3
- package/src/sdk/bus/attachment-registry.ts +5 -1
- package/src/sdk/bus/chat-daemon-cli.ts +4 -39
- package/src/sdk/bus/chat-daemon-control.ts +6 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/index.ts +984 -146
- package/src/sdk/bus/kind-aware-reconciliation.ts +317 -0
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/prompt-reconciliation.ts +2 -1
- package/src/sdk/bus/reconciliation-store.ts +303 -0
- package/src/sdk/bus/rich-draft.ts +1 -1
- package/src/sdk/bus/rich-render.ts +2 -2
- package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
- package/src/sdk/bus/telegram-cli.ts +33 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
- package/src/sdk/bus/telegram-daemon.ts +916 -23
- package/src/sdk/bus/telegram-reference.ts +40 -3
- package/src/sdk/bus/threaded-render.ts +48 -3
- package/src/sdk/bus/topic-registry.ts +20 -0
- package/src/sdk/host/control/dispatch.ts +5 -1
- package/src/sdk/host/control/operations.ts +1 -1
- package/src/sdk/host/host.ts +23 -1
- package/src/sdk/host/query/handlers.ts +55 -0
- package/src/sdk/host/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +51 -0
- package/src/sdk/protocol/operation-registry.ts +7 -2
- package/src/sdk/session.ts +101 -10
- package/src/session/agent-session.ts +1286 -220
- package/src/session/artifacts.ts +22 -0
- package/src/session/auth-broker-config.ts +10 -3
- package/src/session/blob-store.ts +915 -24
- package/src/session/internal/managed-session-scope.ts +44 -6
- package/src/session/internal/managed-session-storage.ts +48 -6
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +2364 -438
- package/src/session/session-storage.ts +9 -1
- package/src/session/streaming-output.ts +500 -111
- package/src/setup/credential-import.ts +75 -13
- package/src/setup/provider-onboarding.ts +19 -4
- package/src/skill-state/active-state.ts +32 -10
- package/src/skill-state/workflow-hud.ts +42 -2
- package/src/skill-state/workflow-mutation-guard.ts +560 -8
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +23 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +23 -7
- package/src/task/render.ts +6 -2
- package/src/task/types.ts +108 -0
- package/src/tools/ask-answer-registry.ts +12 -6
- package/src/tools/ask.ts +169 -118
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash-interactive.ts +8 -3
- package/src/tools/bash.ts +503 -60
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/fetch.ts +114 -23
- package/src/tools/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +4 -0
- package/src/tools/output-meta.ts +281 -20
- package/src/tools/path-utils.ts +8 -3
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1560 -310
- package/src/tools/resource-gc.ts +182 -18
- package/src/tools/review.ts +5 -7
- package/src/tools/search.ts +1 -0
- package/src/tools/subagent-render.ts +6 -2
- package/src/tools/subagent.ts +6 -0
- package/src/tools/telegram-send.ts +6 -3
- package/src/tools/tool-result.ts +14 -1
- package/src/utils/gh.ts +39 -0
- package/src/utils/image-resize.ts +3 -0
- package/src/web/search/providers/anthropic.ts +4 -4
- package/src/web/search/providers/codex.ts +1 -1
- package/src/web/search/providers/kimi.ts +15 -5
- package/src/web/search/providers/searxng.ts +47 -4
- package/src/web/search/providers/xai.ts +7 -2
- package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
- package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
- package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- package/src/gjc-runtime/deep-interview-draft.ts +0 -843
- package/src/gjc-runtime/deep-interview-payload.ts +0 -262
- package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
- package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
package/src/async/job-manager.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface AsyncJob {
|
|
|
32
32
|
promise: Promise<void>;
|
|
33
33
|
resultText?: string;
|
|
34
34
|
errorText?: string;
|
|
35
|
+
/** Safe, bounded cause when session setup failed before the LLM began work. */
|
|
36
|
+
setupFailureSummary?: string;
|
|
35
37
|
metadata?: AsyncJobMetadata;
|
|
36
38
|
/**
|
|
37
39
|
* Registry id of the agent that registered the job (e.g. "0-Main",
|
|
@@ -69,9 +71,12 @@ export interface AsyncJobMetadata {
|
|
|
69
71
|
* non-terminal and non-delivering: the run suspended at a safe boundary and the
|
|
70
72
|
* subagent can be resumed from its persisted sessionFile. `completed` always
|
|
71
73
|
* wins a race with a late pause because the run returns it once it has actually
|
|
72
|
-
* finished.
|
|
74
|
+
* finished. A `failed` outcome retains a safe setup diagnostic for receipt rendering.
|
|
73
75
|
*/
|
|
74
|
-
export type SubagentRunOutcome =
|
|
76
|
+
export type SubagentRunOutcome =
|
|
77
|
+
| { kind: "completed"; text: string }
|
|
78
|
+
| { kind: "failed"; text: string; setupFailureSummary?: string }
|
|
79
|
+
| { kind: "paused"; note?: string };
|
|
75
80
|
|
|
76
81
|
/** Canonical lifecycle of a subagent across pause/resume cycles. */
|
|
77
82
|
export type SubagentLifecycle = "running" | "paused" | "queued" | "completed" | "failed" | "cancelled";
|
|
@@ -146,7 +151,11 @@ export interface SubagentRecord {
|
|
|
146
151
|
historicalJobIds: string[];
|
|
147
152
|
status: SubagentLifecycle;
|
|
148
153
|
sessionFile: string | null;
|
|
149
|
-
/**
|
|
154
|
+
/**
|
|
155
|
+
* Explicit veto, not a complete availability result. False always denies;
|
|
156
|
+
* true still requires an owner-compatible descriptor or non-blank session
|
|
157
|
+
* file, followed by a separately available runner (`no_runner` otherwise).
|
|
158
|
+
*/
|
|
150
159
|
resumable: boolean;
|
|
151
160
|
queued?: { ownerId?: string; seq: number; message?: string; createdAt: number };
|
|
152
161
|
/** Resolved model the subagent was asked to use, e.g. "openai-codex/gpt-5.5". */
|
|
@@ -176,6 +185,22 @@ function sessionFileFromResumeDescriptorData(data: unknown): string | null {
|
|
|
176
185
|
return typeof sessionFile === "string" && sessionFile.trim().length > 0 ? sessionFile : null;
|
|
177
186
|
}
|
|
178
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Derive retained context from an already owner-compatible descriptor or a
|
|
190
|
+
* legacy session file. A descriptor is sufficient even when `sessionFile` is
|
|
191
|
+
* null because the descriptor is the payload the resume runner consumes.
|
|
192
|
+
*/
|
|
193
|
+
function hasRetainedResumeContext(input: {
|
|
194
|
+
resumable: boolean;
|
|
195
|
+
sessionFile: string | null;
|
|
196
|
+
descriptor: ResumeDescriptor | undefined;
|
|
197
|
+
}): boolean {
|
|
198
|
+
if (!input.resumable) return false;
|
|
199
|
+
return (
|
|
200
|
+
input.descriptor !== undefined || (typeof input.sessionFile === "string" && input.sessionFile.trim().length > 0)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
179
204
|
/** A pending resume awaiting a free concurrency slot. */
|
|
180
205
|
interface ResumeQueueEntry {
|
|
181
206
|
subagentId: string;
|
|
@@ -499,7 +524,7 @@ export class AsyncJobManager {
|
|
|
499
524
|
typeof result === "string" ? { kind: "completed", text: result } : result;
|
|
500
525
|
|
|
501
526
|
if (job.status === "cancelled") {
|
|
502
|
-
job.resultText = outcome.kind === "
|
|
527
|
+
job.resultText = outcome.kind === "paused" ? outcome.note : outcome.text;
|
|
503
528
|
this.#runLifecycle(id, "terminal", job);
|
|
504
529
|
this.#scheduleEviction(id);
|
|
505
530
|
this.#markRecordTerminal(id, "cancelled");
|
|
@@ -509,7 +534,7 @@ export class AsyncJobManager {
|
|
|
509
534
|
if (outcome.kind === "paused") {
|
|
510
535
|
// Sole canonical writer of the running -> paused transition. No
|
|
511
536
|
// delivery and no eviction scheduling: a paused subagent stays
|
|
512
|
-
// listed and resumable from its
|
|
537
|
+
// listed and resumable from its retained resume context.
|
|
513
538
|
job.status = "paused";
|
|
514
539
|
this.#freezeEndTime(job);
|
|
515
540
|
if (outcome.note) job.resultText = outcome.note;
|
|
@@ -517,6 +542,18 @@ export class AsyncJobManager {
|
|
|
517
542
|
this.#drainResumeQueue();
|
|
518
543
|
return;
|
|
519
544
|
}
|
|
545
|
+
if (outcome.kind === "failed") {
|
|
546
|
+
job.status = "failed";
|
|
547
|
+
job.setupFailureSummary = outcome.setupFailureSummary;
|
|
548
|
+
this.#freezeEndTime(job);
|
|
549
|
+
job.errorText = outcome.text;
|
|
550
|
+
this.#enqueueDelivery(id, outcome.text);
|
|
551
|
+
this.#runLifecycle(id, "terminal", job);
|
|
552
|
+
this.#scheduleEviction(id);
|
|
553
|
+
this.#markRecordTerminal(id, "failed");
|
|
554
|
+
this.#drainResumeQueue();
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
520
557
|
|
|
521
558
|
job.status = "completed";
|
|
522
559
|
this.#freezeEndTime(job);
|
|
@@ -684,7 +721,9 @@ export class AsyncJobManager {
|
|
|
684
721
|
historicalJobIds: [],
|
|
685
722
|
status: "completed",
|
|
686
723
|
sessionFile,
|
|
687
|
-
|
|
724
|
+
// The synthesized record copies this descriptor's owner, so the
|
|
725
|
+
// descriptor is owner-compatible with the record by construction.
|
|
726
|
+
resumable: hasRetainedResumeContext({ resumable: true, sessionFile, descriptor }),
|
|
688
727
|
};
|
|
689
728
|
this.#subagentRecords.set(record.subagentId, record);
|
|
690
729
|
return record;
|
|
@@ -765,13 +804,24 @@ export class AsyncJobManager {
|
|
|
765
804
|
}
|
|
766
805
|
|
|
767
806
|
/**
|
|
768
|
-
* Resolve
|
|
769
|
-
*
|
|
770
|
-
*
|
|
771
|
-
* without one.
|
|
807
|
+
* Resolve a descriptor only when `ownerId` matches the record by strict
|
|
808
|
+
* equality. Two undefined owners match; a distinguishably foreign descriptor
|
|
809
|
+
* is treated as absent for eligibility, runner selection, and execution.
|
|
772
810
|
*/
|
|
773
|
-
#
|
|
774
|
-
|
|
811
|
+
#descriptorForRecord(rec: SubagentRecord): ResumeDescriptor | undefined {
|
|
812
|
+
const descriptor = this.#resumeDescriptors.get(rec.subagentId);
|
|
813
|
+
return descriptor !== undefined && descriptor.ownerId === rec.ownerId ? descriptor : undefined;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Resolve the resume runner for a record and its already owner-compatible
|
|
818
|
+
* descriptor. Per-descriptor authority is unavailable when the descriptor is foreign.
|
|
819
|
+
*/
|
|
820
|
+
#resolveResumeRunner(rec: SubagentRecord, descriptor: ResumeDescriptor | undefined): ResumeRunner | undefined {
|
|
821
|
+
return (
|
|
822
|
+
(descriptor !== undefined ? this.#descriptorResumeRunners.get(rec.subagentId) : undefined) ??
|
|
823
|
+
this.#resumeRunner
|
|
824
|
+
);
|
|
775
825
|
}
|
|
776
826
|
|
|
777
827
|
getResumeDescriptor(subagentId: string, filter?: AsyncJobFilter): ResumeDescriptor | undefined {
|
|
@@ -1045,7 +1095,11 @@ export class AsyncJobManager {
|
|
|
1045
1095
|
return { ok: true, status: rec.status };
|
|
1046
1096
|
}
|
|
1047
1097
|
|
|
1048
|
-
/**
|
|
1098
|
+
/**
|
|
1099
|
+
* Resume a non-running subagent from retained context: an owner-compatible
|
|
1100
|
+
* descriptor or a legacy session file. Workflow routing keeps `not_found`,
|
|
1101
|
+
* `context_unavailable`, `no_runner`, and `resume_failed` distinct.
|
|
1102
|
+
*/
|
|
1049
1103
|
resumeSubagent(
|
|
1050
1104
|
subagentId: string,
|
|
1051
1105
|
filter?: AsyncJobFilter,
|
|
@@ -1066,8 +1120,11 @@ export class AsyncJobManager {
|
|
|
1066
1120
|
}
|
|
1067
1121
|
return { ok: false, status: "queued", reason: "already_queued" };
|
|
1068
1122
|
}
|
|
1069
|
-
|
|
1070
|
-
if (!
|
|
1123
|
+
const descriptor = this.#descriptorForRecord(rec);
|
|
1124
|
+
if (!hasRetainedResumeContext({ resumable: rec.resumable, sessionFile: rec.sessionFile, descriptor })) {
|
|
1125
|
+
return { ok: false, reason: "context_unavailable" };
|
|
1126
|
+
}
|
|
1127
|
+
if (!this.#resolveResumeRunner(rec, descriptor)) return { ok: false, reason: "no_runner" };
|
|
1071
1128
|
if (this.getRunningJobs().length >= this.#maxRunningJobs) {
|
|
1072
1129
|
const seq = ++this.#resumeSeq;
|
|
1073
1130
|
rec.status = "queued";
|
|
@@ -1081,12 +1138,13 @@ export class AsyncJobManager {
|
|
|
1081
1138
|
});
|
|
1082
1139
|
return { ok: true, queued: true, status: "queued" };
|
|
1083
1140
|
}
|
|
1084
|
-
return this.#startResume(rec, message);
|
|
1141
|
+
return this.#startResume(rec, message, descriptor);
|
|
1085
1142
|
}
|
|
1086
1143
|
|
|
1087
1144
|
#startResume(
|
|
1088
1145
|
rec: SubagentRecord,
|
|
1089
|
-
message
|
|
1146
|
+
message: string | undefined,
|
|
1147
|
+
descriptor: ResumeDescriptor | undefined,
|
|
1090
1148
|
): { ok: boolean; status?: SubagentLifecycle; jobId?: string; reason?: string } {
|
|
1091
1149
|
if (this.#isOwnerSubagentShutdownFenced(rec.ownerId)) {
|
|
1092
1150
|
return { ok: false, status: rec.status, reason: "owner_shutdown_in_progress" };
|
|
@@ -1095,8 +1153,8 @@ export class AsyncJobManager {
|
|
|
1095
1153
|
// Clear any retained progress from the previous run so a resumed subagent
|
|
1096
1154
|
// never renders the prior run's tool/output as live before it emits again.
|
|
1097
1155
|
this.#subagentProgress.delete(rec.subagentId);
|
|
1098
|
-
const runner = this.#resolveResumeRunner(rec
|
|
1099
|
-
const newJobId = runner?.(rec.subagentId, message,
|
|
1156
|
+
const runner = this.#resolveResumeRunner(rec, descriptor);
|
|
1157
|
+
const newJobId = runner?.(rec.subagentId, message, descriptor);
|
|
1100
1158
|
if (!newJobId) return { ok: false, reason: "resume_failed" };
|
|
1101
1159
|
if (prevJobId && prevJobId !== newJobId) rec.historicalJobIds.push(prevJobId);
|
|
1102
1160
|
rec.currentJobId = newJobId;
|
|
@@ -1122,7 +1180,7 @@ export class AsyncJobManager {
|
|
|
1122
1180
|
continue;
|
|
1123
1181
|
}
|
|
1124
1182
|
try {
|
|
1125
|
-
const result = this.#startResume(rec, entry.message);
|
|
1183
|
+
const result = this.#startResume(rec, entry.message, this.#descriptorForRecord(rec));
|
|
1126
1184
|
if (result.reason === "owner_shutdown_in_progress") {
|
|
1127
1185
|
index += 1;
|
|
1128
1186
|
continue;
|
package/src/capability/index.ts
CHANGED
|
@@ -259,10 +259,18 @@ export function initializeWithSettings(activeSettings: Settings): void {
|
|
|
259
259
|
for (const id of disabled) disabledProviders.add(id);
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
function assertDisabledProvidersWritable(activeSettings: Settings): void {
|
|
263
|
+
if (!activeSettings.canWriteDurableConfig()) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
"Cannot change settings while config.yml has invalid YAML syntax. Repair config.yml and reload settings.",
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
262
269
|
/**
|
|
263
270
|
* Persist current disabled providers to settings.
|
|
264
271
|
*/
|
|
265
272
|
function persistDisabledProviders(activeSettings: Settings, providers: ReadonlySet<string>): void {
|
|
273
|
+
assertDisabledProvidersWritable(activeSettings);
|
|
266
274
|
activeSettings.set("disabledProviders", Array.from(providers));
|
|
267
275
|
}
|
|
268
276
|
|
package/src/cli/fast-help.ts
CHANGED
|
@@ -93,7 +93,7 @@ Available Tools (default-enabled unless noted):
|
|
|
93
93
|
bash - Execute bash commands
|
|
94
94
|
edit - Edit files with find/replace
|
|
95
95
|
write - Write files (creates/overwrites)
|
|
96
|
-
|
|
96
|
+
search - Search file contents
|
|
97
97
|
find - Find files by glob pattern
|
|
98
98
|
lsp - Language server protocol (code intelligence)
|
|
99
99
|
python - Execute Python code (requires: ${APP_NAME} setup python)
|
package/src/cli/plugin-cli.ts
CHANGED
|
@@ -7,7 +7,19 @@
|
|
|
7
7
|
import { APP_NAME, getProjectDir } from "@gajae-code/utils";
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
import { resolveOrDefaultProjectRegistryPath } from "../discovery/helpers";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
applyGjcBundleUpdate,
|
|
12
|
+
bundleIdentity,
|
|
13
|
+
type GjcBundleIdentity,
|
|
14
|
+
type GjcBundleSummary,
|
|
15
|
+
GjcPluginLoadError,
|
|
16
|
+
getGjcBundle,
|
|
17
|
+
installGjcBundle,
|
|
18
|
+
isGjcPluginBundleSource,
|
|
19
|
+
isGjcPluginSourceShape,
|
|
20
|
+
listGjcBundles,
|
|
21
|
+
previewGjcBundleUpdate,
|
|
22
|
+
} from "../extensibility/gjc-plugins";
|
|
11
23
|
import { PluginManager, parseSettingValue, validateSetting } from "../extensibility/plugins";
|
|
12
24
|
import {
|
|
13
25
|
getInstalledPluginsRegistryPath,
|
|
@@ -312,9 +324,118 @@ async function handleDiscover(args: string[], _flags: PluginCommandArgs["flags"]
|
|
|
312
324
|
}
|
|
313
325
|
}
|
|
314
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Scope-qualified GJC bundle upgrade: re-resolve the stored source, review the
|
|
329
|
+
* candidate, then apply it as a compare-and-swap. `--dry-run` stops after the
|
|
330
|
+
* preview. Requires exactly one of `--user` / `--project` because (scope, name)
|
|
331
|
+
* is the canonical target.
|
|
332
|
+
*/
|
|
333
|
+
async function handleGjcUpgrade(name: string, flags: PluginCommandArgs["flags"]): Promise<void> {
|
|
334
|
+
if (flags.user === flags.project) {
|
|
335
|
+
console.error(chalk.red(`GJC bundle upgrade requires exactly one of --user or --project for "${name}".`));
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
const scope: "user" | "project" = flags.user ? "user" : "project";
|
|
339
|
+
const ctx = { cwd: getProjectDir() };
|
|
340
|
+
const identity = bundleIdentity(scope, name);
|
|
341
|
+
|
|
342
|
+
const emitError = (error: { code: string; message: string; recovery?: string }): never => {
|
|
343
|
+
if (flags.json) console.log(JSON.stringify({ error }, null, 2));
|
|
344
|
+
else {
|
|
345
|
+
console.error(chalk.red(`${theme.status.error} ${error.message}`));
|
|
346
|
+
if (error.recovery) console.error(chalk.dim(` Try: ${error.recovery}`));
|
|
347
|
+
}
|
|
348
|
+
process.exit(3);
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// Source re-resolution can throw with a cause carrying the raw locator, so
|
|
352
|
+
// the whole flow reports a stable code instead of the underlying error.
|
|
353
|
+
try {
|
|
354
|
+
await runGjcUpgrade(ctx, identity, name, scope, flags, emitError);
|
|
355
|
+
} catch (err) {
|
|
356
|
+
const reason = err instanceof GjcPluginLoadError ? err.code : "upgrade_failed";
|
|
357
|
+
console.error(chalk.red(`${theme.status.error} Failed to upgrade GJC bundle ${name} (${reason})`));
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function runGjcUpgrade(
|
|
363
|
+
ctx: { cwd: string },
|
|
364
|
+
identity: GjcBundleIdentity,
|
|
365
|
+
name: string,
|
|
366
|
+
scope: "user" | "project",
|
|
367
|
+
flags: PluginCommandArgs["flags"],
|
|
368
|
+
emitError: (error: { code: string; message: string; recovery?: string }) => never,
|
|
369
|
+
): Promise<void> {
|
|
370
|
+
const preview = await previewGjcBundleUpdate(ctx, identity);
|
|
371
|
+
if (!preview.ok) emitError(preview.error);
|
|
372
|
+
else if (flags.dryRun || !preview.value.changed) {
|
|
373
|
+
const { changed, candidateVersion, addedSurfaceIds, removedSurfaceIds } = preview.value;
|
|
374
|
+
if (flags.json) {
|
|
375
|
+
console.log(
|
|
376
|
+
JSON.stringify(
|
|
377
|
+
{
|
|
378
|
+
status: changed ? "update-available" : "up-to-date",
|
|
379
|
+
identity,
|
|
380
|
+
currentVersion: preview.value.current.version,
|
|
381
|
+
candidateVersion,
|
|
382
|
+
addedSurfaceIds,
|
|
383
|
+
removedSurfaceIds,
|
|
384
|
+
},
|
|
385
|
+
null,
|
|
386
|
+
2,
|
|
387
|
+
),
|
|
388
|
+
);
|
|
389
|
+
} else if (!changed) {
|
|
390
|
+
console.log(chalk.dim(`GJC bundle ${name} (${scope}) is up to date at ${preview.value.current.version}`));
|
|
391
|
+
} else {
|
|
392
|
+
console.log(
|
|
393
|
+
chalk.cyan(`[dry-run] ${name} (${scope}): ${preview.value.current.version} -> ${candidateVersion}`),
|
|
394
|
+
);
|
|
395
|
+
if (addedSurfaceIds.length > 0) console.log(chalk.dim(` + ${addedSurfaceIds.join(", ")}`));
|
|
396
|
+
if (removedSurfaceIds.length > 0) console.log(chalk.dim(` - ${removedSurfaceIds.join(", ")}`));
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
const applied = await applyGjcBundleUpdate(ctx, preview.value.token);
|
|
400
|
+
if (!applied.ok) emitError(applied.error);
|
|
401
|
+
else if (flags.json) {
|
|
402
|
+
console.log(
|
|
403
|
+
JSON.stringify(
|
|
404
|
+
{
|
|
405
|
+
status: applied.value.status,
|
|
406
|
+
bundle: applied.value.summary,
|
|
407
|
+
remnantCount: applied.value.remnantCount,
|
|
408
|
+
},
|
|
409
|
+
null,
|
|
410
|
+
2,
|
|
411
|
+
),
|
|
412
|
+
);
|
|
413
|
+
} else {
|
|
414
|
+
console.log(
|
|
415
|
+
chalk.green(
|
|
416
|
+
`${theme.status.success} ${applied.value.status} GJC bundle ${name}@${applied.value.summary.version} (${scope})`,
|
|
417
|
+
),
|
|
418
|
+
);
|
|
419
|
+
if (applied.value.remnantCount > 0) {
|
|
420
|
+
console.error(chalk.yellow(` ${applied.value.remnantCount} leftover directory could not be removed`));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
315
426
|
async function handleUpgrade(args: string[], flags: PluginCommandArgs["flags"]): Promise<void> {
|
|
316
|
-
const manager = await makeMarketplaceManager();
|
|
317
427
|
const pluginId = args[0];
|
|
428
|
+
// Scope-qualified GJC bundles upgrade through the lifecycle service, never
|
|
429
|
+
// through the marketplace manager.
|
|
430
|
+
if (pluginId && (flags.user || flags.project)) {
|
|
431
|
+
const scope: "user" | "project" = flags.user ? "user" : "project";
|
|
432
|
+
const existing = await getGjcBundle({ cwd: getProjectDir() }, bundleIdentity(scope, pluginId));
|
|
433
|
+
if (existing.ok) {
|
|
434
|
+
await handleGjcUpgrade(pluginId, flags);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const manager = await makeMarketplaceManager();
|
|
318
439
|
try {
|
|
319
440
|
if (pluginId) {
|
|
320
441
|
if (flags.scope) {
|
|
@@ -349,6 +470,15 @@ async function handleUpgrade(args: string[], flags: PluginCommandArgs["flags"]):
|
|
|
349
470
|
}
|
|
350
471
|
}
|
|
351
472
|
|
|
473
|
+
/**
|
|
474
|
+
* Stable, non-identifying reason for an install failure. The raw spec and the
|
|
475
|
+
* underlying cause can both carry credentials, a query string, or an absolute
|
|
476
|
+
* home path, so neither is ever printed.
|
|
477
|
+
*/
|
|
478
|
+
function describeInstallFailure(error: unknown): string {
|
|
479
|
+
return error instanceof GjcPluginLoadError ? error.code : "install_failed";
|
|
480
|
+
}
|
|
481
|
+
|
|
352
482
|
async function handleInstall(
|
|
353
483
|
manager: PluginManager,
|
|
354
484
|
packages: string[],
|
|
@@ -374,27 +504,52 @@ async function handleInstall(
|
|
|
374
504
|
const knownMarketplaces = new Set((await mktMgr.listMarketplaces()).map(m => m.name));
|
|
375
505
|
|
|
376
506
|
for (const spec of packages) {
|
|
377
|
-
// GJC
|
|
378
|
-
// git
|
|
379
|
-
|
|
507
|
+
// A GJC bundle is identified by the SHAPE of its source: a filesystem path,
|
|
508
|
+
// a git locator, or a tarball. npm and marketplace specs are never any of
|
|
509
|
+
// those, so shape alone separates the two worlds without resolving.
|
|
510
|
+
//
|
|
511
|
+
// Shape is checked BEFORE `isGjcPluginBundleSource`, which resolves the
|
|
512
|
+
// source: a deleted or unreachable GJC source fails that probe and would
|
|
513
|
+
// otherwise fall through to npm, losing the create-only refusal the
|
|
514
|
+
// lifecycle owes for an already-installed target.
|
|
515
|
+
if (isGjcPluginSourceShape(spec) || (await isGjcPluginBundleSource(spec))) {
|
|
380
516
|
if (flags.user === flags.project) {
|
|
381
517
|
console.error(
|
|
382
|
-
|
|
518
|
+
// The spec can carry credentials or an absolute home path, so name
|
|
519
|
+
// the missing flag instead of echoing it back.
|
|
520
|
+
chalk.red("GJC plugin bundle install requires exactly one of --user or --project."),
|
|
383
521
|
);
|
|
384
522
|
process.exit(1);
|
|
385
523
|
}
|
|
386
524
|
const scope: "user" | "project" = flags.user ? "user" : "project";
|
|
387
525
|
try {
|
|
388
|
-
const res = await
|
|
526
|
+
const res = await installGjcBundle({ cwd: getProjectDir() }, scope, spec);
|
|
527
|
+
if (!res.ok) {
|
|
528
|
+
const doc = {
|
|
529
|
+
error: { code: res.error.code, message: res.error.message, recovery: res.error.recovery },
|
|
530
|
+
};
|
|
531
|
+
if (flags.json) console.log(JSON.stringify(doc, null, 2));
|
|
532
|
+
else {
|
|
533
|
+
console.error(chalk.red(`${theme.status.error} ${res.error.message}`));
|
|
534
|
+
if (res.error.recovery) console.error(chalk.dim(` Try: ${res.error.recovery}`));
|
|
535
|
+
}
|
|
536
|
+
process.exit(3);
|
|
537
|
+
}
|
|
538
|
+
const { summary } = res.value;
|
|
389
539
|
if (flags.json) {
|
|
390
|
-
console.log(JSON.stringify({
|
|
540
|
+
console.log(JSON.stringify({ status: res.value.status, bundle: summary }, null, 2));
|
|
391
541
|
} else {
|
|
392
542
|
console.log(
|
|
393
|
-
chalk.green(
|
|
543
|
+
chalk.green(
|
|
544
|
+
`${theme.status.success} installed GJC plugin ${summary.identity.name}@${summary.version} (${scope})`,
|
|
545
|
+
),
|
|
394
546
|
);
|
|
395
547
|
}
|
|
396
548
|
} catch (err) {
|
|
397
|
-
|
|
549
|
+
// Never echo the raw spec or the underlying cause: either can carry
|
|
550
|
+
// credentials, a query string, or an absolute home path.
|
|
551
|
+
const reason = err instanceof GjcPluginLoadError ? err.code : "install_failed";
|
|
552
|
+
console.error(chalk.red(`${theme.status.error} Failed to install GJC bundle (${reason})`));
|
|
398
553
|
process.exit(1);
|
|
399
554
|
}
|
|
400
555
|
continue;
|
|
@@ -414,7 +569,9 @@ async function handleInstall(
|
|
|
414
569
|
),
|
|
415
570
|
);
|
|
416
571
|
} catch (err) {
|
|
417
|
-
|
|
572
|
+
// The spec can carry credentials, a query string, or an absolute home
|
|
573
|
+
// path, so report the failure without echoing it or the raw cause.
|
|
574
|
+
console.error(chalk.red(`${theme.status.error} Failed to install plugin (${describeInstallFailure(err)})`));
|
|
418
575
|
process.exit(1);
|
|
419
576
|
}
|
|
420
577
|
continue;
|
|
@@ -449,7 +606,9 @@ async function handleInstall(
|
|
|
449
606
|
}
|
|
450
607
|
}
|
|
451
608
|
} catch (err) {
|
|
452
|
-
|
|
609
|
+
// The spec can carry credentials, a query string, or an absolute home
|
|
610
|
+
// path, so report the failure without echoing it or the raw cause.
|
|
611
|
+
console.error(chalk.red(`${theme.status.error} Failed to install plugin (${describeInstallFailure(err)})`));
|
|
453
612
|
process.exit(1);
|
|
454
613
|
}
|
|
455
614
|
}
|
|
@@ -503,8 +662,7 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
|
|
|
503
662
|
const mktMgr = await makeMarketplaceManager();
|
|
504
663
|
const mktPlugins = await mktMgr.listInstalledPlugins();
|
|
505
664
|
const cwd = getProjectDir();
|
|
506
|
-
const [
|
|
507
|
-
const gjcBundles = [...gjcUser.plugins, ...gjcProject.plugins];
|
|
665
|
+
const gjcBundles: GjcBundleSummary[] = await listGjcBundles({ cwd });
|
|
508
666
|
|
|
509
667
|
if (flags.json) {
|
|
510
668
|
console.log(JSON.stringify({ npm: npmPlugins, marketplace: mktPlugins, gjc: gjcBundles }, null, 2));
|
|
@@ -559,9 +717,9 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
|
|
|
559
717
|
console.log(chalk.bold("GJC Plugin Bundles:\n"));
|
|
560
718
|
for (const plugin of gjcBundles) {
|
|
561
719
|
const status = plugin.enabled ? chalk.green(theme.status.enabled) : chalk.dim(theme.status.disabled);
|
|
562
|
-
const scopeLabel = chalk.dim(` (${plugin.scope})`);
|
|
563
|
-
const disabledCount = plugin.
|
|
564
|
-
const quarantineCount = plugin.
|
|
720
|
+
const scopeLabel = chalk.dim(` (${plugin.identity.scope})`);
|
|
721
|
+
const disabledCount = plugin.surfaces.filter(s => !s.enabled).length;
|
|
722
|
+
const quarantineCount = plugin.surfaces.filter(s => s.quarantined).length;
|
|
565
723
|
const detail = [
|
|
566
724
|
disabledCount > 0 ? `${disabledCount} disabled` : null,
|
|
567
725
|
quarantineCount > 0 ? `${quarantineCount} quarantined` : null,
|
|
@@ -569,7 +727,7 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
|
|
|
569
727
|
.filter((v): v is string => Boolean(v))
|
|
570
728
|
.join(", ");
|
|
571
729
|
console.log(
|
|
572
|
-
`${status} ${plugin.name}@${plugin.version}${scopeLabel}${detail ? chalk.dim(` — ${detail}`) : ""}`,
|
|
730
|
+
`${status} ${plugin.identity.name}@${plugin.version}${scopeLabel}${detail ? chalk.dim(` — ${detail}`) : ""}`,
|
|
573
731
|
);
|
|
574
732
|
}
|
|
575
733
|
}
|
package/src/cli/read-cli.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { renderError } from "../tools/tool-errors";
|
|
|
15
15
|
|
|
16
16
|
export interface ReadCommandArgs {
|
|
17
17
|
path: string;
|
|
18
|
+
truncation?: "head" | "last" | "both";
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export async function runReadCommand(cmd: ReadCommandArgs): Promise<void> {
|
|
@@ -37,7 +38,7 @@ export async function runReadCommand(cmd: ReadCommandArgs): Promise<void> {
|
|
|
37
38
|
const tool = wrapToolWithMetaNotice(new ReadTool(session));
|
|
38
39
|
|
|
39
40
|
try {
|
|
40
|
-
const result = await tool.execute("gjc-read", { path: cmd.path });
|
|
41
|
+
const result = await tool.execute("gjc-read", { path: cmd.path, truncation: cmd.truncation });
|
|
41
42
|
|
|
42
43
|
for (const block of result.content) {
|
|
43
44
|
if (block.type === "text") {
|
package/src/cli.ts
CHANGED
|
@@ -65,6 +65,7 @@ export const commands: CommandEntry[] = [
|
|
|
65
65
|
{ name: "migrate", load: () => import("./commands/migrate").then(m => m.default) },
|
|
66
66
|
{ name: "rlm", load: () => import("./commands/rlm").then(m => m.default) },
|
|
67
67
|
{ name: "update", load: () => import("./commands/update").then(m => m.default) },
|
|
68
|
+
{ name: "read", load: () => import("./commands/read").then(m => m.default) },
|
|
68
69
|
{ name: "plugin", load: () => import("./commands/plugin").then(m => m.default) },
|
|
69
70
|
{ name: "completion", load: () => import("./commands/completion").then(m => m.default) },
|
|
70
71
|
{ name: "launch", load: () => import("./commands/launch").then(m => m.default) },
|
|
@@ -2,8 +2,22 @@ import { Command, Flags } from "@gajae-code/utils/cli";
|
|
|
2
2
|
import { runNativeDeepInterviewCommand } from "../gjc-runtime/deep-interview-runtime";
|
|
3
3
|
|
|
4
4
|
export default class DeepInterview extends Command {
|
|
5
|
-
static description =
|
|
6
|
-
|
|
5
|
+
static description = `Run native GJC deep-interview workflow.
|
|
6
|
+
|
|
7
|
+
All deep-interview state operations go through this command — no gjc state needed:
|
|
8
|
+
read Print the persisted envelope, revision, content sha, and any pending draft
|
|
9
|
+
write One-shot incremental JSON merge into state (--reset replaces; the locked
|
|
10
|
+
intent contract survives a reset)
|
|
11
|
+
stage Stage one JSON transition draft (--for <transition> --input '<json>'|@file)
|
|
12
|
+
check Dry-run the staged draft against current state (same merge apply performs)
|
|
13
|
+
apply Commit the staged draft with runtime-owned revision+sha CAS
|
|
14
|
+
discard Remove the pending draft
|
|
15
|
+
clear Clear deep-interview state for the session (lifecycle passthrough)
|
|
16
|
+
handoff Hand off to the next workflow skill (lifecycle passthrough)
|
|
17
|
+
|
|
18
|
+
Ambiguity is runtime-owned: apply/write derive current_ambiguity from the latest valid scored
|
|
19
|
+
round and clamp it to the deterministic floor. Sessions resolve from --session-id, payload
|
|
20
|
+
session_id, or GJC_SESSION_ID.`;
|
|
7
21
|
static strict = false;
|
|
8
22
|
static flags = {
|
|
9
23
|
quick: Flags.boolean({ description: "Seed a quick deep-interview run" }),
|
|
@@ -15,6 +29,11 @@ export default class DeepInterview extends Command {
|
|
|
15
29
|
"session-id": Flags.string({
|
|
16
30
|
description: "Route state/spec handoff through a session-scoped .gjc/_session-{sessionid} directory",
|
|
17
31
|
}),
|
|
32
|
+
input: Flags.string({ description: "JSON payload (or @file) for the write/stage verbs" }),
|
|
33
|
+
for: Flags.string({
|
|
34
|
+
description: "Transition for stage: initialize-context | record-round | update-facts | merge-state",
|
|
35
|
+
}),
|
|
36
|
+
reset: Flags.boolean({ description: "With write: replace state instead of incremental merge" }),
|
|
18
37
|
write: Flags.boolean({ description: "Persist a final deep-interview spec through the sanctioned GJC CLI/API" }),
|
|
19
38
|
stage: Flags.string({ description: 'Spec stage for --write (currently "final")' }),
|
|
20
39
|
slug: Flags.string({ description: "Safe slug for .gjc/_session-{sessionid}/specs/deep-interview-<slug>.md" }),
|
|
@@ -27,13 +46,14 @@ export default class DeepInterview extends Command {
|
|
|
27
46
|
json: Flags.boolean({ description: "Output JSON" }),
|
|
28
47
|
};
|
|
29
48
|
static examples = [
|
|
30
|
-
'$ gjc deep-interview --trace --standard "<idea>"
|
|
31
|
-
"$ gjc deep-interview
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"$ gjc deep-interview
|
|
35
|
-
"$ gjc deep-interview
|
|
36
|
-
"$ gjc deep-interview
|
|
49
|
+
'$ gjc deep-interview --trace --standard "<idea>"',
|
|
50
|
+
"$ gjc deep-interview read --json",
|
|
51
|
+
'$ gjc deep-interview write --input \'{"state":{"threshold":0.05}}\' --json',
|
|
52
|
+
'$ gjc deep-interview stage --for record-round --input \'{"state":{"rounds":[{"round":1,"round_key":"r1"}]}}\' --json',
|
|
53
|
+
"$ gjc deep-interview check --json",
|
|
54
|
+
"$ gjc deep-interview apply --json",
|
|
55
|
+
"$ gjc deep-interview --write --stage final --slug my-feature --spec ./final-spec.md",
|
|
56
|
+
"$ gjc deep-interview --write --stage final --slug my-feature --spec ./final-spec.md --deliberate",
|
|
37
57
|
];
|
|
38
58
|
|
|
39
59
|
async run(): Promise<void> {
|
package/src/commands/harness.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
14
14
|
import * as fs from "node:fs/promises";
|
|
15
15
|
import * as path from "node:path";
|
|
16
16
|
import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
17
|
+
import { $credentialEnv } from "@gajae-code/utils/env";
|
|
17
18
|
import {
|
|
18
19
|
GJC_TMUX_OWNER_GENERATION_ENV,
|
|
19
20
|
GJC_TMUX_OWNER_SERVER_KEY_ENV,
|
|
@@ -565,20 +566,42 @@ function ownerIsolationPlatform(): NodeJS.Platform {
|
|
|
565
566
|
: "linux";
|
|
566
567
|
}
|
|
567
568
|
|
|
569
|
+
/**
|
|
570
|
+
* Operator override for the process-start probe command, resolved from trusted
|
|
571
|
+
* environment sources only.
|
|
572
|
+
*
|
|
573
|
+
* The result is spawned, so whatever can set it chooses which binary runs.
|
|
574
|
+
* `$env` merges the caller's `cwd/.env` into `process.env`, so reading it there
|
|
575
|
+
* would let repository content pick the command; resolve it the same way
|
|
576
|
+
* provider credentials are (launching shell plus GJC/user-owned `.env` files,
|
|
577
|
+
* never the project `.env`). A malformed override stays fatal rather than
|
|
578
|
+
* silently falling back to `ps`, matching the previous behavior.
|
|
579
|
+
*/
|
|
580
|
+
type ProcessStartCommandOverride = { kind: "none" } | { kind: "invalid" } | { kind: "command"; command: string[] };
|
|
581
|
+
|
|
582
|
+
function processStartCommandOverride(): ProcessStartCommandOverride {
|
|
583
|
+
const configured = $credentialEnv("GJC_HARNESS_PROCESS_START_COMMAND");
|
|
584
|
+
if (!configured) return { kind: "none" };
|
|
585
|
+
try {
|
|
586
|
+
const parsed = JSON.parse(configured) as unknown;
|
|
587
|
+
if (!Array.isArray(parsed) || parsed.length === 0 || parsed.some(value => typeof value !== "string" || !value))
|
|
588
|
+
return { kind: "invalid" };
|
|
589
|
+
return { kind: "command", command: parsed as string[] };
|
|
590
|
+
} catch {
|
|
591
|
+
return { kind: "invalid" };
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** Test seam: the process-start command override as resolved from trusted env. */
|
|
596
|
+
export function processStartCommandOverrideForTest(): ProcessStartCommandOverride {
|
|
597
|
+
return processStartCommandOverride();
|
|
598
|
+
}
|
|
599
|
+
|
|
568
600
|
function portableProcessStartTime(pid: number): string | null {
|
|
569
601
|
if (process.platform === "linux") return null;
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
try {
|
|
574
|
-
const parsed = JSON.parse(configured) as unknown;
|
|
575
|
-
if (!Array.isArray(parsed) || parsed.length === 0 || parsed.some(value => typeof value !== "string" || !value))
|
|
576
|
-
return null;
|
|
577
|
-
command = parsed;
|
|
578
|
-
} catch {
|
|
579
|
-
return null;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
602
|
+
const override = processStartCommandOverride();
|
|
603
|
+
if (override.kind === "invalid") return null;
|
|
604
|
+
const command: string[] = override.kind === "command" ? override.command : ["ps", "-o", "lstart=", "-p"];
|
|
582
605
|
const result = Bun.spawnSync([...command, String(pid)], {
|
|
583
606
|
stdout: "pipe",
|
|
584
607
|
stderr: "ignore",
|