@gajae-code/coding-agent 0.15.6 → 0.16.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 +99 -0
- package/dist/types/async/job-manager.d.ts +32 -1
- package/dist/types/browser-backend.d.ts +12 -0
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/root-flags.d.ts +14 -0
- package/dist/types/cli/update-cli.d.ts +14 -0
- package/dist/types/cli.d.ts +7 -0
- package/dist/types/commands/launch.d.ts +10 -0
- package/dist/types/commands/sdk.d.ts +2 -0
- package/dist/types/config/autorouting-tier-map.d.ts +24 -0
- package/dist/types/config/billing-path.d.ts +25 -0
- package/dist/types/config/config-schema-version.d.ts +13 -1
- package/dist/types/config/file-lock.d.ts +5 -0
- package/dist/types/config/model-registry.d.ts +22 -0
- package/dist/types/config/settings-schema.d.ts +27 -8
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/coordinator-mcp/projection-scan.d.ts +8 -0
- package/dist/types/crash/record-loader.d.ts +15 -0
- package/dist/types/extensibility/extensions/types.d.ts +8 -3
- package/dist/types/gjc-runtime/launch-worktree-reservation.d.ts +21 -0
- package/dist/types/gjc-runtime/launch-worktree.d.ts +25 -1
- package/dist/types/gjc-runtime/managed-owner-supervisor.d.ts +2 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +22 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +66 -1
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +1 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +27 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/master-mode/context.d.ts +21 -0
- package/dist/types/master-mode/first-request.d.ts +34 -0
- package/dist/types/master-mode/snapshot.d.ts +32 -0
- package/dist/types/modes/acp/acp-agent.d.ts +21 -21
- package/dist/types/modes/components/frictionless-onboarding-selector.d.ts +10 -0
- package/dist/types/modes/components/model-selector.d.ts +4 -0
- package/dist/types/modes/components/oauth-selector.d.ts +1 -0
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/components/sessions-dashboard.d.ts +2 -1
- package/dist/types/modes/components/status-line/model-name.d.ts +18 -0
- package/dist/types/modes/components/status-line/priority-row.d.ts +34 -0
- package/dist/types/modes/components/status-line/segments.d.ts +10 -0
- package/dist/types/modes/interactive-mode.d.ts +16 -2
- package/dist/types/modes/print-mode.d.ts +17 -0
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/ui-language.d.ts +7 -1
- package/dist/types/sdk/broker/broker.d.ts +79 -2
- package/dist/types/sdk/broker/endpoint-authority.d.ts +24 -0
- package/dist/types/sdk/broker/ensure.d.ts +3 -0
- package/dist/types/sdk/broker/index.d.ts +3 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +6 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +40 -0
- package/dist/types/sdk/broker/master-capability.d.ts +10 -0
- package/dist/types/sdk/broker/session-index.d.ts +40 -11
- package/dist/types/sdk/broker/session-scope.d.ts +72 -0
- package/dist/types/sdk/broker/spawn-authority.d.ts +201 -0
- package/dist/types/sdk/broker/spawn-substrate.d.ts +30 -0
- package/dist/types/sdk/broker/startup-budget.d.ts +52 -0
- package/dist/types/sdk/broker/state-version.d.ts +21 -1
- package/dist/types/sdk/broker/worktree-occupancy.d.ts +28 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +3 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/index.d.ts +9 -1
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +1 -1
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +1 -1
- package/dist/types/sdk/bus/slack-conversation.d.ts +1 -1
- package/dist/types/sdk/bus/slack-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
- package/dist/types/sdk/cli/index.d.ts +1 -0
- package/dist/types/sdk/cli/master-cli.d.ts +63 -0
- package/dist/types/sdk/cli/rows.d.ts +12 -5
- package/dist/types/sdk/cli/session-cli.d.ts +20 -3
- package/dist/types/sdk/client/client.d.ts +3 -2
- package/dist/types/sdk/host/control/dispatch.d.ts +10 -0
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +2 -0
- package/dist/types/sdk/host/control/runtime-gate.d.ts +21 -7
- package/dist/types/sdk/host/events.d.ts +1 -0
- package/dist/types/sdk/host/host.d.ts +10 -0
- package/dist/types/sdk/host/query/cursor.d.ts +4 -2
- package/dist/types/sdk/host/query/handlers.d.ts +1 -0
- package/dist/types/sdk/host/query/revision-store.d.ts +1 -0
- package/dist/types/sdk/host/session-runtime.d.ts +70 -17
- package/dist/types/sdk/lifecycle/broker-client.d.ts +6 -0
- package/dist/types/sdk/lifecycle/service.d.ts +15 -3
- package/dist/types/sdk/lifecycle-session.d.ts +3 -1
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -5
- package/dist/types/sdk/receipt-state.d.ts +2 -0
- package/dist/types/sdk/router/session-router.d.ts +6 -0
- package/dist/types/sdk/session.d.ts +16 -0
- package/dist/types/sdk/startup-capability.d.ts +2 -1
- package/dist/types/sdk/turn-result.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +52 -7
- package/dist/types/session/credential-store-errors.d.ts +1 -0
- package/dist/types/session/fold-coordinator.d.ts +29 -2
- package/dist/types/session/session-manager.d.ts +79 -2
- package/dist/types/session/yield-queue.d.ts +5 -4
- package/dist/types/setup/frictionless-onboarding.d.ts +1 -0
- package/dist/types/tools/ask.d.ts +1 -0
- package/dist/types/tools/bash.d.ts +16 -0
- package/dist/types/tools/browser/launch.d.ts +10 -0
- package/dist/types/tools/browser/registry.d.ts +8 -0
- package/dist/types/tools/gh.d.ts +8 -0
- package/dist/types/tools/index.d.ts +10 -10
- package/dist/types/tools/job.d.ts +3 -1
- package/dist/types/utils/external-editor.d.ts +7 -0
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/pirate.ts +7 -4
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +13 -1
- package/scripts/verify-gjc-sdk-canonicalization.ts +35 -1
- package/src/async/job-manager.ts +107 -9
- package/src/browser-backend.ts +29 -0
- package/src/cli/accounts-cli.ts +9 -5
- package/src/cli/args.ts +17 -0
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/plugin-cli.ts +29 -0
- package/src/cli/root-flags.ts +5 -0
- package/src/cli/update-cli.ts +140 -23
- package/src/commands/launch.ts +86 -18
- package/src/commands/sdk.ts +135 -28
- package/src/config/autorouting-tier-map.ts +12 -0
- package/src/config/billing-path.ts +42 -0
- package/src/config/config-schema-version.ts +18 -1
- package/src/config/file-lock.ts +158 -83
- package/src/config/model-preset-registry.ts +178 -23
- package/src/config/model-profiles.ts +5 -5
- package/src/config/model-registry.ts +291 -42
- package/src/config/model-resolver.ts +5 -0
- package/src/config/settings-schema.ts +27 -8
- package/src/config/settings.ts +51 -15
- package/src/coordinator-mcp/projection-scan.ts +27 -6
- package/src/coordinator-mcp/question-state.ts +9 -11
- package/src/coordinator-mcp/server.ts +115 -21
- package/src/crash/index-store.ts +2 -0
- package/src/crash/record-loader.ts +10 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/extensibility/extensions/runner.ts +27 -0
- package/src/extensibility/extensions/types.ts +8 -3
- package/src/extensibility/gjc-plugins/installer.ts +51 -11
- package/src/extensibility/runtime-skill-discovery.ts +110 -3
- package/src/extensibility/skills.ts +22 -12
- package/src/gjc-runtime/launch-worktree-reservation.ts +242 -0
- package/src/gjc-runtime/launch-worktree.ts +285 -4
- package/src/gjc-runtime/managed-owner-supervisor.ts +63 -51
- package/src/gjc-runtime/session-state-lock.ts +213 -14
- package/src/gjc-runtime/session-state-sidecar.ts +938 -39
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +4 -7
- package/src/gjc-runtime/tmux-owner-isolation.ts +18 -3
- package/src/gjc-runtime/tmux-sessions.ts +252 -13
- package/src/hooks/skill-state.ts +6 -0
- package/src/internal-urls/docs-index.generated.ts +15 -15
- package/src/internal-urls/issue-pr-protocol.ts +4 -2
- package/src/main.ts +61 -3
- package/src/master-mode/context.ts +50 -0
- package/src/master-mode/first-request.ts +65 -0
- package/src/master-mode/snapshot.ts +205 -0
- package/src/modes/acp/acp-agent.ts +610 -161
- package/src/modes/components/footer.ts +4 -2
- package/src/modes/components/frictionless-onboarding-selector.ts +48 -2
- package/src/modes/components/model-selector.ts +76 -8
- package/src/modes/components/oauth-selector.ts +6 -1
- package/src/modes/components/session-selector.ts +23 -15
- package/src/modes/components/sessions-dashboard.ts +8 -5
- package/src/modes/components/settings-selector.ts +1 -0
- package/src/modes/components/status-line/model-name.ts +53 -0
- package/src/modes/components/status-line/priority-row.ts +107 -0
- package/src/modes/components/status-line/segments.ts +23 -9
- package/src/modes/components/tool-status-header.ts +151 -15
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/event-controller.ts +30 -4
- package/src/modes/controllers/extension-ui-controller.ts +13 -13
- package/src/modes/controllers/input-controller.ts +30 -2
- package/src/modes/controllers/selector-controller.ts +200 -98
- package/src/modes/interactive-mode.ts +36 -12
- package/src/modes/print-mode.ts +64 -0
- package/src/modes/prompt-action-autocomplete.ts +30 -4
- package/src/modes/runtime-init.ts +12 -9
- package/src/modes/theme/theme.ts +5 -0
- package/src/modes/types.ts +2 -0
- package/src/modes/ui-language.ts +49 -2
- package/src/modes/utils/ui-helpers.ts +22 -3
- package/src/prompts/agent-fragments/browser-aside.md +22 -0
- package/src/prompts/system/master-mode.md +28 -0
- package/src/prompts/tools/ask.md +1 -1
- package/src/prompts/tools/bash.md +1 -0
- package/src/prompts/tools/job.md +1 -1
- package/src/sdk/acp/adapter.ts +5 -0
- package/src/sdk/broker/broker.ts +1646 -27
- package/src/sdk/broker/endpoint-authority.ts +86 -0
- package/src/sdk/broker/ensure.ts +81 -3
- package/src/sdk/broker/index.ts +3 -0
- package/src/sdk/broker/lifecycle-ledger.ts +6 -0
- package/src/sdk/broker/lifecycle.ts +440 -75
- package/src/sdk/broker/master-capability.ts +232 -0
- package/src/sdk/broker/session-index.ts +121 -17
- package/src/sdk/broker/session-scope.ts +272 -0
- package/src/sdk/broker/spawn-authority.ts +1031 -0
- package/src/sdk/broker/spawn-substrate.ts +591 -0
- package/src/sdk/broker/startup-budget.ts +144 -2
- package/src/sdk/broker/state-version.ts +43 -14
- package/src/sdk/broker/transport.ts +1 -0
- package/src/sdk/broker/worktree-occupancy.ts +90 -0
- package/src/sdk/bus/chat-daemon-control.ts +5 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +136 -18
- package/src/sdk/bus/discord-daemon.ts +50 -10
- package/src/sdk/bus/index.ts +84 -7
- package/src/sdk/bus/kind-aware-reconciliation.ts +296 -48
- package/src/sdk/bus/lifecycle-commands.ts +4 -0
- package/src/sdk/bus/notification-service.ts +22 -5
- package/src/sdk/bus/prompt-reconciliation.ts +7 -2
- package/src/sdk/bus/reconciliation-store.ts +55 -31
- package/src/sdk/bus/slack-conversation.ts +1 -1
- package/src/sdk/bus/slack-daemon.ts +72 -38
- package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
- package/src/sdk/cli/index.ts +1 -0
- package/src/sdk/cli/master-cli.ts +259 -0
- package/src/sdk/cli/rows.ts +41 -15
- package/src/sdk/cli/session-cli.ts +297 -26
- package/src/sdk/client/client.ts +14 -8
- package/src/sdk/host/control/dispatch.ts +101 -40
- package/src/sdk/host/control/index.ts +2 -0
- package/src/sdk/host/control/operations.ts +2 -0
- package/src/sdk/host/control/runtime-gate.ts +203 -11
- package/src/sdk/host/events.ts +1 -0
- package/src/sdk/host/host.ts +29 -2
- package/src/sdk/host/query/cursor.ts +52 -7
- package/src/sdk/host/query/handlers.ts +33 -12
- package/src/sdk/host/query/revision-store.ts +12 -0
- package/src/sdk/host/session-runtime.test.ts +673 -14
- package/src/sdk/host/session-runtime.ts +674 -103
- package/src/sdk/host/surface-policy.ts +3 -3
- package/src/sdk/lifecycle/broker-client.ts +28 -0
- package/src/sdk/lifecycle/service.ts +279 -20
- package/src/sdk/lifecycle-session.ts +17 -4
- package/src/sdk/prompt-deadline-manager.ts +2 -1
- package/src/sdk/protocol/operation-inventory.generated.json +105 -3
- package/src/sdk/protocol/operation-registry.ts +14 -4
- package/src/sdk/receipt-state.ts +10 -0
- package/src/sdk/router/session-router.ts +219 -118
- package/src/sdk/session.ts +416 -195
- package/src/sdk/startup-capability.ts +1 -0
- package/src/sdk/turn-result.ts +22 -0
- package/src/session/agent-session.ts +1628 -318
- package/src/session/blob-store.ts +15 -5
- package/src/session/credential-store-errors.ts +2 -0
- package/src/session/fold-coordinator.ts +40 -3
- package/src/session/internal/managed-session-storage.ts +153 -78
- package/src/session/session-manager.ts +850 -97
- package/src/session/yield-queue.ts +24 -10
- package/src/setup/frictionless-onboarding.ts +2 -0
- package/src/slash-commands/builtin-registry.ts +41 -0
- package/src/task/executor.ts +9 -4
- package/src/telemetry/events.ts +1138 -12
- package/src/tools/ask-contract.test.ts +64 -0
- package/src/tools/ask-contract.ts +36 -1
- package/src/tools/ask.ts +10 -8
- package/src/tools/bash-interactive.ts +11 -2
- package/src/tools/bash.ts +412 -75
- package/src/tools/browser/launch.ts +37 -0
- package/src/tools/browser/registry.ts +99 -9
- package/src/tools/cron.ts +6 -4
- package/src/tools/descriptors.test.ts +15 -0
- package/src/tools/descriptors.ts +5 -1
- package/src/tools/gh.ts +104 -48
- package/src/tools/github-cache.ts +2 -2
- package/src/tools/index.ts +10 -6
- package/src/tools/job.ts +4 -1
- package/src/tools/monitor.ts +12 -9
- package/src/tools/resolve.ts +30 -10
- package/src/tools/tool-catalog.generated.ts +2 -2
- package/src/utils/external-editor.ts +72 -1
|
@@ -52,6 +52,10 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
52
52
|
"slash_command:tutorial": "visual/local-only onboarding selector, not a user-facing SDK control seam",
|
|
53
53
|
"slash_command:transcript": "visual/local-only transcript viewer, not a user-facing SDK control seam",
|
|
54
54
|
"slash_command:sessions": "visual/local-only sessions dashboard, not a user-facing SDK control seam",
|
|
55
|
+
"slash_command:star":
|
|
56
|
+
"local transcript-discovery metadata command; no SDK operation counterpart or runtime/retention authority",
|
|
57
|
+
"slash_command:unstar":
|
|
58
|
+
"local transcript-discovery metadata command; no SDK operation counterpart or runtime/retention authority",
|
|
55
59
|
"agent_session:constructor": "internal accessor/plumbing, not a user-facing control seam",
|
|
56
60
|
"agent_session:getSessionAgentDir":
|
|
57
61
|
"internal session-scoped agent-directory accessor, not a user-facing SDK control seam",
|
|
@@ -107,6 +111,12 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
107
111
|
"agent_session:activeMidRunBarrierCountForTests": "read-only test seam, not a user-facing SDK control seam",
|
|
108
112
|
"agent_session:activeMidRunMaintenanceCountForTests": "read-only test seam, not a user-facing SDK control seam",
|
|
109
113
|
"agent_session:getPendingNextTurnMessagesForTests": "read-only test seam, not a user-facing SDK control seam",
|
|
114
|
+
"agent_session:queueCoordinatorRuntimeStatePersistForTests":
|
|
115
|
+
"test-only coordinator persistence ordering seam, not a user-facing SDK control seam",
|
|
116
|
+
"agent_session:parkAgentEndForCoordinatorPersistForTests":
|
|
117
|
+
"test-only parked terminal persistence seam, not a user-facing SDK control seam",
|
|
118
|
+
"agent_session:flushParkedAgentEndForCoordinatorPersistForTests":
|
|
119
|
+
"test-only parked terminal flush seam, not a user-facing SDK control seam",
|
|
110
120
|
"agent_session:setCancelAndSubmitAbortOutcomeProviderForTests":
|
|
111
121
|
"test-only cancellation seam, not a user-facing SDK control seam",
|
|
112
122
|
"agent_session:getAgentId": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -131,6 +141,7 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
131
141
|
"agent_session:hasForegroundBashBackgroundRequestHandler":
|
|
132
142
|
"internal accessor/plumbing, not a user-facing control seam",
|
|
133
143
|
"agent_session:requestForegroundBashBackground": "internal accessor/plumbing, not a user-facing SDK control seam",
|
|
144
|
+
"agent_session:onJobFold": "internal fold-event plumbing feeding the bash_folded event frame, not a control seam",
|
|
134
145
|
|
|
135
146
|
"agent_session:getSelectedMCPToolNames": "internal accessor/plumbing, not a user-facing control seam",
|
|
136
147
|
"agent_session:isToolDiscoveryEnabled": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -284,7 +295,7 @@ const SEAM_TO_SDK: Readonly<Record<string, string>> = {
|
|
|
284
295
|
"agent_session:cycleThinkingLevel": "thinking.cycle",
|
|
285
296
|
"agent_session:setSteeringMode": "queue.steering_mode.set",
|
|
286
297
|
"agent_session:setFollowUpMode": "queue.follow_up_mode.set",
|
|
287
|
-
"agent_session:
|
|
298
|
+
"agent_session:setToolInterruptPolicy": "queue.tool_interrupt_policy.set",
|
|
288
299
|
"agent_session:compact": "compaction.run",
|
|
289
300
|
"agent_session:setAutoCompactionEnabled": "compaction.auto.set",
|
|
290
301
|
"agent_session:setAutoRetryEnabled": "retry.auto.set",
|
|
@@ -296,6 +307,7 @@ const SEAM_TO_SDK: Readonly<Record<string, string>> = {
|
|
|
296
307
|
"agent_session:moveQueuedMessageForEditing": "queue.message.move",
|
|
297
308
|
"agent_session:executeBash": "bash.execute",
|
|
298
309
|
"agent_session:abortBash": "bash.abort",
|
|
310
|
+
"agent_session:requestForegroundBashBackgroundOutcome": "bash.background",
|
|
299
311
|
"agent_session:switchSession": "session.switch",
|
|
300
312
|
"agent_session:branch": "session.branch",
|
|
301
313
|
"agent_session:handoff": "session.handoff",
|
|
@@ -1567,6 +1567,24 @@ function isTypeOnlyTmuxPrimitiveOccurrence(contents: string, occurrence: TmuxPri
|
|
|
1567
1567
|
return /^\s*(?:export\s+)?type\b/.test(contents.slice(lineStart, lineEnd === -1 ? contents.length : lineEnd));
|
|
1568
1568
|
}
|
|
1569
1569
|
|
|
1570
|
+
function isExactTmuxSelfInjectionGuardVerb(
|
|
1571
|
+
file: string,
|
|
1572
|
+
contents: string,
|
|
1573
|
+
occurrence: TmuxPrimitiveOccurrence,
|
|
1574
|
+
): boolean {
|
|
1575
|
+
if (file !== "packages/coding-agent/src/tools/tmux-self-injection-guard.ts") return false;
|
|
1576
|
+
const declaration = 'const INPUT_VERBS = new Set(["send-keys", "paste-buffer", "send-prefix"]);';
|
|
1577
|
+
const declarationStart = contents.indexOf(declaration);
|
|
1578
|
+
if (declarationStart === -1 || contents.indexOf(declaration, declarationStart + 1) !== -1) return false;
|
|
1579
|
+
const references = [...contents.matchAll(/\bINPUT_VERBS\b/g)];
|
|
1580
|
+
if (references.length !== 2) return false;
|
|
1581
|
+
const guardUse = "INPUT_VERBS.has(invocation.verb)";
|
|
1582
|
+
const guardUseStart = contents.indexOf(guardUse);
|
|
1583
|
+
if (guardUseStart === -1 || contents.indexOf(guardUse, guardUseStart + 1) !== -1) return false;
|
|
1584
|
+
if (!references.some(reference => reference.index === guardUseStart)) return false;
|
|
1585
|
+
return occurrence.start >= declarationStart && occurrence.end <= declarationStart + declaration.length;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1570
1588
|
function tmuxMachineBusViolations(file: string, contents: string): string[] {
|
|
1571
1589
|
if (isGeneratedDocumentationIndex(file)) return [];
|
|
1572
1590
|
const allowedTeamFallbackRanges =
|
|
@@ -1581,7 +1599,8 @@ function tmuxMachineBusViolations(file: string, contents: string): string[] {
|
|
|
1581
1599
|
if (
|
|
1582
1600
|
isExactTeamFallback ||
|
|
1583
1601
|
isExactTmuxScrollCopyModeSendKeys(file, contents, occurrence) ||
|
|
1584
|
-
isTypeOnlyTmuxPrimitiveOccurrence(contents, occurrence)
|
|
1602
|
+
isTypeOnlyTmuxPrimitiveOccurrence(contents, occurrence) ||
|
|
1603
|
+
isExactTmuxSelfInjectionGuardVerb(file, contents, occurrence)
|
|
1585
1604
|
)
|
|
1586
1605
|
continue;
|
|
1587
1606
|
const detail =
|
|
@@ -3147,6 +3166,21 @@ fi
|
|
|
3147
3166
|
1,
|
|
3148
3167
|
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3149
3168
|
);
|
|
3169
|
+
await runSelfTestFixture(
|
|
3170
|
+
{
|
|
3171
|
+
"packages/coding-agent/src/tools/tmux-self-injection-guard.ts":
|
|
3172
|
+
'const INPUT_VERBS = new Set(["send-keys", "paste-buffer", "send-prefix"]);\nfunction guarded(invocation: { verb: string }): void { if (!INPUT_VERBS.has(invocation.verb)) return; }\n',
|
|
3173
|
+
},
|
|
3174
|
+
0,
|
|
3175
|
+
);
|
|
3176
|
+
await runSelfTestFixture(
|
|
3177
|
+
{
|
|
3178
|
+
"packages/coding-agent/src/tools/tmux-self-injection-guard.ts":
|
|
3179
|
+
'const INPUT_VERBS = new Set(["send-keys", "paste-buffer", "send-prefix"]);\nfunction guarded(invocation: { verb: string }): void { if (!INPUT_VERBS.has(invocation.verb)) return; }\nfor (const verb of INPUT_VERBS) Bun.spawnSync(["tmux", verb, "-t", pane, prompt]);\n',
|
|
3180
|
+
},
|
|
3181
|
+
1,
|
|
3182
|
+
"tmux send-keys content injection is outside sanctioned process lifecycle",
|
|
3183
|
+
);
|
|
3150
3184
|
await runSelfTestFixture(
|
|
3151
3185
|
{
|
|
3152
3186
|
"packages/coding-agent/src/gjc-runtime/team-runtime.ts":
|
package/src/async/job-manager.ts
CHANGED
|
@@ -68,9 +68,25 @@ export function jobElapsedMs(job: Pick<AsyncJob, "startTime" | "endTime">, now:
|
|
|
68
68
|
return Math.max(0, (job.endTime ?? now) - job.startTime);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Why a foreground wait left the foreground. Every fold path names its
|
|
73
|
+
* trigger so job snapshots and SDK clients can tell a user steer from the
|
|
74
|
+
* chord, the auto-background timer, or the explicit `bash.background` control.
|
|
75
|
+
*/
|
|
76
|
+
export type FoldReason = "steer" | "chord" | "timer" | "sdk_control";
|
|
77
|
+
|
|
78
|
+
/** A fold observed by the manager; published to SDK clients as `bash_folded`. */
|
|
79
|
+
export interface JobFoldEvent {
|
|
80
|
+
jobId: string;
|
|
81
|
+
generation: string;
|
|
82
|
+
reason: FoldReason;
|
|
83
|
+
}
|
|
84
|
+
|
|
71
85
|
export interface AsyncJobMetadata {
|
|
72
86
|
/** Set once a foreground wait has been folded, so surfacing can show folded work. */
|
|
73
87
|
backgrounded?: boolean;
|
|
88
|
+
/** Why a foreground wait was folded; absent for jobs started directly in the background (`async: true`). */
|
|
89
|
+
foldReason?: FoldReason;
|
|
74
90
|
subagent?: {
|
|
75
91
|
id: string;
|
|
76
92
|
agent: string;
|
|
@@ -271,6 +287,7 @@ interface AsyncJobDelivery {
|
|
|
271
287
|
label: string;
|
|
272
288
|
status: AsyncJob["status"];
|
|
273
289
|
backgrounded: boolean;
|
|
290
|
+
foldReason?: FoldReason;
|
|
274
291
|
text: string;
|
|
275
292
|
originalBytes?: number;
|
|
276
293
|
truncated?: boolean;
|
|
@@ -290,6 +307,7 @@ interface AsyncJobReceiptClaim {
|
|
|
290
307
|
label: string;
|
|
291
308
|
status: AsyncJob["status"];
|
|
292
309
|
backgrounded: boolean;
|
|
310
|
+
foldReason?: FoldReason;
|
|
293
311
|
ownerId?: string;
|
|
294
312
|
}
|
|
295
313
|
|
|
@@ -331,6 +349,8 @@ export interface AsyncJobSnapshotEntry {
|
|
|
331
349
|
status: AsyncJob["status"];
|
|
332
350
|
generation: string;
|
|
333
351
|
backgrounded: boolean;
|
|
352
|
+
/** Present when `backgrounded` was set by a fold; absent for direct background starts. */
|
|
353
|
+
foldReason?: FoldReason;
|
|
334
354
|
deliveryState: JobDeliveryState;
|
|
335
355
|
}
|
|
336
356
|
|
|
@@ -630,6 +650,7 @@ export class AsyncJobManager {
|
|
|
630
650
|
}
|
|
631
651
|
|
|
632
652
|
readonly #jobs = new Map<string, AsyncJob>();
|
|
653
|
+
#retainedDisposalCompletion: Promise<void> = Promise.resolve();
|
|
633
654
|
readonly #deliveries: AsyncJobDelivery[] = [];
|
|
634
655
|
readonly #inFlightDeliveries: AsyncJobDelivery[] = [];
|
|
635
656
|
readonly #suppressedDeliveries = new Set<string>();
|
|
@@ -653,7 +674,6 @@ export class AsyncJobManager {
|
|
|
653
674
|
readonly #maxDeadLetterOverflowOwners: number;
|
|
654
675
|
#deliveryLoop: Promise<void> | undefined;
|
|
655
676
|
#disposed = false;
|
|
656
|
-
#disposing = false;
|
|
657
677
|
#runningOwnerCleanups = false;
|
|
658
678
|
readonly #subagentRecords = new Map<string, SubagentRecord>();
|
|
659
679
|
readonly #terminalEvents = new Map<string, TerminalEvent>();
|
|
@@ -996,6 +1016,8 @@ export class AsyncJobManager {
|
|
|
996
1016
|
};
|
|
997
1017
|
}
|
|
998
1018
|
|
|
1019
|
+
readonly #foldListeners = new Set<(event: JobFoldEvent) => void>();
|
|
1020
|
+
|
|
999
1021
|
#notifyChange(): void {
|
|
1000
1022
|
for (const cb of this.#changeListeners) {
|
|
1001
1023
|
try {
|
|
@@ -2307,6 +2329,7 @@ export class AsyncJobManager {
|
|
|
2307
2329
|
status: job.status,
|
|
2308
2330
|
generation: job.generation,
|
|
2309
2331
|
backgrounded: job.metadata?.backgrounded === true,
|
|
2332
|
+
foldReason: job.metadata?.foldReason,
|
|
2310
2333
|
deliveryState,
|
|
2311
2334
|
};
|
|
2312
2335
|
});
|
|
@@ -2329,6 +2352,7 @@ export class AsyncJobManager {
|
|
|
2329
2352
|
status: delivery.status,
|
|
2330
2353
|
generation: delivery.generation,
|
|
2331
2354
|
backgrounded: delivery.backgrounded,
|
|
2355
|
+
foldReason: delivery.foldReason,
|
|
2332
2356
|
deliveryState: "pending",
|
|
2333
2357
|
});
|
|
2334
2358
|
}
|
|
@@ -2344,6 +2368,7 @@ export class AsyncJobManager {
|
|
|
2344
2368
|
status: delivery.status,
|
|
2345
2369
|
generation: delivery.generation,
|
|
2346
2370
|
backgrounded: delivery.backgrounded,
|
|
2371
|
+
foldReason: delivery.foldReason,
|
|
2347
2372
|
deliveryState: "pending",
|
|
2348
2373
|
});
|
|
2349
2374
|
}
|
|
@@ -2359,6 +2384,7 @@ export class AsyncJobManager {
|
|
|
2359
2384
|
status: claim.status,
|
|
2360
2385
|
generation: claim.generation,
|
|
2361
2386
|
backgrounded: claim.backgrounded,
|
|
2387
|
+
foldReason: claim.foldReason,
|
|
2362
2388
|
deliveryState: "pending",
|
|
2363
2389
|
});
|
|
2364
2390
|
}
|
|
@@ -2408,6 +2434,7 @@ export class AsyncJobManager {
|
|
|
2408
2434
|
label: job.label,
|
|
2409
2435
|
status: job.status,
|
|
2410
2436
|
backgrounded: job.metadata?.backgrounded === true,
|
|
2437
|
+
foldReason: job.metadata?.foldReason,
|
|
2411
2438
|
text,
|
|
2412
2439
|
attempt: 0,
|
|
2413
2440
|
nextAttemptAt: Date.now(),
|
|
@@ -2426,6 +2453,7 @@ export class AsyncJobManager {
|
|
|
2426
2453
|
label: job.label,
|
|
2427
2454
|
status: job.status,
|
|
2428
2455
|
backgrounded: job.metadata?.backgrounded === true,
|
|
2456
|
+
foldReason: job.metadata?.foldReason,
|
|
2429
2457
|
ownerId: job.ownerId,
|
|
2430
2458
|
});
|
|
2431
2459
|
this.#notifyChange();
|
|
@@ -2632,12 +2660,26 @@ export class AsyncJobManager {
|
|
|
2632
2660
|
}
|
|
2633
2661
|
|
|
2634
2662
|
/**
|
|
2635
|
-
*
|
|
2636
|
-
*
|
|
2663
|
+
* Subscribe to fold events. Fires once per successful `markBackgrounded`
|
|
2664
|
+
* transition (never on the idempotent repeat), so a subscriber can publish
|
|
2665
|
+
* exactly one `bash_folded` frame per fold. Listener errors are isolated.
|
|
2637
2666
|
*/
|
|
2638
|
-
|
|
2667
|
+
onFold(cb: (event: JobFoldEvent) => void): () => void {
|
|
2668
|
+
this.#foldListeners.add(cb);
|
|
2669
|
+
return () => {
|
|
2670
|
+
this.#foldListeners.delete(cb);
|
|
2671
|
+
};
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
/**
|
|
2675
|
+
* Mark a job that was launched directly in the background (`bash` with
|
|
2676
|
+
* `async: true`). It never had a foreground wait, so this is not a fold: no
|
|
2677
|
+
* `foldReason` is recorded and no fold listener fires.
|
|
2678
|
+
*/
|
|
2679
|
+
markStartedInBackground(jobId: string, generation: string): boolean {
|
|
2639
2680
|
const job = this.#jobs.get(jobId);
|
|
2640
2681
|
if (!job || job.generation !== generation) return false;
|
|
2682
|
+
if (job.metadata?.backgrounded === true) return true;
|
|
2641
2683
|
job.metadata = { ...job.metadata, backgrounded: true };
|
|
2642
2684
|
for (const delivery of [...this.#deliveries, ...this.#inFlightDeliveries]) {
|
|
2643
2685
|
if (delivery.jobId === jobId && delivery.generation === generation) delivery.backgrounded = true;
|
|
@@ -2646,6 +2688,37 @@ export class AsyncJobManager {
|
|
|
2646
2688
|
return true;
|
|
2647
2689
|
}
|
|
2648
2690
|
|
|
2691
|
+
/**
|
|
2692
|
+
* Mark a running job as backgrounded (folded out of its foreground call).
|
|
2693
|
+
* Read by getJobsSnapshot so folded work stays visible; safe to call twice.
|
|
2694
|
+
* The first transition records `reason` and notifies fold listeners; a
|
|
2695
|
+
* repeat keeps the original reason and emits nothing.
|
|
2696
|
+
*/
|
|
2697
|
+
markBackgrounded(jobId: string, generation: string, reason: FoldReason): boolean {
|
|
2698
|
+
const job = this.#jobs.get(jobId);
|
|
2699
|
+
if (!job || job.generation !== generation) return false;
|
|
2700
|
+
if (job.metadata?.backgrounded === true) return true;
|
|
2701
|
+
job.metadata = { ...job.metadata, backgrounded: true, foldReason: reason };
|
|
2702
|
+
for (const delivery of [...this.#deliveries, ...this.#inFlightDeliveries]) {
|
|
2703
|
+
if (delivery.jobId === jobId && delivery.generation === generation) {
|
|
2704
|
+
delivery.backgrounded = true;
|
|
2705
|
+
delivery.foldReason = reason;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
this.#notifyChange();
|
|
2709
|
+
const event: JobFoldEvent = { jobId, generation, reason };
|
|
2710
|
+
for (const cb of this.#foldListeners) {
|
|
2711
|
+
try {
|
|
2712
|
+
cb(event);
|
|
2713
|
+
} catch (error) {
|
|
2714
|
+
logger.warn("Async job fold listener failed", {
|
|
2715
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2716
|
+
});
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
return true;
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2649
2722
|
async waitForAll(): Promise<void> {
|
|
2650
2723
|
await Promise.all(Array.from(this.#jobs.values()).map(job => job.promise));
|
|
2651
2724
|
}
|
|
@@ -2707,6 +2780,17 @@ export class AsyncJobManager {
|
|
|
2707
2780
|
// registration keeps the original protection (cleanups cannot register fresh
|
|
2708
2781
|
// work) without disabling delivery. Errors in cleanups are logged, never
|
|
2709
2782
|
// escalated.
|
|
2783
|
+
const unsettledJobPromises = new Set<Promise<void>>();
|
|
2784
|
+
const jobIdsByPromise = new Map<Promise<void>, string>();
|
|
2785
|
+
for (const job of this.#jobs.values()) {
|
|
2786
|
+
const promise = job.promise;
|
|
2787
|
+
unsettledJobPromises.add(promise);
|
|
2788
|
+
jobIdsByPromise.set(promise, job.id);
|
|
2789
|
+
void promise.then(
|
|
2790
|
+
() => unsettledJobPromises.delete(promise),
|
|
2791
|
+
() => unsettledJobPromises.delete(promise),
|
|
2792
|
+
);
|
|
2793
|
+
}
|
|
2710
2794
|
this.#registrationClosed = true;
|
|
2711
2795
|
this.#clearEvictionTimers();
|
|
2712
2796
|
this.#runningOwnerCleanups = true;
|
|
@@ -2715,7 +2799,6 @@ export class AsyncJobManager {
|
|
|
2715
2799
|
} finally {
|
|
2716
2800
|
this.#runningOwnerCleanups = false;
|
|
2717
2801
|
}
|
|
2718
|
-
this.#disposing = true;
|
|
2719
2802
|
this.cancelAll();
|
|
2720
2803
|
for (const tombstone of this.#monitorTombstones.values()) {
|
|
2721
2804
|
try {
|
|
@@ -2734,13 +2817,22 @@ export class AsyncJobManager {
|
|
|
2734
2817
|
const remainingDeliveryMs = Math.max(0, disposalDeadline - Date.now());
|
|
2735
2818
|
const drained = await this.drainDeliveries({ timeoutMs: remainingDeliveryMs });
|
|
2736
2819
|
if (!drained) this.#projectUndeliveredDisposalFailures();
|
|
2737
|
-
const
|
|
2820
|
+
const retainedAuthority = new Set<Promise<void>>(unsettledJobPromises);
|
|
2821
|
+
for (const delivery of this.#inFlightDeliveries) {
|
|
2822
|
+
if (delivery.promise) retainedAuthority.add(delivery.promise);
|
|
2823
|
+
}
|
|
2824
|
+
this.#retainedDisposalCompletion = Promise.allSettled(retainedAuthority).then(() => {});
|
|
2825
|
+
const physicalStuckJobIds = [...unsettledJobPromises]
|
|
2826
|
+
.map(promise => jobIdsByPromise.get(promise))
|
|
2827
|
+
.filter((id): id is string => id !== undefined);
|
|
2828
|
+
const stuckJobIds = [...new Set([...waitResult.stuckJobIds, ...physicalStuckJobIds])];
|
|
2829
|
+
const disposalCompleted = waitResult.completed && drained && retainedAuthority.size === 0;
|
|
2738
2830
|
this.#lastDisposeDiagnostics = {
|
|
2739
|
-
stuckJobIds
|
|
2831
|
+
stuckJobIds,
|
|
2740
2832
|
deliveriesDrained: disposalCompleted,
|
|
2741
2833
|
};
|
|
2742
|
-
if (
|
|
2743
|
-
logger.warn("Async job manager dispose timed out waiting for jobs", { stuckJobIds
|
|
2834
|
+
if (stuckJobIds.length > 0) {
|
|
2835
|
+
logger.warn("Async job manager dispose timed out waiting for jobs", { stuckJobIds });
|
|
2744
2836
|
}
|
|
2745
2837
|
this.#clearEvictionTimers();
|
|
2746
2838
|
this.#disposed = true;
|
|
@@ -2772,9 +2864,14 @@ export class AsyncJobManager {
|
|
|
2772
2864
|
this.#ownerSubagentShutdownLeases.clear();
|
|
2773
2865
|
this.#notifyChange();
|
|
2774
2866
|
this.#changeListeners.clear();
|
|
2867
|
+
this.#foldListeners.clear();
|
|
2775
2868
|
return disposalCompleted;
|
|
2776
2869
|
}
|
|
2777
2870
|
|
|
2871
|
+
awaitRetainedDisposalCompletion(): Promise<void> {
|
|
2872
|
+
return this.#retainedDisposalCompletion;
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2778
2875
|
#projectUndeliveredDisposalFailures(): void {
|
|
2779
2876
|
const retained = [...this.#deliveries, ...this.#inFlightDeliveries];
|
|
2780
2877
|
for (const delivery of retained) {
|
|
@@ -3145,6 +3242,7 @@ export class AsyncJobManager {
|
|
|
3145
3242
|
label: job.label,
|
|
3146
3243
|
status: job.status,
|
|
3147
3244
|
backgrounded: job.metadata?.backgrounded === true,
|
|
3245
|
+
foldReason: job.metadata?.foldReason,
|
|
3148
3246
|
text: deliveryText.text,
|
|
3149
3247
|
originalBytes: deliveryText.originalBytes,
|
|
3150
3248
|
truncated: deliveryText.truncated,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import browserAsidePrompt from "./prompts/agent-fragments/browser-aside.md" with { type: "text" };
|
|
2
|
+
|
|
3
|
+
export type BrowserBackendId = "native" | "aside";
|
|
4
|
+
|
|
5
|
+
export interface BrowserBackend {
|
|
6
|
+
readonly id: BrowserBackendId;
|
|
7
|
+
readonly exposesBuiltinTool: boolean;
|
|
8
|
+
readonly developerInstructions?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface BrowserBackendSettingsSource {
|
|
12
|
+
get(key: string): unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const nativeBrowserBackend: BrowserBackend = {
|
|
16
|
+
id: "native",
|
|
17
|
+
exposesBuiltinTool: true,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const asideBrowserBackend: BrowserBackend = {
|
|
21
|
+
id: "aside",
|
|
22
|
+
exposesBuiltinTool: false,
|
|
23
|
+
developerInstructions: browserAsidePrompt.trim(),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** Resolve the configured browser backend. Aside is strictly opt-in. */
|
|
27
|
+
export function resolveBrowserBackend(settings: BrowserBackendSettingsSource): BrowserBackend {
|
|
28
|
+
return settings.get("browser.backend") === "aside" ? asideBrowserBackend : nativeBrowserBackend;
|
|
29
|
+
}
|
package/src/cli/accounts-cli.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type AuthStorage,
|
|
11
11
|
type CredentialInventoryRecord,
|
|
12
12
|
type CredentialRemovalTarget,
|
|
13
|
+
isSqliteCorruptionError,
|
|
13
14
|
OAuthCredentialSelectorError,
|
|
14
15
|
type OAuthPinTarget,
|
|
15
16
|
resolveOAuthStorageProvider,
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
checkAccountInventory,
|
|
24
25
|
clearPersistentPinForRemovedRows,
|
|
25
26
|
} from "../session/account-inventory";
|
|
27
|
+
import { CREDENTIAL_STORE_UNREADABLE_MESSAGE } from "../session/credential-store-errors";
|
|
26
28
|
import { resolveStartupAuthConfig, type StartupAuthConfigSnapshot } from "../session/startup-auth-config";
|
|
27
29
|
|
|
28
30
|
export const ACCOUNTS_ACTIONS = ["list", "check", "pin", "logout"] as const;
|
|
@@ -48,6 +50,7 @@ class AccountsCommandError extends Error {
|
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
export function toAccountsCommandError(error: unknown): AccountsCommandError | undefined {
|
|
53
|
+
if (isSqliteCorruptionError(error)) return new AccountsCommandError(CREDENTIAL_STORE_UNREADABLE_MESSAGE);
|
|
51
54
|
if (error instanceof OAuthCredentialSelectorError) return new AccountsCommandError(error.message);
|
|
52
55
|
return undefined;
|
|
53
56
|
}
|
|
@@ -391,16 +394,17 @@ export async function runAccountsCommand(cmd: AccountsCommandArgs): Promise<void
|
|
|
391
394
|
}
|
|
392
395
|
}
|
|
393
396
|
} catch (error) {
|
|
397
|
+
const normalizedError = toAccountsCommandError(error) ?? error;
|
|
394
398
|
if (cmd.flags.json) {
|
|
395
|
-
if (!(
|
|
396
|
-
process.stderr.write(`accounts command failed: ${cleanReason(
|
|
399
|
+
if (!(normalizedError instanceof AccountsCommandError)) {
|
|
400
|
+
process.stderr.write(`accounts command failed: ${cleanReason(normalizedError) ?? "Command failed."}\n`);
|
|
397
401
|
}
|
|
398
402
|
process.exitCode = 1;
|
|
399
|
-
writeJsonFailure(
|
|
403
|
+
writeJsonFailure(normalizedError);
|
|
400
404
|
return;
|
|
401
405
|
}
|
|
402
|
-
if (
|
|
403
|
-
process.stderr.write(`${
|
|
406
|
+
if (normalizedError instanceof AccountsCommandError) {
|
|
407
|
+
process.stderr.write(`${normalizedError.message}\n`);
|
|
404
408
|
process.exitCode = 1;
|
|
405
409
|
return;
|
|
406
410
|
}
|
package/src/cli/args.ts
CHANGED
|
@@ -84,6 +84,8 @@ export interface Args {
|
|
|
84
84
|
noRules?: boolean;
|
|
85
85
|
listModels?: string | true;
|
|
86
86
|
noTitle?: boolean;
|
|
87
|
+
master?: true;
|
|
88
|
+
masterScope?: "repo" | "pwd" | "global";
|
|
87
89
|
messages: string[];
|
|
88
90
|
fileArgs: string[];
|
|
89
91
|
/** Flags unknown to every launch parser; their consumer supplies the diagnostic. */
|
|
@@ -178,6 +180,17 @@ export function parseArgs(args: string[], authority: ParseArgsAuthority = "local
|
|
|
178
180
|
result.help = true;
|
|
179
181
|
} else if (arg === "--version" || arg === "-v") {
|
|
180
182
|
result.version = true;
|
|
183
|
+
} else if (arg === "--master") {
|
|
184
|
+
result.master = true;
|
|
185
|
+
} else if (arg === "--scope") {
|
|
186
|
+
const scope = takeFlagValue(args, i++, "--scope");
|
|
187
|
+
if (scope !== "repo" && scope !== "pwd" && scope !== "global") {
|
|
188
|
+
throw new CliParseError("invalid --scope value (expected repo, pwd, or global)");
|
|
189
|
+
}
|
|
190
|
+
if (result.masterScope !== undefined && result.masterScope !== scope) {
|
|
191
|
+
throw new CliParseError("--scope cannot be specified with conflicting values");
|
|
192
|
+
}
|
|
193
|
+
result.masterScope = scope;
|
|
181
194
|
} else if (arg === "--allow-home") {
|
|
182
195
|
result.allowHome = true;
|
|
183
196
|
} else if (arg === "--mode") {
|
|
@@ -371,6 +384,10 @@ export function parseArgs(args: string[], authority: ParseArgsAuthority = "local
|
|
|
371
384
|
}
|
|
372
385
|
}
|
|
373
386
|
|
|
387
|
+
if (result.masterScope !== undefined && result.master !== true) {
|
|
388
|
+
throw new CliParseError("--scope requires --master");
|
|
389
|
+
}
|
|
390
|
+
if (result.master === true && result.masterScope === undefined) result.masterScope = "repo";
|
|
374
391
|
if (result.default && !result.mpreset) {
|
|
375
392
|
throw new CliParseError("--default requires --mpreset <name>");
|
|
376
393
|
}
|
package/src/cli/fast-help.ts
CHANGED
|
@@ -79,6 +79,7 @@ Environment Variables:
|
|
|
79
79
|
|
|
80
80
|
# Configuration
|
|
81
81
|
GJC_CODING_AGENT_DIR - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)
|
|
82
|
+
GJC_UI_LANGUAGE - Explicit first-use onboarding language (en, ko, zh, or ja); invalid values use English without prompting
|
|
82
83
|
GJC_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
|
|
83
84
|
GJC_SMOL_MODEL - Override smol/fast model (see --smol)
|
|
84
85
|
GJC_SLOW_MODEL - Override slow/reasoning model (see --slow)
|
package/src/cli/plugin-cli.ts
CHANGED
|
@@ -886,11 +886,40 @@ async function handleLink(manager: PluginManager, paths: string[], flags: { json
|
|
|
886
886
|
}
|
|
887
887
|
}
|
|
888
888
|
|
|
889
|
+
async function collectMarketplaceDoctorChecks(): Promise<
|
|
890
|
+
Array<{ name: string; status: "ok" | "warning" | "error"; message: string }>
|
|
891
|
+
> {
|
|
892
|
+
const extra: Array<{ name: string; status: "ok" | "warning" | "error"; message: string }> = [];
|
|
893
|
+
try {
|
|
894
|
+
const mktMgr = await makeMarketplaceManager();
|
|
895
|
+
const installed = await mktMgr.listInstalledPlugins();
|
|
896
|
+
for (const summary of installed) {
|
|
897
|
+
for (const entry of summary.entries) {
|
|
898
|
+
let exists = false;
|
|
899
|
+
try {
|
|
900
|
+
const { statSync } = await import("node:fs");
|
|
901
|
+
statSync(entry.installPath);
|
|
902
|
+
exists = true;
|
|
903
|
+
} catch {}
|
|
904
|
+
if (!exists) {
|
|
905
|
+
extra.push({
|
|
906
|
+
name: `marketplace:${summary.id}:${entry.scope}`,
|
|
907
|
+
status: "error",
|
|
908
|
+
message: `Marketplace plugin "${summary.id}" (${entry.scope}) references missing cache dir "${entry.installPath}" (v${entry.version}); reinstall or upgrade the plugin`,
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
} catch {}
|
|
914
|
+
return extra;
|
|
915
|
+
}
|
|
916
|
+
|
|
889
917
|
async function handleDoctor(
|
|
890
918
|
manager: PluginManager,
|
|
891
919
|
flags: { json?: boolean; fix?: boolean; migratePlugins?: boolean },
|
|
892
920
|
): Promise<void> {
|
|
893
921
|
const checks = await manager.doctor({ fix: flags.fix });
|
|
922
|
+
checks.push(...(await collectMarketplaceDoctorChecks()));
|
|
894
923
|
try {
|
|
895
924
|
const statuses = flags.migratePlugins
|
|
896
925
|
? await runGjcPluginMigrationPreflight(getProjectDir())
|
package/src/cli/root-flags.ts
CHANGED
|
@@ -73,6 +73,11 @@ export const ROOT_LAUNCH_FLAGS = {
|
|
|
73
73
|
optionalValue: true,
|
|
74
74
|
}),
|
|
75
75
|
"no-title": Flags.boolean({ description: "Disable title auto-generation" }),
|
|
76
|
+
master: Flags.boolean({ description: "Launch an interactive master session" }),
|
|
77
|
+
scope: Flags.string({
|
|
78
|
+
description: "Master scope: repo (default), pwd, or global",
|
|
79
|
+
options: ["repo", "pwd", "global"],
|
|
80
|
+
}),
|
|
76
81
|
};
|
|
77
82
|
|
|
78
83
|
export type ConsumerLaunchFlagName = "hook" | "extension" | "no-extensions" | "no-skills" | "skills";
|