@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
package/src/cli/update-cli.ts
CHANGED
|
@@ -9,7 +9,7 @@ import * as fs from "node:fs";
|
|
|
9
9
|
import * as os from "node:os";
|
|
10
10
|
import * as path from "node:path";
|
|
11
11
|
import { pipeline } from "node:stream/promises";
|
|
12
|
-
import { $which, APP_NAME, isCompiledBinary, isEnoent, VERSION } from "@gajae-code/utils";
|
|
12
|
+
import { $which, APP_NAME, isCompiledBinary, isEnoent, redactCrashSecrets, VERSION } from "@gajae-code/utils";
|
|
13
13
|
import { $ } from "bun";
|
|
14
14
|
import chalk from "chalk";
|
|
15
15
|
import { Settings } from "../config/settings";
|
|
@@ -55,6 +55,7 @@ export interface InstalledVersionVerification {
|
|
|
55
55
|
ok: boolean;
|
|
56
56
|
actual?: string;
|
|
57
57
|
path?: string;
|
|
58
|
+
versionOutput?: string;
|
|
58
59
|
smokeTestFailed?: boolean;
|
|
59
60
|
smokeTestOutput?: string;
|
|
60
61
|
cleanupWarning?: string;
|
|
@@ -462,6 +463,71 @@ export function parseReportedVersionForTest(output: string): string | undefined
|
|
|
462
463
|
return parseReportedVersion(output);
|
|
463
464
|
}
|
|
464
465
|
|
|
466
|
+
const VERIFICATION_OUTPUT_MAX_LENGTH = 512;
|
|
467
|
+
const ANSI_ESCAPE = /\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\))/gu;
|
|
468
|
+
const UNSAFE_CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/gu;
|
|
469
|
+
|
|
470
|
+
function sanitizeVerificationOutput(...streams: Array<string | undefined>): string | undefined {
|
|
471
|
+
const output = streams
|
|
472
|
+
.map(stream => stream?.replace(ANSI_ESCAPE, "").replace(UNSAFE_CONTROL, " ").replace(/\s+/g, " ").trim() ?? "")
|
|
473
|
+
.filter(Boolean)
|
|
474
|
+
.filter((stream, index, all) => all.indexOf(stream) === index)
|
|
475
|
+
.join(" ");
|
|
476
|
+
if (!output) return undefined;
|
|
477
|
+
const redacted = redactCrashSecrets(output);
|
|
478
|
+
if (redacted.length <= VERIFICATION_OUTPUT_MAX_LENGTH) return redacted;
|
|
479
|
+
return `${redacted.slice(0, VERIFICATION_OUTPUT_MAX_LENGTH - 3)}...`;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export function sanitizeVerificationOutputForTest(
|
|
483
|
+
stderr: string | undefined,
|
|
484
|
+
stdout: string | undefined,
|
|
485
|
+
): string | undefined {
|
|
486
|
+
return sanitizeVerificationOutput(stderr, stdout);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
interface InstalledVersionCommandResult {
|
|
490
|
+
exitCode: number | null;
|
|
491
|
+
stdout: string;
|
|
492
|
+
stderr: string;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
type InstalledVersionCommandRunner = (runtimePath: string) => Promise<InstalledVersionCommandResult>;
|
|
496
|
+
|
|
497
|
+
async function verifyInstalledVersionWith(
|
|
498
|
+
expectedVersion: string,
|
|
499
|
+
runtimePath: string | undefined,
|
|
500
|
+
runVersion: InstalledVersionCommandRunner,
|
|
501
|
+
): Promise<InstalledVersionVerification> {
|
|
502
|
+
if (!runtimePath) return { ok: false };
|
|
503
|
+
try {
|
|
504
|
+
const result = await runVersion(runtimePath);
|
|
505
|
+
if (result.exitCode !== 0) {
|
|
506
|
+
return {
|
|
507
|
+
ok: false,
|
|
508
|
+
path: runtimePath,
|
|
509
|
+
versionOutput: sanitizeVerificationOutput(result.stderr, result.stdout),
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
const actual = parseReportedVersion(result.stdout);
|
|
513
|
+
return { ok: actual === expectedVersion, actual, path: runtimePath };
|
|
514
|
+
} catch (error) {
|
|
515
|
+
return {
|
|
516
|
+
ok: false,
|
|
517
|
+
path: runtimePath,
|
|
518
|
+
versionOutput: sanitizeVerificationOutput(error instanceof Error ? error.message : String(error)),
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export async function verifyInstalledVersionForTest(options: {
|
|
524
|
+
expectedVersion: string;
|
|
525
|
+
runtimePath: string | undefined;
|
|
526
|
+
runVersion: InstalledVersionCommandRunner;
|
|
527
|
+
}): Promise<InstalledVersionVerification> {
|
|
528
|
+
return await verifyInstalledVersionWith(options.expectedVersion, options.runtimePath, options.runVersion);
|
|
529
|
+
}
|
|
530
|
+
|
|
465
531
|
/**
|
|
466
532
|
* Run the resolved gjc binary and check if it reports the expected version.
|
|
467
533
|
*/
|
|
@@ -469,15 +535,14 @@ async function verifyInstalledVersion(
|
|
|
469
535
|
expectedVersion: string,
|
|
470
536
|
runtimePath: string | undefined = resolveGjcPath(),
|
|
471
537
|
): Promise<InstalledVersionVerification> {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
538
|
+
return await verifyInstalledVersionWith(expectedVersion, runtimePath, async resolvedPath => {
|
|
539
|
+
const result = await $`${resolvedPath} --version`.quiet().nothrow();
|
|
540
|
+
return {
|
|
541
|
+
exitCode: result.exitCode,
|
|
542
|
+
stdout: result.stdout.toString(),
|
|
543
|
+
stderr: result.stderr.toString(),
|
|
544
|
+
};
|
|
545
|
+
});
|
|
481
546
|
}
|
|
482
547
|
|
|
483
548
|
async function verifyInstalledRuntime(
|
|
@@ -665,7 +730,8 @@ function formatVerificationFailure(result: InstalledVersionVerification, expecte
|
|
|
665
730
|
if (result.actual) {
|
|
666
731
|
return `${APP_NAME} at ${result.path} still reports ${result.actual} (expected ${expectedVersion})`;
|
|
667
732
|
}
|
|
668
|
-
|
|
733
|
+
const outputSuffix = result.versionOutput ? `: ${result.versionOutput}` : "";
|
|
734
|
+
return `could not verify updated version${result.path ? ` at ${result.path}` : ""}${outputSuffix}`;
|
|
669
735
|
}
|
|
670
736
|
|
|
671
737
|
export function formatVerificationFailureForTest(
|
|
@@ -1084,6 +1150,67 @@ function formatRegistryProvenance(version: string, registry: string | undefined)
|
|
|
1084
1150
|
return `Version ${version} was resolved from ${registry}; GitHub release assets may not exist for a version that was never published there.`;
|
|
1085
1151
|
}
|
|
1086
1152
|
|
|
1153
|
+
interface ProcessReportWithLibc {
|
|
1154
|
+
header?: {
|
|
1155
|
+
glibcVersionRuntime?: unknown;
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
const GLIBC_VERSION_PATTERN = /^\d+\.\d+$/u;
|
|
1160
|
+
|
|
1161
|
+
function reportedGlibcVersion(value: unknown): string | undefined {
|
|
1162
|
+
if (typeof value !== "string") return undefined;
|
|
1163
|
+
const version = value.trim();
|
|
1164
|
+
return GLIBC_VERSION_PATTERN.test(version) ? version : undefined;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
function runtimeGlibcVersion(): string | undefined {
|
|
1168
|
+
try {
|
|
1169
|
+
const report = process.report?.getReport?.() as ProcessReportWithLibc | undefined;
|
|
1170
|
+
return reportedGlibcVersion(report?.header?.glibcVersionRuntime);
|
|
1171
|
+
} catch {
|
|
1172
|
+
return undefined;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
function hasMuslLoader(): boolean {
|
|
1177
|
+
return (
|
|
1178
|
+
fs.existsSync("/lib/ld-musl-x86_64.so.1") ||
|
|
1179
|
+
fs.existsSync("/lib/ld-musl-aarch64.so.1") ||
|
|
1180
|
+
fs.existsSync("/lib/ld-musl-armhf.so.1")
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
type LinuxLibc = "glibc" | "musl" | "unknown";
|
|
1185
|
+
|
|
1186
|
+
function detectLinuxLibcFromSignals(glibcVersionRuntime: string | undefined, muslLoaderPresent: boolean): LinuxLibc {
|
|
1187
|
+
if (reportedGlibcVersion(glibcVersionRuntime) !== undefined) return "glibc";
|
|
1188
|
+
return muslLoaderPresent ? "musl" : "unknown";
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
function detectLinuxLibc(): LinuxLibc {
|
|
1192
|
+
return detectLinuxLibcFromSignals(runtimeGlibcVersion(), hasMuslLoader());
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
function unsupportedLinuxLibcReason(libc: LinuxLibc): string | undefined {
|
|
1196
|
+
if (libc === "glibc") return undefined;
|
|
1197
|
+
return libc === "musl"
|
|
1198
|
+
? "Unsupported libc: musl. Prebuilt Linux binaries are glibc-only. See docs/install.md"
|
|
1199
|
+
: "Unable to verify an active glibc runtime. Prebuilt Linux binaries are glibc-only. See docs/install.md";
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
function assertSupportedLinuxLibc(libc: LinuxLibc): void {
|
|
1203
|
+
const reason = unsupportedLinuxLibcReason(libc);
|
|
1204
|
+
if (reason) throw new Error(formatUnsupportedTargetMessage(reason));
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
export function assertSupportedLinuxLibcForTest(
|
|
1208
|
+
glibcVersionRuntime: string | undefined,
|
|
1209
|
+
muslLoaderPresent: boolean,
|
|
1210
|
+
): void {
|
|
1211
|
+
assertSupportedLinuxLibc(detectLinuxLibcFromSignals(glibcVersionRuntime, muslLoaderPresent));
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1087
1214
|
/**
|
|
1088
1215
|
* Download a release binary to a target path, replacing an existing file.
|
|
1089
1216
|
*/
|
|
@@ -1092,18 +1219,8 @@ async function updateViaBinaryAt(
|
|
|
1092
1219
|
expectedVersion: string,
|
|
1093
1220
|
registry?: string,
|
|
1094
1221
|
): Promise<InstalledVersionVerification> {
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
(fs.existsSync("/lib/ld-musl-x86_64.so.1") ||
|
|
1098
|
-
fs.existsSync("/lib/ld-musl-aarch64.so.1") ||
|
|
1099
|
-
fs.existsSync("/lib/ld-musl-armhf.so.1"))
|
|
1100
|
-
) {
|
|
1101
|
-
throw new Error(
|
|
1102
|
-
formatUnsupportedTargetMessage(
|
|
1103
|
-
"Unsupported libc: musl. Prebuilt Linux binaries are glibc-only. See docs/install.md",
|
|
1104
|
-
),
|
|
1105
|
-
);
|
|
1106
|
-
}
|
|
1222
|
+
const linuxLibc = process.platform === "linux" ? detectLinuxLibc() : undefined;
|
|
1223
|
+
if (linuxLibc !== undefined) assertSupportedLinuxLibc(linuxLibc);
|
|
1107
1224
|
const binaryName = getBinaryName();
|
|
1108
1225
|
const url = buildReleaseBinaryUrl(expectedVersion);
|
|
1109
1226
|
const registryNote = formatRegistryProvenance(expectedVersion, registry);
|
package/src/commands/launch.ts
CHANGED
|
@@ -2,20 +2,30 @@
|
|
|
2
2
|
* Root command for the coding agent CLI.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { APP_NAME, setProjectDir } from "@gajae-code/utils";
|
|
5
|
+
import { APP_NAME, getAgentDir, setProjectDir } from "@gajae-code/utils";
|
|
6
6
|
import { Args, Command } from "@gajae-code/utils/cli";
|
|
7
7
|
import { assertLocalLaunchArgs, parseArgs } from "../cli/args";
|
|
8
8
|
import { ROOT_LAUNCH_FLAGS } from "../cli/root-flags";
|
|
9
9
|
import { writeCoordinatorAtomic } from "../coordinator-mcp/durability";
|
|
10
10
|
import { launchDefaultTmuxIfNeeded } from "../gjc-runtime/launch-tmux";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
type GjcLaunchWorktreePlan,
|
|
13
|
+
type PreparedLaunchWorktree,
|
|
14
|
+
parseLaunchWorktreeMode,
|
|
15
|
+
planLaunchWorktree,
|
|
16
|
+
prepareLaunchWorktree,
|
|
17
|
+
} from "../gjc-runtime/launch-worktree";
|
|
18
|
+
import { type LaunchWorktreeReservation, reserveLaunchWorktree } from "../gjc-runtime/launch-worktree-reservation";
|
|
12
19
|
import {
|
|
13
20
|
GJC_COORDINATOR_SESSION_ID_ENV,
|
|
14
21
|
GJC_COORDINATOR_SESSION_STATE_FILE_ENV,
|
|
15
22
|
GJC_TMUX_OWNER_GENERATION_ENV,
|
|
16
23
|
} from "../gjc-runtime/session-state-sidecar";
|
|
17
24
|
import { runRootCommand } from "../main";
|
|
25
|
+
import { assertMasterLaunchArgs } from "../master-mode/context";
|
|
18
26
|
import { prepareAcpTerminalAuthArgs } from "../modes/acp/terminal-auth";
|
|
27
|
+
import { type IndexedSession, SessionIndex } from "../sdk/broker/session-index";
|
|
28
|
+
import { worktreeOccupant } from "../sdk/broker/worktree-occupancy";
|
|
19
29
|
|
|
20
30
|
export async function persistCoordinatorLaunchFailure(
|
|
21
31
|
error: unknown,
|
|
@@ -56,6 +66,54 @@ export async function persistCoordinatorLaunchFailure(
|
|
|
56
66
|
await writeCoordinatorAtomic(stateFile, `${JSON.stringify(payload, null, 2)}\n`);
|
|
57
67
|
}
|
|
58
68
|
|
|
69
|
+
function worktreeInUseError(worktreePath: string, occupant?: string): Error {
|
|
70
|
+
const holder = occupant ? `session ${occupant}` : "another launch";
|
|
71
|
+
return new Error(
|
|
72
|
+
`worktree_in_use:${worktreePath} is already held by ${holder}. ` +
|
|
73
|
+
"Use gjc --worktree <name> for a separate checkout, or stop that session.",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function reserveLaunchWorktreeOrFail(agentDir: string, worktreePath: string): Promise<LaunchWorktreeReservation> {
|
|
78
|
+
const reservation = await reserveLaunchWorktree(agentDir, worktreePath);
|
|
79
|
+
if (!reservation) throw worktreeInUseError(worktreePath);
|
|
80
|
+
return reservation;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Test seam for the path-keyed atomic reservation. */
|
|
84
|
+
export async function reserveLaunchWorktreeForTest(
|
|
85
|
+
agentDir: string,
|
|
86
|
+
worktreePath: string,
|
|
87
|
+
): Promise<LaunchWorktreeReservation> {
|
|
88
|
+
return await reserveLaunchWorktreeOrFail(agentDir, worktreePath);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function assertLaunchWorktreeUnoccupied(worktree: GjcLaunchWorktreePlan | { enabled: false }): Promise<void> {
|
|
92
|
+
if (!worktree.enabled) return;
|
|
93
|
+
let sessions: readonly IndexedSession[];
|
|
94
|
+
try {
|
|
95
|
+
sessions = (await new SessionIndex(getAgentDir()).open()).listSessionIdentities();
|
|
96
|
+
} catch {
|
|
97
|
+
throw new Error(`worktree_occupancy_unavailable:${worktree.worktreePath}`);
|
|
98
|
+
}
|
|
99
|
+
const occupant = worktreeOccupant(sessions, worktree.worktreePath);
|
|
100
|
+
if (occupant) throw worktreeInUseError(worktree.worktreePath, occupant);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function reserveLaunchWorktreePreflight(
|
|
104
|
+
worktree: GjcLaunchWorktreePlan | { enabled: false },
|
|
105
|
+
): Promise<LaunchWorktreeReservation | undefined> {
|
|
106
|
+
if (!worktree.enabled) return undefined;
|
|
107
|
+
const reservation = await reserveLaunchWorktreeOrFail(getAgentDir(), worktree.worktreePath);
|
|
108
|
+
try {
|
|
109
|
+
await assertLaunchWorktreeUnoccupied(worktree);
|
|
110
|
+
return reservation;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
await reservation.release();
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
59
117
|
export default class Index extends Command {
|
|
60
118
|
static description = "Red-claw AI coding assistant";
|
|
61
119
|
static hidden = true;
|
|
@@ -93,34 +151,44 @@ export default class Index extends Command {
|
|
|
93
151
|
const { args } = prepareAcpTerminalAuthArgs(this.argv);
|
|
94
152
|
const parsed = parseArgs([...args], "deferred");
|
|
95
153
|
if (parsed.mode !== "acp") assertLocalLaunchArgs(parsed);
|
|
154
|
+
assertMasterLaunchArgs(parsed);
|
|
96
155
|
if (parsed.help || parsed.version) {
|
|
97
156
|
await runRootCommand(parsed, args);
|
|
98
157
|
return;
|
|
99
158
|
}
|
|
100
159
|
|
|
101
160
|
let launch: PreparedLaunchWorktree;
|
|
161
|
+
let reservation: LaunchWorktreeReservation | undefined;
|
|
102
162
|
try {
|
|
163
|
+
const plannedWorktree = planLaunchWorktree(process.cwd(), parseLaunchWorktreeMode(args).mode);
|
|
164
|
+
reservation = await reserveLaunchWorktreePreflight(plannedWorktree);
|
|
103
165
|
launch = prepareLaunchWorktree(process.cwd(), args);
|
|
104
166
|
} catch (error) {
|
|
167
|
+
await reservation?.release();
|
|
105
168
|
await persistCoordinatorLaunchFailure(error, process.cwd());
|
|
106
169
|
throw error;
|
|
107
170
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
171
|
+
try {
|
|
172
|
+
if (launch.worktree.enabled) {
|
|
173
|
+
process.chdir(launch.cwd);
|
|
174
|
+
setProjectDir(launch.cwd);
|
|
175
|
+
}
|
|
176
|
+
const launchParsed = parseArgs(launch.args, "deferred");
|
|
177
|
+
if (launchParsed.mode !== "acp") assertLocalLaunchArgs(launchParsed);
|
|
178
|
+
assertMasterLaunchArgs(launchParsed);
|
|
179
|
+
if (
|
|
180
|
+
launchDefaultTmuxIfNeeded({
|
|
181
|
+
parsed: launchParsed,
|
|
182
|
+
rawArgs: launch.args,
|
|
183
|
+
cwd: launch.cwd,
|
|
184
|
+
worktreeBranch: launch.worktree.enabled && !launch.worktree.detached ? launch.worktree.branchName : null,
|
|
185
|
+
project: launch.cwd,
|
|
186
|
+
})
|
|
187
|
+
)
|
|
188
|
+
return;
|
|
189
|
+
await runRootCommand(launchParsed, launch.args);
|
|
190
|
+
} finally {
|
|
191
|
+
await reservation?.release();
|
|
111
192
|
}
|
|
112
|
-
const launchParsed = parseArgs(launch.args, "deferred");
|
|
113
|
-
if (launchParsed.mode !== "acp") assertLocalLaunchArgs(launchParsed);
|
|
114
|
-
if (
|
|
115
|
-
launchDefaultTmuxIfNeeded({
|
|
116
|
-
parsed: launchParsed,
|
|
117
|
-
rawArgs: launch.args,
|
|
118
|
-
cwd: launch.cwd,
|
|
119
|
-
worktreeBranch: launch.worktree.enabled && !launch.worktree.detached ? launch.worktree.branchName : null,
|
|
120
|
-
project: launch.cwd,
|
|
121
|
-
})
|
|
122
|
-
)
|
|
123
|
-
return;
|
|
124
|
-
await runRootCommand(launchParsed, launch.args);
|
|
125
193
|
}
|
|
126
194
|
}
|
package/src/commands/sdk.ts
CHANGED
|
@@ -27,7 +27,8 @@ import {
|
|
|
27
27
|
} from "../sdk/broker/lifecycle";
|
|
28
28
|
import { processIncarnation } from "../sdk/broker/process-incarnation";
|
|
29
29
|
import { writeBrokerStartupFailureMarker } from "../sdk/broker/startup-failure";
|
|
30
|
-
import { runSdkSessionCli } from "../sdk/cli";
|
|
30
|
+
import { renderSdkSearchTable, runSdkSearch, runSdkSessionCli } from "../sdk/cli";
|
|
31
|
+
import { renderSpawnTable, runSdkSpawn, SdkMasterCliError } from "../sdk/cli/master-cli";
|
|
31
32
|
import { runSdkGuidesCli } from "../sdk/guides/cli";
|
|
32
33
|
import { type CreateLifecycleAgentSessionResult, createLifecycleAgentSession } from "../sdk/lifecycle-session";
|
|
33
34
|
import { listManagedSessionCandidates, resolveManagedSessionScope } from "../sdk/session-directory";
|
|
@@ -38,6 +39,7 @@ import {
|
|
|
38
39
|
SdkStartupRollbackTracker,
|
|
39
40
|
} from "../sdk/startup-capability";
|
|
40
41
|
import { runSdkServe } from "../sdk/transport/serve-cli";
|
|
42
|
+
import { isSessionDisposalIncompleteError } from "../session/agent-session";
|
|
41
43
|
import {
|
|
42
44
|
type CapturedSessionTranscriptSnapshot,
|
|
43
45
|
type ResumeSessionIdentity,
|
|
@@ -404,11 +406,13 @@ export async function runSessionHost(
|
|
|
404
406
|
sleep?: (ms: number) => Promise<void>;
|
|
405
407
|
cwd?: string;
|
|
406
408
|
processIncarnation?: (pid: number) => string | undefined;
|
|
409
|
+
applyStartupModelProfiles?: typeof applyStartupModelProfiles;
|
|
407
410
|
} = {},
|
|
408
411
|
): Promise<void> {
|
|
409
412
|
const now = timing.now ?? Date.now;
|
|
410
413
|
const sleep = timing.sleep ?? (async ms => await Bun.sleep(ms));
|
|
411
414
|
const readIncarnation = timing.processIncarnation ?? processIncarnation;
|
|
415
|
+
const applyModelProfiles = timing.applyStartupModelProfiles ?? applyStartupModelProfiles;
|
|
412
416
|
const request = readSessionLifecycleLaunchRequest(process.env.GJC_SDK_LIFECYCLE_REQUEST, now());
|
|
413
417
|
const agentDir = process.env.GJC_AGENT_DIR;
|
|
414
418
|
if (!agentDir) throw new Error("GJC_AGENT_DIR is required for sdk session-host-internal.");
|
|
@@ -582,6 +586,7 @@ export async function runSessionHost(
|
|
|
582
586
|
...(mcpStartupTimeoutMs !== undefined ? { mcpStartupTimeoutMs } : {}),
|
|
583
587
|
...(request.readiness ? { readiness: request.readiness } : {}),
|
|
584
588
|
...(request.modelId ? { modelId: request.modelId } : {}),
|
|
589
|
+
lifecycleRequestId: effectMarker,
|
|
585
590
|
});
|
|
586
591
|
} catch (error) {
|
|
587
592
|
throw await registrationFailure(error);
|
|
@@ -597,22 +602,32 @@ export async function runSessionHost(
|
|
|
597
602
|
throw created.failure;
|
|
598
603
|
}
|
|
599
604
|
const { session, capability, rollback, startDeferredMemoryBackend } = created;
|
|
605
|
+
let lifecycleTranscriptPath: string | undefined;
|
|
606
|
+
session.registerToolSessionTransitionCleanup(async () => {
|
|
607
|
+
await session.sessionManager.ensureOnDisk();
|
|
608
|
+
lifecycleTranscriptPath = session.sessionManager.getSessionFile();
|
|
609
|
+
});
|
|
600
610
|
let sessionDisposal: Promise<void> | undefined;
|
|
601
611
|
const disposeSession = (): Promise<void> => {
|
|
602
|
-
sessionDisposal ??=
|
|
612
|
+
sessionDisposal ??= (async () => {
|
|
613
|
+
try {
|
|
614
|
+
await session.dispose();
|
|
615
|
+
} catch (error) {
|
|
616
|
+
if (!isSessionDisposalIncompleteError(error)) throw error;
|
|
617
|
+
await session.awaitDisposeCompletion();
|
|
618
|
+
}
|
|
619
|
+
})();
|
|
603
620
|
return sessionDisposal;
|
|
604
621
|
};
|
|
605
622
|
let disposal: Promise<LifecycleTranscriptEvidence | undefined> | undefined;
|
|
606
623
|
const disposeAndCapture = (): Promise<LifecycleTranscriptEvidence | undefined> => {
|
|
607
624
|
disposal ??= (async () => {
|
|
608
625
|
await disposeSession();
|
|
626
|
+
if (!lifecycleTranscriptPath) return undefined;
|
|
609
627
|
try {
|
|
610
|
-
await session.sessionManager.ensureOnDisk();
|
|
611
|
-
const transcriptPath = session.sessionManager.getSessionFile();
|
|
612
|
-
if (!transcriptPath) return undefined;
|
|
613
628
|
const [bytes, stat] = await Promise.all([
|
|
614
|
-
fs.readFile(
|
|
615
|
-
fs.stat(
|
|
629
|
+
fs.readFile(lifecycleTranscriptPath),
|
|
630
|
+
fs.stat(lifecycleTranscriptPath, { bigint: true }),
|
|
616
631
|
]);
|
|
617
632
|
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
618
633
|
return {
|
|
@@ -706,12 +721,14 @@ export async function runSessionHost(
|
|
|
706
721
|
const modelProfileStartup =
|
|
707
722
|
process.env.GJC_SDK_TEST_HANG_MODEL_PROFILE === cwd
|
|
708
723
|
? new Promise<void>(() => {})
|
|
709
|
-
:
|
|
724
|
+
: applyModelProfiles({
|
|
710
725
|
session,
|
|
711
726
|
settings: session.settings,
|
|
712
727
|
modelRegistry: session.modelRegistry,
|
|
713
728
|
parsedArgs: parsed,
|
|
714
729
|
startupThinkingLevel,
|
|
730
|
+
preferCachedModels: true,
|
|
731
|
+
preferCachedDefaultProfile: true,
|
|
715
732
|
});
|
|
716
733
|
await beforeCutoff(modelProfileStartup);
|
|
717
734
|
throwIfCutoff();
|
|
@@ -838,19 +855,24 @@ class SdkSessionHelp extends Command {
|
|
|
838
855
|
description: "Workspace directory for saved-session resolution (default: current directory)",
|
|
839
856
|
}),
|
|
840
857
|
op: Flags.string({ description: "Raw control or global operation" }),
|
|
841
|
-
|
|
842
|
-
description: "list scope: repo (default), cwd, worktree, or all",
|
|
843
|
-
options: ["repo", "cwd", "worktree", "all"],
|
|
844
|
-
}),
|
|
858
|
+
|
|
845
859
|
query: Flags.string({ description: "Raw query name" }),
|
|
846
860
|
"json-input": Flags.string({ description: "SDK request JSON object" }),
|
|
847
861
|
"json-input-file": Flags.string({ description: "Read SDK request JSON from a 0600 file" }),
|
|
848
862
|
"json-input-stdin": Flags.boolean({ description: "Read SDK request JSON from standard input" }),
|
|
849
|
-
"idempotency-key": Flags.string({
|
|
850
|
-
|
|
863
|
+
"idempotency-key": Flags.string({
|
|
864
|
+
description: "Caller idempotency key required for lifecycle globals and terminal abort controls",
|
|
865
|
+
}),
|
|
866
|
+
confirm: Flags.boolean({ description: "Confirm a destructive local CLI control operation" }),
|
|
851
867
|
cursor: Flags.string({
|
|
852
|
-
description: "Raw query continuation cursor,
|
|
868
|
+
description: "Raw query continuation cursor, saved checkpoint token, or search continuation cursor",
|
|
869
|
+
}),
|
|
870
|
+
scope: Flags.string({
|
|
871
|
+
description:
|
|
872
|
+
"session list scope: repo (default), cwd, worktree, or all; search scope: repo (default), pwd, or global",
|
|
853
873
|
}),
|
|
874
|
+
limit: Flags.integer({ description: "Search page size from 1 to 100" }),
|
|
875
|
+
json: Flags.boolean({ description: "Render search as the SdkSearchResultV1 JSON envelope" }),
|
|
854
876
|
text: Flags.string({ description: "Prompt text for send (alternative to --json-input)" }),
|
|
855
877
|
"op-ref": Flags.string({ description: "Operation reference for send (defaults to a generated ULID)" }),
|
|
856
878
|
wait: Flags.boolean({
|
|
@@ -864,6 +886,70 @@ class SdkSessionHelp extends Command {
|
|
|
864
886
|
async run(): Promise<void> {}
|
|
865
887
|
}
|
|
866
888
|
|
|
889
|
+
class SdkSpawnCommand extends Command {
|
|
890
|
+
static description = "Spawn a task-seeded background child session (local interactive master only).";
|
|
891
|
+
static flags = {
|
|
892
|
+
cwd: Flags.string({ description: "Working directory for the spawned child" }),
|
|
893
|
+
prompt: Flags.string({ description: "Seed task delivered once to the child" }),
|
|
894
|
+
model: Flags.string({ description: "Model selector for the child" }),
|
|
895
|
+
profile: Flags.string({ description: "Model profile name for the child" }),
|
|
896
|
+
"agent-dir": Flags.string({ description: "SDK broker state directory" }),
|
|
897
|
+
"idempotency-key": Flags.string({
|
|
898
|
+
description: "Idempotency key for replaying an uncertain session.spawn result",
|
|
899
|
+
}),
|
|
900
|
+
json: Flags.boolean({ description: "Render the safe spawn result as JSON" }),
|
|
901
|
+
};
|
|
902
|
+
async run(): Promise<void> {
|
|
903
|
+
const { flags } = await this.parse(SdkSpawnCommand);
|
|
904
|
+
try {
|
|
905
|
+
const spawn = await runSdkSpawn({
|
|
906
|
+
cwd: flags.cwd,
|
|
907
|
+
prompt: flags.prompt,
|
|
908
|
+
model: flags.model,
|
|
909
|
+
profile: flags.profile,
|
|
910
|
+
agentDir: flags["agent-dir"],
|
|
911
|
+
idempotencyKey: flags["idempotency-key"],
|
|
912
|
+
});
|
|
913
|
+
process.stdout.write(`${flags.json ? JSON.stringify(spawn.rendered) : renderSpawnTable(spawn.rendered)}\n`);
|
|
914
|
+
if (spawn.exitCode !== 0) process.exitCode = spawn.exitCode;
|
|
915
|
+
} catch (error) {
|
|
916
|
+
if (error instanceof SdkMasterCliError) {
|
|
917
|
+
process.stderr.write(`Error: ${error.code}: ${error.message}\n`);
|
|
918
|
+
process.exitCode = error.exitCode;
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
throw error;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
class SdkSearchCommand extends Command {
|
|
927
|
+
static description = "Search broker-visible SDK sessions within an exact repo, pwd, or global scope.";
|
|
928
|
+
static flags = {
|
|
929
|
+
"agent-dir": Flags.string({ description: "SDK broker state directory" }),
|
|
930
|
+
repo: Flags.string({ description: "Workspace directory for scope resolution (default: current directory)" }),
|
|
931
|
+
scope: Flags.string({ description: "Search scope: repo, pwd, or global (default: repo)" }),
|
|
932
|
+
limit: Flags.integer({ description: "Search page size from 1 to 100" }),
|
|
933
|
+
cursor: Flags.string({ description: "Frozen scoped search continuation cursor" }),
|
|
934
|
+
json: Flags.boolean({ description: "Render exactly the SdkSearchResultV1 JSON envelope" }),
|
|
935
|
+
};
|
|
936
|
+
async run(): Promise<void> {
|
|
937
|
+
const { flags } = await this.parse(SdkSearchCommand);
|
|
938
|
+
const scope = flags.scope;
|
|
939
|
+
if (scope !== undefined && scope !== "repo" && scope !== "pwd" && scope !== "global")
|
|
940
|
+
throw new CliParseError("--scope must be repo, pwd, or global.");
|
|
941
|
+
const search = await runSdkSearch({
|
|
942
|
+
agentDir: flags["agent-dir"],
|
|
943
|
+
repo: flags.repo,
|
|
944
|
+
scope,
|
|
945
|
+
limit: flags.limit,
|
|
946
|
+
cursor: flags.cursor,
|
|
947
|
+
});
|
|
948
|
+
process.stdout.write(`${flags.json ? JSON.stringify(search.result) : renderSdkSearchTable(search.result)}\n`);
|
|
949
|
+
if (search.exitCode !== 0) process.exitCode = search.exitCode;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
867
953
|
class SdkSessionCommand extends Command {
|
|
868
954
|
static description = SdkSessionHelp.description;
|
|
869
955
|
static args = SdkSessionHelp.args;
|
|
@@ -936,10 +1022,12 @@ class SdkGuidesCommand extends Command {
|
|
|
936
1022
|
|
|
937
1023
|
export default class Sdk extends Command {
|
|
938
1024
|
static description =
|
|
939
|
-
"gjc sdk serve --stdio | --socket <path> [--session <id>]; gjc sdk session list|inspect|send|status|tail; gjc sdk guides refresh|list|show|status|trust";
|
|
1025
|
+
"gjc sdk serve --stdio | --socket <path> [--session <id>]; gjc sdk search [--scope repo|pwd|global] [--json] [--limit N] [--cursor ...]; gjc sdk spawn --cwd <dir> --prompt <task> (master only); gjc sdk session list|inspect|send|status|tail; gjc sdk guides refresh|list|show|status|trust";
|
|
940
1026
|
static hidden = false;
|
|
941
1027
|
static delegateHelp = true;
|
|
942
|
-
static args = {
|
|
1028
|
+
static args = {
|
|
1029
|
+
action: Args.string({ required: false, options: ["serve", "search", "spawn", "session", "guides"] }),
|
|
1030
|
+
};
|
|
943
1031
|
static flags = SdkServeHelp.flags;
|
|
944
1032
|
async run(): Promise<void> {
|
|
945
1033
|
const action = this.argv[0];
|
|
@@ -947,22 +1035,38 @@ export default class Sdk extends Command {
|
|
|
947
1035
|
const helpAction =
|
|
948
1036
|
action === "serve"
|
|
949
1037
|
? "sdk serve"
|
|
950
|
-
: action === "
|
|
951
|
-
? "sdk
|
|
952
|
-
: action === "
|
|
953
|
-
? "sdk
|
|
954
|
-
: "
|
|
1038
|
+
: action === "search"
|
|
1039
|
+
? "sdk search"
|
|
1040
|
+
: action === "spawn"
|
|
1041
|
+
? "sdk spawn"
|
|
1042
|
+
: action === "session"
|
|
1043
|
+
? "sdk session"
|
|
1044
|
+
: action === "guides"
|
|
1045
|
+
? "sdk guides"
|
|
1046
|
+
: "sdk";
|
|
955
1047
|
const helpCommand =
|
|
956
1048
|
action === "serve"
|
|
957
1049
|
? SdkServeHelp
|
|
958
|
-
: action === "
|
|
959
|
-
?
|
|
960
|
-
: action === "
|
|
961
|
-
?
|
|
962
|
-
:
|
|
1050
|
+
: action === "search"
|
|
1051
|
+
? SdkSearchCommand
|
|
1052
|
+
: action === "spawn"
|
|
1053
|
+
? SdkSpawnCommand
|
|
1054
|
+
: action === "session"
|
|
1055
|
+
? SdkSessionCommand
|
|
1056
|
+
: action === "guides"
|
|
1057
|
+
? SdkGuidesCommand
|
|
1058
|
+
: Sdk;
|
|
963
1059
|
renderCommandHelp("gjc", helpAction, helpCommand);
|
|
964
1060
|
return;
|
|
965
1061
|
}
|
|
1062
|
+
if (action === "search") {
|
|
1063
|
+
await new SdkSearchCommand(this.argv.slice(1), this.config).run();
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
if (action === "spawn") {
|
|
1067
|
+
await new SdkSpawnCommand(this.argv.slice(1), this.config).run();
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
966
1070
|
if (action === "session") {
|
|
967
1071
|
await new SdkSessionCommand(this.argv.slice(1), this.config).run();
|
|
968
1072
|
return;
|
|
@@ -976,7 +1080,7 @@ export default class Sdk extends Command {
|
|
|
976
1080
|
return;
|
|
977
1081
|
}
|
|
978
1082
|
if (action !== "broker-internal" && action !== "session-host-internal")
|
|
979
|
-
throw new CliParseError("Expected action to be serve, session, or guides.");
|
|
1083
|
+
throw new CliParseError("Expected action to be serve, search, spawn, session, or guides.");
|
|
980
1084
|
const internal = parseSdkInternalArgv(this.argv);
|
|
981
1085
|
if (internal.action === "session-host-internal") {
|
|
982
1086
|
await runSessionHost();
|
|
@@ -985,6 +1089,9 @@ export default class Sdk extends Command {
|
|
|
985
1089
|
const agentDir = internal.agentDir;
|
|
986
1090
|
const broker = new Broker({
|
|
987
1091
|
agentDir,
|
|
1092
|
+
masterOrphanGraceMs: (await Settings.loadForScope({ cwd: process.cwd(), agentDir })).get(
|
|
1093
|
+
"sdk.masterOrphanGraceMs",
|
|
1094
|
+
),
|
|
988
1095
|
resolveDirectoryMigration: async cwd => {
|
|
989
1096
|
const settings = await Settings.loadForScope({ cwd, agentDir });
|
|
990
1097
|
try {
|
|
@@ -360,8 +360,19 @@ export const TIER_MAP_SKIP_LIST = {
|
|
|
360
360
|
"nvidia/thinkingmachines/inkling": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
361
361
|
"nvidia/upstage/solar-10.7b-instruct": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
362
362
|
"openai-codex/gpt-daybreak-blue-latest": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
363
|
+
"opencode-go/deepseek-v4-flash-vision-exp": {
|
|
364
|
+
rationale: "post-rebase catalog addition from dev; not yet curated",
|
|
365
|
+
},
|
|
366
|
+
"opencode-go/glm-5.3-flash": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
363
367
|
"opencode-go/gpt-5.6-luna": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
368
|
+
"opencode-go/grok-4.6": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
364
369
|
"opencode-go/hy3": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
370
|
+
"opencode-go/hy4-preview": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
371
|
+
"opencode-go/longcat-2.0": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
372
|
+
"opencode-go/muse-spark-1.2-contributor": {
|
|
373
|
+
rationale: "post-rebase catalog addition from dev; not yet curated",
|
|
374
|
+
},
|
|
375
|
+
"opencode-go/qwen3.8-flash": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
365
376
|
"opencode-go/qwen3.8-max": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
366
377
|
"opencode-zen/grok-4.6": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
367
378
|
"opencode-zen/hy3-free": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
@@ -923,6 +934,7 @@ export const TIER_MAP_SKIP_LIST = {
|
|
|
923
934
|
"anthropic/claude-3-5-sonnet-20241022": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
924
935
|
"anthropic/claude-3-haiku-20240307": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
925
936
|
"anthropic/claude-fable-5": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
937
|
+
"anthropic/claude-fable-5-1": { rationale: "post-feature catalog addition; not yet curated" },
|
|
926
938
|
"anthropic/claude-haiku-4-5-20251001": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
927
939
|
"anthropic/claude-opus-4-0": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
928
940
|
"anthropic/claude-opus-4-1": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|