@gajae-code/coding-agent 0.15.5 → 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 +26 -1
- 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 +2 -0
- 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 +96 -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 +2 -5
- 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/client/discovery.d.ts +1 -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 +15 -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 -7
- package/dist/types/session/fold-coordinator.d.ts +201 -0
- 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/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 +40 -5
- 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/config/autorouting-tier-map.ts +32 -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 +51 -9
- package/src/config/model-registry.ts +1021 -122
- 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/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 +2 -3
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +1 -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/session-state-lock.ts +1242 -141
- package/src/gjc-runtime/session-state-sidecar.ts +76 -3
- package/src/index.ts +1 -0
- package/src/internal-urls/docs-index.generated.ts +9 -8
- 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/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 +36 -6
- package/src/sdk/bus/prompt-reconciliation.ts +28 -4
- package/src/sdk/bus/slack-conversation.ts +5 -1
- package/src/sdk/cli/session-cli.ts +12 -1
- package/src/sdk/client/discovery.ts +3 -1
- package/src/sdk/host/control/dispatch.ts +3 -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 +371 -37
- package/src/sdk/host/session-runtime.ts +364 -52
- 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 +228 -96
- package/src/sdk/session.ts +83 -12
- package/src/session/account-inventory.ts +27 -11
- package/src/session/agent-session.ts +678 -103
- package/src/session/fold-coordinator.ts +433 -0
- 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 +5 -4
- 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 +772 -67
- package/src/tools/index.ts +7 -5
- 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,
|
|
@@ -1142,6 +1144,7 @@ export interface UpdateCommandDependencies {
|
|
|
1142
1144
|
restartDaemon?: (settings: Settings) => Promise<void>;
|
|
1143
1145
|
recoverNotifications?: (settings: Settings) => Promise<void>;
|
|
1144
1146
|
runPostUpdateRecovery?: (runtimePath: string) => Promise<void>;
|
|
1147
|
+
recordTelemetryEvent?: (event: TelemetryEventName, details: TelemetryDetails) => unknown;
|
|
1145
1148
|
exit?: (code: number) => never;
|
|
1146
1149
|
}
|
|
1147
1150
|
|
|
@@ -1363,6 +1366,24 @@ export async function runUpdateCommand(
|
|
|
1363
1366
|
const update = deps.performUpdate ?? performUpdate;
|
|
1364
1367
|
const refreshDefaults = deps.refreshInstalledDefaultSkills ?? refreshInstalledDefaultSkills;
|
|
1365
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 });
|
|
1366
1387
|
|
|
1367
1388
|
console.log(chalk.dim(`Current version: ${VERSION}`));
|
|
1368
1389
|
if (channel !== "stable") {
|
|
@@ -1373,16 +1394,18 @@ export async function runUpdateCommand(
|
|
|
1373
1394
|
try {
|
|
1374
1395
|
target = await resolveTarget();
|
|
1375
1396
|
} catch (err) {
|
|
1397
|
+
record("update_check_completed", { channel, result: "failed" });
|
|
1376
1398
|
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
1377
|
-
return
|
|
1399
|
+
return flushTelemetryBeforeExit();
|
|
1378
1400
|
}
|
|
1379
1401
|
|
|
1380
1402
|
let release: ReleaseInfo;
|
|
1381
1403
|
try {
|
|
1382
1404
|
release = await lookupRelease({ channel });
|
|
1383
1405
|
} catch (err) {
|
|
1406
|
+
record("update_check_completed", { channel, result: "failed" });
|
|
1384
1407
|
console.error(chalk.red(`Failed to check for updates: ${err}`));
|
|
1385
|
-
return
|
|
1408
|
+
return flushTelemetryBeforeExit();
|
|
1386
1409
|
}
|
|
1387
1410
|
|
|
1388
1411
|
// A config file that exists but could not be read changes which registry
|
|
@@ -1395,12 +1418,13 @@ export async function runUpdateCommand(
|
|
|
1395
1418
|
try {
|
|
1396
1419
|
comparison = compareVersions(release.version, VERSION);
|
|
1397
1420
|
} catch (err) {
|
|
1421
|
+
record("update_check_completed", { channel, result: "failed" });
|
|
1398
1422
|
console.error(
|
|
1399
1423
|
chalk.red(
|
|
1400
1424
|
`Failed to check for updates: the ${channel} channel reported an unparseable version "${release.version}": ${err instanceof Error ? err.message : String(err)}`,
|
|
1401
1425
|
),
|
|
1402
1426
|
);
|
|
1403
|
-
return
|
|
1427
|
+
return flushTelemetryBeforeExit();
|
|
1404
1428
|
}
|
|
1405
1429
|
|
|
1406
1430
|
const decision = resolveUpdateDecision({
|
|
@@ -1416,7 +1440,10 @@ export async function runUpdateCommand(
|
|
|
1416
1440
|
try {
|
|
1417
1441
|
const verification = await verifyTarget(release, target.path);
|
|
1418
1442
|
if (verification.ok) {
|
|
1443
|
+
record("update_check_completed", { channel, result: "available" });
|
|
1444
|
+
record("update_install_started", { channel, installMethod: target.method });
|
|
1419
1445
|
printVerifiedMigrationTarget(target, release.version);
|
|
1446
|
+
record("update_install_completed", { channel, result: "installed", installMethod: target.method });
|
|
1420
1447
|
return;
|
|
1421
1448
|
}
|
|
1422
1449
|
} finally {
|
|
@@ -1425,6 +1452,7 @@ export async function runUpdateCommand(
|
|
|
1425
1452
|
}
|
|
1426
1453
|
|
|
1427
1454
|
if (!decision.install) {
|
|
1455
|
+
record("update_check_completed", { channel, result: "up_to_date" });
|
|
1428
1456
|
console.log(chalk.green(`${theme.status.success} Already up to date`));
|
|
1429
1457
|
return;
|
|
1430
1458
|
}
|
|
@@ -1439,9 +1467,14 @@ export async function runUpdateCommand(
|
|
|
1439
1467
|
console.log(chalk.yellow(`Forcing reinstall of ${release.version}`));
|
|
1440
1468
|
}
|
|
1441
1469
|
|
|
1442
|
-
|
|
1470
|
+
record("update_check_completed", { channel, result: "available" });
|
|
1471
|
+
if (opts.check) {
|
|
1472
|
+
record("update_install_completed", { channel, result: "skipped" });
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1443
1475
|
|
|
1444
1476
|
let installedVersion: string | undefined;
|
|
1477
|
+
record("update_install_started", { channel, installMethod: target.method });
|
|
1445
1478
|
try {
|
|
1446
1479
|
const resolved = target ?? (await resolveTarget());
|
|
1447
1480
|
const verification = await update(resolved, release.version, release.registry);
|
|
@@ -1450,16 +1483,18 @@ export async function runUpdateCommand(
|
|
|
1450
1483
|
await (deps.runPostUpdateRecovery ?? runPostUpdateRecovery)(verification.path);
|
|
1451
1484
|
} else if (!deps.performUpdate) throw new Error("verified installed runtime path is unavailable");
|
|
1452
1485
|
} catch (err) {
|
|
1486
|
+
record("update_install_failed", { channel, result: "failed", installMethod: target.method });
|
|
1453
1487
|
const prefix = installedVersion
|
|
1454
1488
|
? `Updated to ${installedVersion}, but post-update recovery failed`
|
|
1455
1489
|
: "Update failed";
|
|
1456
1490
|
console.error(chalk.red(`${prefix}: ${err}`));
|
|
1457
|
-
return
|
|
1491
|
+
return flushTelemetryBeforeExit();
|
|
1458
1492
|
}
|
|
1459
1493
|
|
|
1460
1494
|
// The installed runtime completes recovery before this old updater process
|
|
1461
1495
|
// refreshes opt-in local definitions, avoiding stale-module daemon control.
|
|
1462
1496
|
await refreshDefaults();
|
|
1497
|
+
record("update_install_completed", { channel, result: "installed", installMethod: target.method });
|
|
1463
1498
|
}
|
|
1464
1499
|
|
|
1465
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
|
+
}
|
|
@@ -5886,6 +5886,38 @@ export const TIER_MAP_SKIP_LIST = {
|
|
|
5886
5886
|
"zenmux/z-ai/glm-5.2": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
5887
5887
|
"zenmux/z-ai/glm-5.2-free": { baseline: true, rationale: "pre-feature baseline; not yet curated" },
|
|
5888
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" },
|
|
5889
5921
|
} as const satisfies TierMapSkipList;
|
|
5890
5922
|
|
|
5891
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) };
|