@gajae-code/coding-agent 0.15.4 → 0.15.6
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 +46 -2
- package/dist/types/async/job-manager.d.ts +83 -0
- package/dist/types/cli/auth-gateway-cli.d.ts +17 -0
- package/dist/types/cli/model-presets-cli.d.ts +9 -0
- package/dist/types/cli/update-cli.d.ts +27 -5
- package/dist/types/commands/auth-gateway.d.ts +3 -0
- package/dist/types/commands/gc.d.ts +13 -0
- package/dist/types/commands/model-presets.d.ts +21 -0
- package/dist/types/config/autorouting-tier-map.d.ts +99 -0
- package/dist/types/config/file-lock.d.ts +49 -2
- package/dist/types/config/internal/model-preset-registry-test-state.d.ts +4 -0
- package/dist/types/config/internal/model-preset-registry-test-support.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +3 -2
- package/dist/types/config/model-preset-registry.d.ts +368 -0
- package/dist/types/config/model-profile-activation.d.ts +39 -0
- package/dist/types/config/model-profiles.d.ts +5 -3
- package/dist/types/config/model-registry.d.ts +11 -5
- package/dist/types/config/settings-schema.d.ts +9 -0
- package/dist/types/coordinator-mcp/model-preset.d.ts +7 -5
- package/dist/types/coordinator-mcp/projection-scan.d.ts +46 -0
- package/dist/types/extensibility/extensions/types.d.ts +4 -4
- package/dist/types/extensibility/shared-events.d.ts +2 -0
- package/dist/types/gjc-runtime/empty-delete-gc.d.ts +58 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +2 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +35 -6
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/main.d.ts +3 -1
- package/dist/types/modes/components/jobs-overlay-model.d.ts +4 -2
- package/dist/types/modes/jobs-observer.d.ts +36 -0
- package/dist/types/sdk/broker/broker.d.ts +3 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +3 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +4 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +8 -1
- package/dist/types/sdk/cli/session-cli.d.ts +42 -1
- package/dist/types/sdk/client/discovery.d.ts +1 -0
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/host/model-pin.d.ts +7 -2
- package/dist/types/sdk/host/sdk-run-capability.d.ts +1 -0
- package/dist/types/sdk/host/session-runtime.d.ts +19 -1
- package/dist/types/sdk/prompt-deadline-manager.d.ts +11 -1
- package/dist/types/sdk/protocol/adapter-validation.d.ts +2 -0
- package/dist/types/sdk/router/session-router.d.ts +9 -0
- package/dist/types/session/account-inventory.d.ts +1 -0
- package/dist/types/session/agent-session.d.ts +19 -5
- package/dist/types/session/fold-coordinator.d.ts +201 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +4 -3
- package/dist/types/session/sdk-run-capability-internal.d.ts +7 -0
- package/dist/types/session/sdk-run-capability.d.ts +2 -0
- package/dist/types/telemetry/control.d.ts +11 -0
- package/dist/types/telemetry/events.d.ts +20 -0
- package/dist/types/telemetry/index.d.ts +3 -0
- package/dist/types/telemetry/transport.d.ts +22 -0
- package/dist/types/tools/bash-interactive.d.ts +23 -0
- package/dist/types/tools/index.d.ts +6 -5
- package/dist/types/tools/path-utils.d.ts +5 -6
- package/dist/types/tools/tmux-self-injection-guard.d.ts +15 -0
- package/dist/types/web/search/providers/base.d.ts +9 -4
- package/dist/types/web/search/providers/xai.d.ts +2 -1
- package/dist/types/web/search/types.d.ts +14 -0
- package/package.json +10 -7
- package/scripts/generate-hotkeys-docs.ts +4 -0
- package/scripts/generate-sdk-operation-inventory.ts +3 -3
- package/src/async/job-manager.ts +671 -39
- package/src/cli/auth-broker-cli.ts +40 -12
- package/src/cli/auth-gateway-cli.ts +273 -97
- package/src/cli/config-cli.ts +2 -2
- package/src/cli/fast-help.ts +3 -0
- package/src/cli/model-presets-cli.ts +100 -0
- package/src/cli/update-cli.ts +142 -6
- package/src/cli.ts +6 -2
- package/src/commands/auth-gateway.ts +12 -8
- package/src/commands/gc.ts +19 -0
- package/src/commands/model-presets.ts +24 -0
- package/src/commands/sdk.ts +5 -0
- package/src/config/autorouting-tier-map.ts +33 -0
- package/src/config/file-lock-gc.ts +9 -4
- package/src/config/file-lock.ts +775 -59
- package/src/config/internal/model-preset-registry-test-state.ts +28 -0
- package/src/config/internal/model-preset-registry-test-support.ts +11 -0
- package/src/config/keybindings.ts +6 -2
- package/src/config/model-preset-registry.ts +2799 -0
- package/src/config/model-profile-activation.ts +115 -28
- package/src/config/model-profile-contract.ts +4 -1
- package/src/config/model-profiles.ts +56 -14
- package/src/config/model-registry.ts +1028 -123
- package/src/config/settings-schema.ts +11 -0
- package/src/config/settings.ts +6 -1
- package/src/coordinator-mcp/model-preset.ts +32 -17
- package/src/coordinator-mcp/policy.ts +1 -1
- package/src/coordinator-mcp/projection-scan.ts +571 -0
- package/src/coordinator-mcp/server.ts +19 -24
- package/src/coordinator-mcp/session-reaper.ts +9 -3
- package/src/extensibility/extensions/loader.ts +0 -1
- package/src/extensibility/extensions/types.ts +4 -2
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +1 -0
- package/src/extensibility/shared-events.ts +2 -0
- package/src/gjc-runtime/empty-delete-gc.ts +301 -0
- package/src/gjc-runtime/gc-render.ts +29 -0
- package/src/gjc-runtime/gc-runtime.ts +174 -11
- package/src/gjc-runtime/launch-worktree.ts +44 -7
- package/src/gjc-runtime/ralplan-runtime.ts +14 -1
- package/src/gjc-runtime/session-state-lock.ts +1242 -141
- package/src/gjc-runtime/session-state-sidecar.ts +76 -3
- package/src/gjc-runtime/tmux-sessions.ts +145 -48
- package/src/index.ts +1 -0
- package/src/internal-urls/docs-index.generated.ts +14 -13
- package/src/lsp/config.ts +4 -3
- package/src/lsp/path-trust.ts +12 -6
- package/src/main.ts +9 -2
- package/src/modes/acp/acp-agent.ts +11 -5
- package/src/modes/components/jobs-overlay-model.ts +99 -16
- package/src/modes/components/model-selector.ts +158 -18
- package/src/modes/components/status-line/segments.ts +6 -1
- package/src/modes/controllers/extension-ui-controller.ts +1 -1
- package/src/modes/controllers/input-controller.ts +23 -6
- package/src/modes/interactive-mode.ts +14 -1
- package/src/modes/jobs-observer.ts +149 -16
- package/src/modes/prompt-action-autocomplete.ts +26 -47
- package/src/modes/runtime-init.ts +1 -1
- package/src/modes/utils/injected-user-submission.ts +15 -1
- package/src/prompts/tools/bash.md +2 -2
- package/src/prompts/tools/fold-receipt.md +3 -0
- package/src/prompts/tools/job.md +1 -1
- package/src/sdk/acp/adapter.ts +17 -2
- package/src/sdk/broker/broker.ts +48 -21
- package/src/sdk/broker/lifecycle.ts +32 -6
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +11 -1
- package/src/sdk/bus/kind-aware-reconciliation.ts +46 -8
- package/src/sdk/bus/prompt-reconciliation.ts +33 -6
- package/src/sdk/bus/slack-conversation.ts +5 -1
- package/src/sdk/bus/telegram-daemon-contract.ts +8 -1
- package/src/sdk/cli/session-cli.ts +161 -5
- package/src/sdk/client/discovery.ts +3 -1
- package/src/sdk/host/control/dispatch.ts +3 -0
- package/src/sdk/host/host.ts +7 -0
- package/src/sdk/host/model-pin.ts +185 -25
- package/src/sdk/host/sdk-run-capability.ts +1 -0
- package/src/sdk/host/session-runtime.test.ts +1240 -107
- package/src/sdk/host/session-runtime.ts +1029 -115
- package/src/sdk/prompt-deadline-manager.ts +16 -1
- package/src/sdk/protocol/adapter-validation.ts +27 -0
- package/src/sdk/protocol/operation-inventory.generated.json +2 -2
- package/src/sdk/protocol/operation-registry.ts +4 -1
- package/src/sdk/router/session-router.ts +297 -111
- package/src/sdk/session.ts +83 -12
- package/src/session/account-inventory.ts +27 -11
- package/src/session/agent-session.ts +887 -95
- package/src/session/fold-coordinator.ts +433 -0
- package/src/session/internal/managed-session-storage.ts +64 -26
- package/src/session/sdk-run-capability-internal.ts +15 -0
- package/src/session/sdk-run-capability.ts +2 -0
- package/src/session/session-manager.ts +29 -10
- package/src/setup/provider-presets.json +1 -1
- package/src/slash-commands/helpers/credential-switch.ts +6 -1
- package/src/task/executor.ts +19 -3
- package/src/telemetry/control.ts +26 -0
- package/src/telemetry/events.ts +142 -0
- package/src/telemetry/index.ts +3 -0
- package/src/telemetry/transport.ts +87 -0
- package/src/tools/bash-interactive.ts +182 -85
- package/src/tools/bash.ts +786 -67
- package/src/tools/index.ts +7 -5
- package/src/tools/path-utils.ts +77 -29
- package/src/tools/tmux-self-injection-guard.ts +359 -0
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/web/search/provider.ts +120 -11
- package/src/web/search/providers/anthropic.ts +89 -17
- package/src/web/search/providers/base.ts +9 -4
- package/src/web/search/providers/gemini.ts +87 -15
- package/src/web/search/providers/openai-compatible.ts +23 -8
- package/src/web/search/providers/xai.ts +98 -12
- package/src/web/search/types.ts +16 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { getAgentDir } from "@gajae-code/utils";
|
|
2
|
+
import {
|
|
3
|
+
getModelPresetRegistryStatus,
|
|
4
|
+
type ModelPresetRegistryStatus,
|
|
5
|
+
refreshModelPresetRegistry,
|
|
6
|
+
rollbackModelPresetRegistry,
|
|
7
|
+
setModelPresetRegistryDisabled,
|
|
8
|
+
setModelPresetRegistryPin,
|
|
9
|
+
} from "../config/model-preset-registry";
|
|
10
|
+
|
|
11
|
+
export const MODEL_PRESETS_ACTIONS = ["status", "refresh", "rollback", "pin", "unpin", "disable", "enable"] as const;
|
|
12
|
+
export type ModelPresetsAction = (typeof MODEL_PRESETS_ACTIONS)[number];
|
|
13
|
+
|
|
14
|
+
export interface ModelPresetsCommandArgs {
|
|
15
|
+
action: ModelPresetsAction;
|
|
16
|
+
revision?: string;
|
|
17
|
+
json?: boolean;
|
|
18
|
+
agentDir?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseRevision(value: string | undefined, action: "rollback" | "pin"): number {
|
|
22
|
+
if (!value || !/^\d+$/.test(value)) throw new Error(`${action} requires a positive accepted revision.`);
|
|
23
|
+
const revision = Number(value);
|
|
24
|
+
if (!Number.isSafeInteger(revision) || revision <= 0)
|
|
25
|
+
throw new Error(`${action} requires a positive accepted revision.`);
|
|
26
|
+
return revision;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function humanStatus(status: ModelPresetRegistryStatus): string {
|
|
30
|
+
const lines = [
|
|
31
|
+
`source: ${status.source}`,
|
|
32
|
+
`cache: ${status.cacheHealth}`,
|
|
33
|
+
`contract: ${status.contractVersion}`,
|
|
34
|
+
`active revision: ${status.activeRevisionId ?? status.activeRevision ?? "none"}`,
|
|
35
|
+
`highest seen revision: ${status.highestSeenRevision ?? "none"}`,
|
|
36
|
+
`pinned revision: ${status.pinnedRevision ?? "none"}`,
|
|
37
|
+
`disabled: ${status.disabled ? "yes" : "no"}`,
|
|
38
|
+
`profiles: ${status.profileCount}`,
|
|
39
|
+
`model presets: ${status.presetCount}`,
|
|
40
|
+
`history: ${status.historyRevisions.length > 0 ? status.historyRevisions.join(", ") : "none"}`,
|
|
41
|
+
];
|
|
42
|
+
if (status.manifestSha256) lines.push(`manifest sha256: ${status.manifestSha256}`);
|
|
43
|
+
if (status.snapshotSha256) lines.push(`snapshot sha256: ${status.snapshotSha256}`);
|
|
44
|
+
if (status.profilesSha256) lines.push(`profiles sha256: ${status.profilesSha256}`);
|
|
45
|
+
if (status.presetsSha256) lines.push(`presets sha256: ${status.presetsSha256}`);
|
|
46
|
+
if (status.keyId) lines.push(`signature key: ${status.keyId}`);
|
|
47
|
+
if (status.sourceRevision) lines.push(`source revision: ${status.sourceRevision}`);
|
|
48
|
+
if (status.acceptedAt) lines.push(`accepted: ${status.acceptedAt}`);
|
|
49
|
+
if (status.lastCheckedAt) lines.push(`last checked: ${status.lastCheckedAt}`);
|
|
50
|
+
if (status.retainedProfiles.length > 0)
|
|
51
|
+
lines.push(`retained removed profiles: ${status.retainedProfiles.join(", ")}`);
|
|
52
|
+
if (status.retainedPresets.length > 0) lines.push(`retained removed presets: ${status.retainedPresets.join(", ")}`);
|
|
53
|
+
if (status.lastError) lines.push(`last error: ${status.lastError}`);
|
|
54
|
+
return `${lines.join("\n")}\n`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function writeStatus(status: ModelPresetRegistryStatus, json: boolean): void {
|
|
58
|
+
process.stdout.write(json ? `${JSON.stringify(status)}\n` : humanStatus(status));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function runModelPresetsCommand(args: ModelPresetsCommandArgs): Promise<void> {
|
|
62
|
+
const agentDir = args.agentDir ?? getAgentDir();
|
|
63
|
+
const dependencies = { agentDir };
|
|
64
|
+
switch (args.action) {
|
|
65
|
+
case "status":
|
|
66
|
+
writeStatus(getModelPresetRegistryStatus(dependencies), args.json === true);
|
|
67
|
+
return;
|
|
68
|
+
case "refresh": {
|
|
69
|
+
const result = await refreshModelPresetRegistry(dependencies);
|
|
70
|
+
if (args.json) {
|
|
71
|
+
process.stdout.write(`${JSON.stringify({ result, status: getModelPresetRegistryStatus(dependencies) })}\n`);
|
|
72
|
+
} else {
|
|
73
|
+
process.stdout.write(
|
|
74
|
+
result.status === "updated"
|
|
75
|
+
? `Accepted preset registry revision ${result.revision}.\n`
|
|
76
|
+
: result.status === "not_modified"
|
|
77
|
+
? "Preset registry is already current.\n"
|
|
78
|
+
: "Preset registry refresh is disabled.\n",
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
case "rollback":
|
|
84
|
+
await rollbackModelPresetRegistry({ ...dependencies, revision: parseRevision(args.revision, "rollback") });
|
|
85
|
+
break;
|
|
86
|
+
case "pin":
|
|
87
|
+
await setModelPresetRegistryPin({ ...dependencies, revision: parseRevision(args.revision, "pin") });
|
|
88
|
+
break;
|
|
89
|
+
case "unpin":
|
|
90
|
+
await setModelPresetRegistryPin(dependencies);
|
|
91
|
+
break;
|
|
92
|
+
case "disable":
|
|
93
|
+
await setModelPresetRegistryDisabled({ ...dependencies, disabled: true });
|
|
94
|
+
break;
|
|
95
|
+
case "enable":
|
|
96
|
+
await setModelPresetRegistryDisabled({ ...dependencies, disabled: false });
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
writeStatus(getModelPresetRegistryStatus(dependencies), args.json === true);
|
|
100
|
+
}
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -17,6 +17,8 @@ import { isUpdateChannel, UPDATE_CHANNELS, type UpdateChannel } from "../config/
|
|
|
17
17
|
import { installDefaultGjcDefinitions } from "../defaults/gjc-defaults";
|
|
18
18
|
import { theme } from "../modes/theme/theme";
|
|
19
19
|
import { getNotificationConfig, type NotificationProvider, resolveNotificationProvider } from "../sdk/bus/config";
|
|
20
|
+
import type { TelemetryDetails, TelemetryEventName } from "../telemetry";
|
|
21
|
+
import { recordTelemetryEvent } from "../telemetry";
|
|
20
22
|
import { runDaemonCommand } from "./daemon-cli";
|
|
21
23
|
import {
|
|
22
24
|
fetchGithubChannelRelease,
|
|
@@ -163,11 +165,12 @@ function isPathInDirectory(filePath: string, directoryPath: string): boolean {
|
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
export type PackageManagerTarget = { manager: "npm"; packageName: string };
|
|
168
|
+
type MigrationUpdateTarget = { method: "migrate"; path: string; previousPath?: string };
|
|
166
169
|
export type UpdateTarget =
|
|
167
170
|
| { method: "bun" }
|
|
168
171
|
| { method: "npm"; packageName: string }
|
|
169
172
|
| { method: "binary"; path: string }
|
|
170
|
-
|
|
|
173
|
+
| MigrationUpdateTarget;
|
|
171
174
|
|
|
172
175
|
type PathPlatform = NodeJS.Platform;
|
|
173
176
|
type PackageExists = (packageName: string, packageRoot: string) => boolean;
|
|
@@ -506,6 +509,73 @@ async function verifyInstalledRuntime(
|
|
|
506
509
|
}
|
|
507
510
|
}
|
|
508
511
|
|
|
512
|
+
interface MigrationTargetVerificationOptions {
|
|
513
|
+
runtimePath: string;
|
|
514
|
+
verifyChecksum: () => Promise<void>;
|
|
515
|
+
verifyRuntime: () => Promise<InstalledVersionVerification>;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
interface MigrationChecksumOptions {
|
|
519
|
+
tag: string;
|
|
520
|
+
assetName: string;
|
|
521
|
+
filePath: string;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
type MigrationChecksumVerifier = (options: MigrationChecksumOptions) => Promise<unknown>;
|
|
525
|
+
|
|
526
|
+
async function verifyMigrationTargetWith(
|
|
527
|
+
options: MigrationTargetVerificationOptions,
|
|
528
|
+
): Promise<InstalledVersionVerification> {
|
|
529
|
+
try {
|
|
530
|
+
await options.verifyChecksum();
|
|
531
|
+
} catch {
|
|
532
|
+
return { ok: false, path: options.runtimePath };
|
|
533
|
+
}
|
|
534
|
+
return await options.verifyRuntime();
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
async function verifyMigrationTarget(
|
|
538
|
+
release: Pick<ReleaseInfo, "tag" | "version">,
|
|
539
|
+
runtimePath: string,
|
|
540
|
+
verifyChecksum: MigrationChecksumVerifier = verifyDownloadedBinaryChecksum,
|
|
541
|
+
verifyRuntime: (
|
|
542
|
+
expectedVersion: string,
|
|
543
|
+
runtimePath: string,
|
|
544
|
+
) => Promise<InstalledVersionVerification> = verifyInstalledRuntime,
|
|
545
|
+
): Promise<InstalledVersionVerification> {
|
|
546
|
+
return await verifyMigrationTargetWith({
|
|
547
|
+
runtimePath,
|
|
548
|
+
verifyChecksum: async () => {
|
|
549
|
+
await verifyChecksum({
|
|
550
|
+
tag: release.tag,
|
|
551
|
+
assetName: getBinaryName(),
|
|
552
|
+
filePath: runtimePath,
|
|
553
|
+
});
|
|
554
|
+
},
|
|
555
|
+
verifyRuntime: async () => await verifyRuntime(release.version, runtimePath),
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
export async function verifyMigrationTargetForTest(
|
|
560
|
+
options: MigrationTargetVerificationOptions,
|
|
561
|
+
): Promise<InstalledVersionVerification> {
|
|
562
|
+
return await verifyMigrationTargetWith(options);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
export async function verifyMigrationTargetAdapterForTest(options: {
|
|
566
|
+
release: Pick<ReleaseInfo, "tag" | "version">;
|
|
567
|
+
runtimePath: string;
|
|
568
|
+
verifyChecksum: MigrationChecksumVerifier;
|
|
569
|
+
verifyRuntime: (expectedVersion: string, runtimePath: string) => Promise<InstalledVersionVerification>;
|
|
570
|
+
}): Promise<InstalledVersionVerification> {
|
|
571
|
+
return await verifyMigrationTarget(
|
|
572
|
+
options.release,
|
|
573
|
+
options.runtimePath,
|
|
574
|
+
options.verifyChecksum,
|
|
575
|
+
options.verifyRuntime,
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
509
579
|
function printRestartGuidance(): void {
|
|
510
580
|
console.log(chalk.dim(`Restart ${APP_NAME} to use the new version`));
|
|
511
581
|
}
|
|
@@ -1062,6 +1132,7 @@ async function updateViaBinaryAt(
|
|
|
1062
1132
|
export interface UpdateCommandDependencies {
|
|
1063
1133
|
getLatestRelease?: (options?: LatestReleaseLookupOptions) => Promise<ReleaseInfo>;
|
|
1064
1134
|
resolveUpdateTarget?: () => Promise<UpdateTarget>;
|
|
1135
|
+
verifyMigrationTarget?: (release: ReleaseInfo, runtimePath: string) => Promise<InstalledVersionVerification>;
|
|
1065
1136
|
performUpdate?: (
|
|
1066
1137
|
target: UpdateTarget,
|
|
1067
1138
|
expectedVersion: string,
|
|
@@ -1073,6 +1144,7 @@ export interface UpdateCommandDependencies {
|
|
|
1073
1144
|
restartDaemon?: (settings: Settings) => Promise<void>;
|
|
1074
1145
|
recoverNotifications?: (settings: Settings) => Promise<void>;
|
|
1075
1146
|
runPostUpdateRecovery?: (runtimePath: string) => Promise<void>;
|
|
1147
|
+
recordTelemetryEvent?: (event: TelemetryEventName, details: TelemetryDetails) => unknown;
|
|
1076
1148
|
exit?: (code: number) => never;
|
|
1077
1149
|
}
|
|
1078
1150
|
|
|
@@ -1265,6 +1337,24 @@ export function resolveUpdateDecision(options: {
|
|
|
1265
1337
|
return { install: true, kind: options.comparison > 0 ? "new-version" : "force" };
|
|
1266
1338
|
}
|
|
1267
1339
|
|
|
1340
|
+
function printVerifiedMigrationTarget(target: MigrationUpdateTarget, version: string): void {
|
|
1341
|
+
console.log(
|
|
1342
|
+
chalk.green(
|
|
1343
|
+
`${theme.status.success} Standalone ${APP_NAME} ${version} is already installed and verified at ${target.path}`,
|
|
1344
|
+
),
|
|
1345
|
+
);
|
|
1346
|
+
if (target.previousPath) {
|
|
1347
|
+
console.log(chalk.yellow(`${target.previousPath} shadows it on PATH.`));
|
|
1348
|
+
console.log(
|
|
1349
|
+
chalk.cyan(
|
|
1350
|
+
`The standalone directory ${path.dirname(target.path)} must precede the shim directory ${path.dirname(target.previousPath)} on PATH.`,
|
|
1351
|
+
),
|
|
1352
|
+
);
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
console.log(chalk.cyan(`Ensure the standalone directory ${path.dirname(target.path)} is on PATH.`));
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1268
1358
|
export async function runUpdateCommand(
|
|
1269
1359
|
opts: UpdateCommandOptions,
|
|
1270
1360
|
deps: UpdateCommandDependencies = {},
|
|
@@ -1272,9 +1362,28 @@ export async function runUpdateCommand(
|
|
|
1272
1362
|
const channel = opts.channel ?? "stable";
|
|
1273
1363
|
const lookupRelease = deps.getLatestRelease ?? getLatestRelease;
|
|
1274
1364
|
const resolveTarget = deps.resolveUpdateTarget ?? resolveUpdateTarget;
|
|
1365
|
+
const verifyTarget = deps.verifyMigrationTarget ?? verifyMigrationTarget;
|
|
1275
1366
|
const update = deps.performUpdate ?? performUpdate;
|
|
1276
1367
|
const refreshDefaults = deps.refreshInstalledDefaultSkills ?? refreshInstalledDefaultSkills;
|
|
1277
1368
|
const exit = deps.exit ?? process.exit;
|
|
1369
|
+
const recordEvent = deps.recordTelemetryEvent ?? ((event, details) => recordTelemetryEvent(event, details));
|
|
1370
|
+
const pendingTelemetry = new Set<Promise<void>>();
|
|
1371
|
+
const record = (event: TelemetryEventName, details: TelemetryDetails): void => {
|
|
1372
|
+
const result = recordEvent(event, details);
|
|
1373
|
+
if (result !== null && (typeof result === "object" || typeof result === "function") && "then" in result) {
|
|
1374
|
+
const pending = Promise.resolve(result as PromiseLike<unknown>).then(
|
|
1375
|
+
() => undefined,
|
|
1376
|
+
() => undefined,
|
|
1377
|
+
);
|
|
1378
|
+
pendingTelemetry.add(pending);
|
|
1379
|
+
void pending.finally(() => pendingTelemetry.delete(pending));
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
const flushTelemetryBeforeExit = async (): Promise<never> => {
|
|
1383
|
+
await Promise.race([Promise.allSettled([...pendingTelemetry]), Bun.sleep(2000)]);
|
|
1384
|
+
return exit(1);
|
|
1385
|
+
};
|
|
1386
|
+
record("update_check_started", { channel });
|
|
1278
1387
|
|
|
1279
1388
|
console.log(chalk.dim(`Current version: ${VERSION}`));
|
|
1280
1389
|
if (channel !== "stable") {
|
|
@@ -1285,16 +1394,18 @@ export async function runUpdateCommand(
|
|
|
1285
1394
|
try {
|
|
1286
1395
|
target = await resolveTarget();
|
|
1287
1396
|
} catch (err) {
|
|
1397
|
+
record("update_check_completed", { channel, result: "failed" });
|
|
1288
1398
|
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
1289
|
-
return
|
|
1399
|
+
return flushTelemetryBeforeExit();
|
|
1290
1400
|
}
|
|
1291
1401
|
|
|
1292
1402
|
let release: ReleaseInfo;
|
|
1293
1403
|
try {
|
|
1294
1404
|
release = await lookupRelease({ channel });
|
|
1295
1405
|
} catch (err) {
|
|
1406
|
+
record("update_check_completed", { channel, result: "failed" });
|
|
1296
1407
|
console.error(chalk.red(`Failed to check for updates: ${err}`));
|
|
1297
|
-
return
|
|
1408
|
+
return flushTelemetryBeforeExit();
|
|
1298
1409
|
}
|
|
1299
1410
|
|
|
1300
1411
|
// A config file that exists but could not be read changes which registry
|
|
@@ -1307,12 +1418,13 @@ export async function runUpdateCommand(
|
|
|
1307
1418
|
try {
|
|
1308
1419
|
comparison = compareVersions(release.version, VERSION);
|
|
1309
1420
|
} catch (err) {
|
|
1421
|
+
record("update_check_completed", { channel, result: "failed" });
|
|
1310
1422
|
console.error(
|
|
1311
1423
|
chalk.red(
|
|
1312
1424
|
`Failed to check for updates: the ${channel} channel reported an unparseable version "${release.version}": ${err instanceof Error ? err.message : String(err)}`,
|
|
1313
1425
|
),
|
|
1314
1426
|
);
|
|
1315
|
-
return
|
|
1427
|
+
return flushTelemetryBeforeExit();
|
|
1316
1428
|
}
|
|
1317
1429
|
|
|
1318
1430
|
const decision = resolveUpdateDecision({
|
|
@@ -1323,7 +1435,24 @@ export async function runUpdateCommand(
|
|
|
1323
1435
|
migrate: target?.method === "migrate",
|
|
1324
1436
|
});
|
|
1325
1437
|
|
|
1438
|
+
if (target.method === "migrate" && decision.install && !opts.force) {
|
|
1439
|
+
const releaseLock = await acquireBinaryUpdateLock(target.path);
|
|
1440
|
+
try {
|
|
1441
|
+
const verification = await verifyTarget(release, target.path);
|
|
1442
|
+
if (verification.ok) {
|
|
1443
|
+
record("update_check_completed", { channel, result: "available" });
|
|
1444
|
+
record("update_install_started", { channel, installMethod: target.method });
|
|
1445
|
+
printVerifiedMigrationTarget(target, release.version);
|
|
1446
|
+
record("update_install_completed", { channel, result: "installed", installMethod: target.method });
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
} finally {
|
|
1450
|
+
await releaseLock();
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1326
1454
|
if (!decision.install) {
|
|
1455
|
+
record("update_check_completed", { channel, result: "up_to_date" });
|
|
1327
1456
|
console.log(chalk.green(`${theme.status.success} Already up to date`));
|
|
1328
1457
|
return;
|
|
1329
1458
|
}
|
|
@@ -1338,9 +1467,14 @@ export async function runUpdateCommand(
|
|
|
1338
1467
|
console.log(chalk.yellow(`Forcing reinstall of ${release.version}`));
|
|
1339
1468
|
}
|
|
1340
1469
|
|
|
1341
|
-
|
|
1470
|
+
record("update_check_completed", { channel, result: "available" });
|
|
1471
|
+
if (opts.check) {
|
|
1472
|
+
record("update_install_completed", { channel, result: "skipped" });
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1342
1475
|
|
|
1343
1476
|
let installedVersion: string | undefined;
|
|
1477
|
+
record("update_install_started", { channel, installMethod: target.method });
|
|
1344
1478
|
try {
|
|
1345
1479
|
const resolved = target ?? (await resolveTarget());
|
|
1346
1480
|
const verification = await update(resolved, release.version, release.registry);
|
|
@@ -1349,16 +1483,18 @@ export async function runUpdateCommand(
|
|
|
1349
1483
|
await (deps.runPostUpdateRecovery ?? runPostUpdateRecovery)(verification.path);
|
|
1350
1484
|
} else if (!deps.performUpdate) throw new Error("verified installed runtime path is unavailable");
|
|
1351
1485
|
} catch (err) {
|
|
1486
|
+
record("update_install_failed", { channel, result: "failed", installMethod: target.method });
|
|
1352
1487
|
const prefix = installedVersion
|
|
1353
1488
|
? `Updated to ${installedVersion}, but post-update recovery failed`
|
|
1354
1489
|
: "Update failed";
|
|
1355
1490
|
console.error(chalk.red(`${prefix}: ${err}`));
|
|
1356
|
-
return
|
|
1491
|
+
return flushTelemetryBeforeExit();
|
|
1357
1492
|
}
|
|
1358
1493
|
|
|
1359
1494
|
// The installed runtime completes recovery before this old updater process
|
|
1360
1495
|
// refreshes opt-in local definitions, avoiding stale-module daemon control.
|
|
1361
1496
|
await refreshDefaults();
|
|
1497
|
+
record("update_install_completed", { channel, result: "installed", installMethod: target.method });
|
|
1362
1498
|
}
|
|
1363
1499
|
|
|
1364
1500
|
/**
|
package/src/cli.ts
CHANGED
|
@@ -54,6 +54,7 @@ export const commands: CommandEntry[] = [
|
|
|
54
54
|
{ name: "daemon", load: () => import("./commands/daemon").then(m => m.default) },
|
|
55
55
|
{ name: "web-search", aliases: ["q"], load: () => import("./commands/web-search").then(m => m.default) },
|
|
56
56
|
{ name: "local-provider", load: () => import("./commands/local-provider").then(m => m.default) },
|
|
57
|
+
{ name: "model-presets", load: () => import("./commands/model-presets").then(m => m.default) },
|
|
57
58
|
{ name: "mcp-serve", load: () => import("./commands/mcp-serve").then(m => m.default) },
|
|
58
59
|
{ name: "mcp", load: () => import("./commands/mcp").then(m => m.default) },
|
|
59
60
|
{
|
|
@@ -364,6 +365,7 @@ function routeLegacyRootArgv(argv: readonly string[]): string[] | undefined {
|
|
|
364
365
|
export function routeModelsAlias(argv: readonly string[]): string[] | undefined {
|
|
365
366
|
if (argv[0] !== "models") return undefined;
|
|
366
367
|
const rest = argv.slice(1);
|
|
368
|
+
if (rest[0] === "presets") return ["model-presets", ...rest.slice(1)];
|
|
367
369
|
if (rest.length === 0) return ["launch", "--list-models"];
|
|
368
370
|
// Pure search tokens become a single fuzzy pattern (matches --list-models).
|
|
369
371
|
if (rest.every(token => !token.startsWith("-") && !token.startsWith("@"))) {
|
|
@@ -461,7 +463,9 @@ export async function runCli(argv: string[]): Promise<void> {
|
|
|
461
463
|
}
|
|
462
464
|
const normalizedArgv = normalizeResumeAlias(argv);
|
|
463
465
|
const legacyArgv = routeLegacyRootArgv(normalizedArgv);
|
|
464
|
-
|
|
466
|
+
const modelPresetsArgv =
|
|
467
|
+
normalizedArgv[0] === "models" && normalizedArgv[1] === "presets" ? routeModelsAlias(normalizedArgv) : undefined;
|
|
468
|
+
if (!legacyArgv && !modelPresetsArgv && hasRootHelpFlag(normalizedArgv)) {
|
|
465
469
|
const { renderRootHelp } = await import("@gajae-code/utils/cli");
|
|
466
470
|
const { getExtraHelpText } = await import("./cli/fast-help");
|
|
467
471
|
renderRootHelp({ bin: APP_NAME, version: VERSION, commands: new Map([["launch", RootHelpCommand]]) });
|
|
@@ -475,7 +479,7 @@ export async function runCli(argv: string[]): Promise<void> {
|
|
|
475
479
|
process.stdout.write(`${APP_NAME}/${VERSION}\n`);
|
|
476
480
|
return;
|
|
477
481
|
}
|
|
478
|
-
const runArgv = legacyArgv ?? routeRootArgv(normalizedArgv);
|
|
482
|
+
const runArgv = legacyArgv ?? modelPresetsArgv ?? routeRootArgv(normalizedArgv);
|
|
479
483
|
if (isStatsHelpFastPath(runArgv)) {
|
|
480
484
|
showStatsFastHelp();
|
|
481
485
|
return;
|
|
@@ -22,24 +22,27 @@ export default class AuthGateway extends Command {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
static flags = {
|
|
25
|
-
json: Flags.boolean({ description: "Output JSON (token/status)" }),
|
|
25
|
+
json: Flags.boolean({ description: "Output JSON (token/status/check)" }),
|
|
26
26
|
bind: Flags.string({ description: "Bind address for `serve` (host:port)", char: "b" }),
|
|
27
|
+
provider: Flags.string({
|
|
28
|
+
description: "Required provider scope for `serve`; also filters `status` and `check`",
|
|
29
|
+
}),
|
|
27
30
|
regenerate: Flags.boolean({ description: "Regenerate the gateway bearer token (token)" }),
|
|
28
31
|
"no-auth": Flags.boolean({
|
|
29
32
|
description:
|
|
30
|
-
"Disable inbound bearer-token auth (serve).
|
|
33
|
+
"Disable inbound bearer-token auth (serve). Loopback non-browser clients without an Origin header are allowed.",
|
|
31
34
|
}),
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
static examples = [
|
|
35
|
-
"# Boot
|
|
36
|
-
"# Boot on a non-default port\n gjc auth-gateway serve --bind=127.0.0.1:4000",
|
|
38
|
+
"# Boot a provider-scoped gateway against the configured broker\n gjc auth-gateway serve --provider=openai-codex",
|
|
39
|
+
"# Boot on a non-default port\n gjc auth-gateway serve --provider=openai-codex --bind=127.0.0.1:4000",
|
|
37
40
|
"# Print the gateway bearer token (creates one on first run)\n gjc auth-gateway token",
|
|
38
41
|
"# Rotate the gateway bearer token\n gjc auth-gateway token --regenerate",
|
|
39
|
-
"# Run on loopback
|
|
40
|
-
"# Show local gateway + broker config status\n gjc auth-gateway status",
|
|
41
|
-
"# Probe
|
|
42
|
-
"# Same, machine-readable for scripts\n gjc auth-gateway check --json",
|
|
42
|
+
"# Run the scoped gateway on loopback for non-browser local clients without a bearer\n gjc auth-gateway serve --provider=openai-codex --no-auth",
|
|
43
|
+
"# Show scoped local gateway + broker config status\n gjc auth-gateway status --provider=openai-codex",
|
|
44
|
+
"# Probe credentials for one gateway scope\n gjc auth-gateway check --provider=openai-codex",
|
|
45
|
+
"# Same, machine-readable for scripts\n gjc auth-gateway check --provider=openai-codex --json",
|
|
43
46
|
];
|
|
44
47
|
|
|
45
48
|
async run(): Promise<void> {
|
|
@@ -53,6 +56,7 @@ export default class AuthGateway extends Command {
|
|
|
53
56
|
flags: {
|
|
54
57
|
json: flags.json,
|
|
55
58
|
bind: flags.bind,
|
|
59
|
+
provider: flags.provider,
|
|
56
60
|
regenerate: flags.regenerate,
|
|
57
61
|
noAuth: flags["no-auth"],
|
|
58
62
|
},
|
package/src/commands/gc.ts
CHANGED
|
@@ -20,6 +20,11 @@ function resolveDiskPolicyFromSettings(): Partial<GcDiskPolicy> | undefined {
|
|
|
20
20
|
export default class Gc extends Command {
|
|
21
21
|
static description = "Garbage-collect stale GJC session/PID records (dry-run by default)";
|
|
22
22
|
static strict = false;
|
|
23
|
+
// The hand parser in gc-runtime owns the real syntax (repeatable space-form
|
|
24
|
+
// operands, dash-prefix rejection, orphan-operand rules); delegate help so the
|
|
25
|
+
// public output is the authoritative gcHelpText() instead of generic flag
|
|
26
|
+
// metadata that would advertise unsupported `--flag=<value>` forms.
|
|
27
|
+
static delegateHelp = true;
|
|
23
28
|
static flags = {
|
|
24
29
|
json: Flags.boolean({ char: "j", description: "Emit machine-readable JSON", default: false }),
|
|
25
30
|
prune: Flags.boolean({ description: "Remove stale records (default: report only)", default: false }),
|
|
@@ -33,6 +38,18 @@ export default class Gc extends Command {
|
|
|
33
38
|
description: "Quarantine a corrupt session-index suffix and retain its valid prefix",
|
|
34
39
|
default: false,
|
|
35
40
|
}),
|
|
41
|
+
"empty-delete-receipts": Flags.boolean({
|
|
42
|
+
description: "Report (and with --prune, prune) empty .gjc-delete-* receipts under --root/--manifest",
|
|
43
|
+
default: false,
|
|
44
|
+
}),
|
|
45
|
+
root: Flags.string({
|
|
46
|
+
description: "Operand root for --empty-delete-receipts (repeatable)",
|
|
47
|
+
multiple: true,
|
|
48
|
+
}),
|
|
49
|
+
manifest: Flags.string({
|
|
50
|
+
description: 'JSON {"roots":[...]} file for --empty-delete-receipts (repeatable)',
|
|
51
|
+
multiple: true,
|
|
52
|
+
}),
|
|
36
53
|
};
|
|
37
54
|
|
|
38
55
|
static examples = [
|
|
@@ -44,6 +61,8 @@ export default class Gc extends Command {
|
|
|
44
61
|
"gjc gc --disk --json",
|
|
45
62
|
"gjc gc --disk --prune",
|
|
46
63
|
"gjc gc --repair-session-index --json",
|
|
64
|
+
"gjc gc --empty-delete-receipts --root ~/.gjc/agent/session-states",
|
|
65
|
+
"gjc gc --empty-delete-receipts --manifest receipts-manifest.json --prune --json",
|
|
47
66
|
];
|
|
48
67
|
|
|
49
68
|
async run(): Promise<void> {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
2
|
+
import { MODEL_PRESETS_ACTIONS, type ModelPresetsAction, runModelPresetsCommand } from "../cli/model-presets-cli";
|
|
3
|
+
|
|
4
|
+
export default class ModelPresets extends Command {
|
|
5
|
+
static description = "Manage the signed model preset registry";
|
|
6
|
+
|
|
7
|
+
static args = {
|
|
8
|
+
action: Args.string({ description: "Action", required: false, options: MODEL_PRESETS_ACTIONS }),
|
|
9
|
+
revision: Args.string({ description: "Accepted revision for pin or rollback", required: false }),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
static flags = {
|
|
13
|
+
json: Flags.boolean({ description: "Output JSON" }),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
async run(): Promise<void> {
|
|
17
|
+
const { args, flags } = await this.parse(ModelPresets);
|
|
18
|
+
await runModelPresetsCommand({
|
|
19
|
+
action: (args.action ?? "status") as ModelPresetsAction,
|
|
20
|
+
revision: args.revision,
|
|
21
|
+
json: flags.json,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/commands/sdk.ts
CHANGED
|
@@ -838,6 +838,10 @@ class SdkSessionHelp extends Command {
|
|
|
838
838
|
description: "Workspace directory for saved-session resolution (default: current directory)",
|
|
839
839
|
}),
|
|
840
840
|
op: Flags.string({ description: "Raw control or global operation" }),
|
|
841
|
+
scope: Flags.string({
|
|
842
|
+
description: "list scope: repo (default), cwd, worktree, or all",
|
|
843
|
+
options: ["repo", "cwd", "worktree", "all"],
|
|
844
|
+
}),
|
|
841
845
|
query: Flags.string({ description: "Raw query name" }),
|
|
842
846
|
"json-input": Flags.string({ description: "SDK request JSON object" }),
|
|
843
847
|
"json-input-file": Flags.string({ description: "Read SDK request JSON from a 0600 file" }),
|
|
@@ -894,6 +898,7 @@ class SdkSessionCommand extends Command {
|
|
|
894
898
|
allEvents: Boolean(flagRec["all-events"]),
|
|
895
899
|
agentDir: flagRec["agent-dir"] as string | undefined,
|
|
896
900
|
repo: flagRec.repo as string | undefined,
|
|
901
|
+
scope: flagRec.scope as string | undefined,
|
|
897
902
|
});
|
|
898
903
|
}
|
|
899
904
|
}
|
|
@@ -146,6 +146,7 @@ export const TIER_MAP_SKIP_LIST = {
|
|
|
146
146
|
},
|
|
147
147
|
"vercel-ai-gateway/google/gemini-3.7-flash": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
148
148
|
"zai/glm-5.3": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
149
|
+
"zai/glm-5.3-flash": { rationale: "post-feature catalog addition; not yet curated" },
|
|
149
150
|
"cursor/gemini-3.7-flash-high": {
|
|
150
151
|
rationale: "post-rebase catalog addition from dev; not yet curated",
|
|
151
152
|
},
|
|
@@ -5885,6 +5886,38 @@ export const TIER_MAP_SKIP_LIST = {
|
|
|
5885
5886
|
"zenmux/z-ai/glm-5.2": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
5886
5887
|
"zenmux/z-ai/glm-5.2-free": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
5887
5888
|
"zenmux/z-ai/glm-5v-turbo": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
5889
|
+
"kiro/auto": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5890
|
+
"kiro/claude-haiku-4-5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5891
|
+
"kiro/claude-haiku-4.5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5892
|
+
"kiro/claude-opus-4-5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5893
|
+
"kiro/claude-opus-4-6": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5894
|
+
"kiro/claude-opus-4-7": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5895
|
+
"kiro/claude-opus-4-8": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5896
|
+
"kiro/claude-opus-4.5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5897
|
+
"kiro/claude-opus-4.6": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5898
|
+
"kiro/claude-opus-4.7": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5899
|
+
"kiro/claude-opus-4.8": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5900
|
+
"kiro/claude-opus-5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5901
|
+
"kiro/claude-sonnet-4": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5902
|
+
"kiro/claude-sonnet-4-5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5903
|
+
"kiro/claude-sonnet-4-6": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5904
|
+
"kiro/claude-sonnet-4.5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5905
|
+
"kiro/claude-sonnet-4.6": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5906
|
+
"kiro/claude-sonnet-5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5907
|
+
"kiro/deepseek-3-2": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5908
|
+
"kiro/deepseek-3.2": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5909
|
+
"kiro/glm-5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5910
|
+
"kiro/gpt-5-6-luna": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5911
|
+
"kiro/gpt-5-6-sol": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5912
|
+
"kiro/gpt-5-6-terra": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5913
|
+
"kiro/gpt-5.6-luna": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5914
|
+
"kiro/gpt-5.6-sol": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5915
|
+
"kiro/gpt-5.6-terra": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5916
|
+
"kiro/minimax-m2-1": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5917
|
+
"kiro/minimax-m2-5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5918
|
+
"kiro/minimax-m2.1": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5919
|
+
"kiro/minimax-m2.5": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5920
|
+
"kiro/qwen3-coder-next": { rationale: "Kiro API-key catalog addition; not yet curated" },
|
|
5888
5921
|
} as const satisfies TierMapSkipList;
|
|
5889
5922
|
|
|
5890
5923
|
export const CURATED_TIER_MAP: AutoroutingCuratedTierMap = {
|
|
@@ -17,7 +17,7 @@ import type {
|
|
|
17
17
|
} from "../gjc-runtime/gc-runtime";
|
|
18
18
|
import { gcPidStatusLabel } from "../gjc-runtime/gc-runtime";
|
|
19
19
|
import { resolveReceiptSpoolDir } from "../harness-control-plane/receipt-spool";
|
|
20
|
-
import {
|
|
20
|
+
import { readFileLockObservationForGc, removeFileLockDirForGc } from "./file-lock";
|
|
21
21
|
|
|
22
22
|
const MAX_WALK_DEPTH = 6;
|
|
23
23
|
/** Default per-root walk budget. Truncation is a warning, not a hard error. */
|
|
@@ -68,7 +68,8 @@ function keptMalformedRecord(lockDir: string): GcRecord {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
async function collectLockRecord(lockDir: string, ctx: GcContext): Promise<GcRecord> {
|
|
71
|
-
const
|
|
71
|
+
const observation = await readFileLockObservationForGc(lockDir);
|
|
72
|
+
const info = observation?.info;
|
|
72
73
|
if (!info) return keptMalformedRecord(lockDir);
|
|
73
74
|
if (info.owner_host_id !== undefined) {
|
|
74
75
|
return {
|
|
@@ -203,7 +204,8 @@ export const fileLocksGcAdapter: GcStoreAdapter = {
|
|
|
203
204
|
},
|
|
204
205
|
async prune(record: GcRecord, ctx: GcContext): Promise<GcPruneOutcome> {
|
|
205
206
|
const lockDir = record.path ?? record.id;
|
|
206
|
-
const
|
|
207
|
+
const observation = await readFileLockObservationForGc(lockDir);
|
|
208
|
+
const info = observation?.info;
|
|
207
209
|
if (!info) return { removed: false, skipped: "lock_no_longer_dead_or_missing" };
|
|
208
210
|
if (info.owner_host_id !== undefined) {
|
|
209
211
|
return { removed: false, skipped: "host_qualified_lock_requires_owner_reclamation" };
|
|
@@ -220,13 +222,16 @@ export const fileLocksGcAdapter: GcStoreAdapter = {
|
|
|
220
222
|
// so removal re-verifies the on-disk identity under the unlink and refuses
|
|
221
223
|
// to delete a recreated LIVE lock (TOCTOU).
|
|
222
224
|
try {
|
|
223
|
-
const removal = await removeFileLockDirForGc(lockDir, info);
|
|
225
|
+
const removal = await removeFileLockDirForGc(lockDir, info, observation?.identity);
|
|
224
226
|
if (removal === "owner_changed") {
|
|
225
227
|
return { removed: false, skipped: "file_lock_owner_changed_before_delete" };
|
|
226
228
|
}
|
|
227
229
|
if (removal === "missing") {
|
|
228
230
|
return { removed: false, skipped: "lock_no_longer_dead_or_missing" };
|
|
229
231
|
}
|
|
232
|
+
if (removal === "cleanup_failed") {
|
|
233
|
+
return { removed: false, skipped: "lock_removal_denied_by_native_identity_guard" };
|
|
234
|
+
}
|
|
230
235
|
return { removed: true };
|
|
231
236
|
} catch (error) {
|
|
232
237
|
return { removed: false, error: errorMessage(error) };
|