@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
|
@@ -17,6 +17,7 @@ import * as crypto from "node:crypto";
|
|
|
17
17
|
import * as fs from "node:fs/promises";
|
|
18
18
|
import * as os from "node:os";
|
|
19
19
|
import * as path from "node:path";
|
|
20
|
+
import * as readline from "node:readline";
|
|
20
21
|
import { cleanReason } from "@gajae-code/ai/auth-broker/redact";
|
|
21
22
|
import {
|
|
22
23
|
AuthBrokerClient,
|
|
@@ -226,19 +227,46 @@ async function runLogin(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
|
226
227
|
await runLocalLogin(providerArg as OAuthProvider);
|
|
227
228
|
}
|
|
228
229
|
|
|
230
|
+
function promptForLogin(rl: readline.Interface, question: string): Promise<string> {
|
|
231
|
+
const { promise, resolve } = Promise.withResolvers<string>();
|
|
232
|
+
rl.question(question, answer => resolve(answer));
|
|
233
|
+
return promise;
|
|
234
|
+
}
|
|
235
|
+
|
|
229
236
|
async function runLocalLogin(provider: OAuthProvider): Promise<void> {
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
237
|
+
// Drive AuthStorage.login() in-process against the local SQLite store the
|
|
238
|
+
// broker uses. Previously this spawned a child process resolved via
|
|
239
|
+
// `import.meta.resolve("@gajae-code/ai/cli")`, which requires an on-disk
|
|
240
|
+
// `node_modules` package resolution — present in a source/dev checkout but
|
|
241
|
+
// absent inside a compiled `bun build --compile` binary's `$bunfs`, so the
|
|
242
|
+
// standalone binary failed with a module-resolution error (issue #5064).
|
|
243
|
+
// `AuthStorage` is already a normal, statically-traceable import from
|
|
244
|
+
// `@gajae-code/ai/core` (see the top of this file), so it bundles cleanly
|
|
245
|
+
// into the compiled binary the same way every other `@gajae-code/ai/core`
|
|
246
|
+
// export used elsewhere in this file already does.
|
|
247
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
248
|
+
const store = await SqliteAuthCredentialStore.open(getAgentDbPath());
|
|
249
|
+
const storage = new AuthStorage(store);
|
|
250
|
+
await storage.reload();
|
|
251
|
+
try {
|
|
252
|
+
await storage.login(provider, {
|
|
253
|
+
onAuth(info) {
|
|
254
|
+
const { url, instructions } = info;
|
|
255
|
+
process.stdout.write(`\nOpen this URL in your browser:\n${url}\n`);
|
|
256
|
+
if (instructions) process.stdout.write(`${instructions}\n`);
|
|
257
|
+
process.stdout.write("\n");
|
|
258
|
+
},
|
|
259
|
+
onProgress(message) {
|
|
260
|
+
process.stdout.write(`${message}\n`);
|
|
261
|
+
},
|
|
262
|
+
onPrompt(p) {
|
|
263
|
+
return promptForLogin(rl, `${p.message}${p.placeholder ? ` (${p.placeholder})` : ""}: `);
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
process.stdout.write(`\nCredentials saved to ${getAgentDbPath()}\n`);
|
|
267
|
+
} finally {
|
|
268
|
+
store.close();
|
|
269
|
+
rl.close();
|
|
242
270
|
}
|
|
243
271
|
}
|
|
244
272
|
|
|
@@ -8,23 +8,28 @@
|
|
|
8
8
|
* `GJC_AUTH_BROKER_URL` / `auth.broker.url` precedence used elsewhere).
|
|
9
9
|
*
|
|
10
10
|
* Sub-verbs:
|
|
11
|
-
* - `serve [--bind=…]` — boots
|
|
11
|
+
* - `serve --provider=<id> [--bind=…]` — boots a provider-scoped gateway against the configured broker.
|
|
12
12
|
* - `token` / `token --regenerate` — manages the gateway bearer token file.
|
|
13
|
-
* - `status` — prints
|
|
13
|
+
* - `status` — prints scoped gateway readiness without token material.
|
|
14
14
|
*/
|
|
15
15
|
import * as crypto from "node:crypto";
|
|
16
16
|
import * as path from "node:path";
|
|
17
17
|
import { cleanReason } from "@gajae-code/ai/auth-broker/redact";
|
|
18
|
-
import { startAuthGateway } from "@gajae-code/ai/auth-gateway/server";
|
|
19
18
|
import {
|
|
20
|
-
|
|
19
|
+
createAuthGatewayModelCatalog,
|
|
20
|
+
isAuthGatewayModelBrokerConsumable,
|
|
21
|
+
isSafeProviderScope,
|
|
22
|
+
startAuthGateway,
|
|
23
|
+
} from "@gajae-code/ai/auth-gateway/server";
|
|
24
|
+
import {
|
|
21
25
|
AuthBrokerClient,
|
|
26
|
+
type AuthCredentialSnapshot,
|
|
22
27
|
AuthStorage,
|
|
28
|
+
type CredentialHealthResult,
|
|
23
29
|
DEFAULT_AUTH_GATEWAY_BIND,
|
|
30
|
+
extractStructuredApiKeyToken,
|
|
24
31
|
type GeneratedProvider,
|
|
25
32
|
getBundledModels,
|
|
26
|
-
getBundledProviders,
|
|
27
|
-
type Model,
|
|
28
33
|
RemoteAuthCredentialStore,
|
|
29
34
|
type SnapshotResponse,
|
|
30
35
|
} from "@gajae-code/ai/core";
|
|
@@ -44,6 +49,7 @@ export interface AuthGatewayCommandArgs {
|
|
|
44
49
|
flags: {
|
|
45
50
|
json?: boolean;
|
|
46
51
|
bind?: string;
|
|
52
|
+
provider?: string;
|
|
47
53
|
regenerate?: boolean;
|
|
48
54
|
/**
|
|
49
55
|
* Disable bearer-token auth on inbound requests. Useful when the gateway
|
|
@@ -77,12 +83,34 @@ function safeDiagnostic(value: unknown, fallback: string): string {
|
|
|
77
83
|
return cleanReason(value) ?? fallback;
|
|
78
84
|
}
|
|
79
85
|
|
|
86
|
+
export function resolveAuthGatewayReadiness(input: {
|
|
87
|
+
noAuth: boolean;
|
|
88
|
+
tokenPresent: boolean;
|
|
89
|
+
credentialCount: number;
|
|
90
|
+
modelCount: number;
|
|
91
|
+
}): { ready: boolean; reason: "token_missing" | "provider_credential_missing" | "provider_catalog_empty" | null } {
|
|
92
|
+
const authReady = input.noAuth || input.tokenPresent;
|
|
93
|
+
const ready = authReady && input.credentialCount > 0 && input.modelCount > 0;
|
|
94
|
+
const reason = !authReady
|
|
95
|
+
? "token_missing"
|
|
96
|
+
: input.credentialCount === 0
|
|
97
|
+
? "provider_credential_missing"
|
|
98
|
+
: input.modelCount === 0
|
|
99
|
+
? "provider_catalog_empty"
|
|
100
|
+
: null;
|
|
101
|
+
return { ready, reason };
|
|
102
|
+
}
|
|
103
|
+
|
|
80
104
|
function writeCommandFailure(action: AuthGatewayAction, flags: AuthGatewayCommandArgs["flags"], error: unknown): void {
|
|
81
105
|
const stable = stableErrorForAction(action);
|
|
106
|
+
const scope = normalizeProviderScope(flags.provider);
|
|
107
|
+
const scopeLabel = flags.provider === undefined ? "(unscoped)" : (scope ?? "(invalid)");
|
|
82
108
|
if (flags.json) {
|
|
83
|
-
process.stdout.write(`${JSON.stringify({ ok: false, error: stable })}\n`);
|
|
109
|
+
process.stdout.write(`${JSON.stringify({ ok: false, error: stable, scope })}\n`);
|
|
84
110
|
} else {
|
|
85
|
-
process.stderr.write(
|
|
111
|
+
process.stderr.write(`scope: ${scopeLabel}\n`);
|
|
112
|
+
const message = action === "check" ? stable.message : safeDiagnostic(error, stable.message);
|
|
113
|
+
process.stderr.write(`${chalk.red("FAILED")} ${message}\n`);
|
|
86
114
|
}
|
|
87
115
|
process.exitCode = 1;
|
|
88
116
|
}
|
|
@@ -130,13 +158,85 @@ function createBrokerClient(brokerConfig: AuthBrokerClientConfig): AuthBrokerCli
|
|
|
130
158
|
return new AuthBrokerClient({ url: brokerConfig.url, token: brokerConfig.token });
|
|
131
159
|
}
|
|
132
160
|
|
|
161
|
+
export function normalizeProviderScope(provider: string | undefined): string | undefined {
|
|
162
|
+
return provider && isSafeProviderScope(provider) ? provider : undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function filterCredentialCheckResults(
|
|
166
|
+
results: readonly CredentialHealthResult[],
|
|
167
|
+
provider: string | undefined,
|
|
168
|
+
): CredentialHealthResult[] {
|
|
169
|
+
return provider ? results.filter(row => row.provider === provider) : [...results];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function sanitizeCredentialCheckResult(row: CredentialHealthResult): Record<string, unknown> {
|
|
173
|
+
return {
|
|
174
|
+
id: row.id,
|
|
175
|
+
provider: row.provider,
|
|
176
|
+
type: row.type,
|
|
177
|
+
ok: row.ok,
|
|
178
|
+
...(row.remoteRefresh ? { remoteRefresh: true } : {}),
|
|
179
|
+
...(row.reason
|
|
180
|
+
? { reason: row.ok === false ? "Credential check failed." : "Credential status unavailable." }
|
|
181
|
+
: {}),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function requireProviderScope(provider: string | undefined, action: "serve"): string {
|
|
186
|
+
const normalized = normalizeProviderScope(provider);
|
|
187
|
+
if (!normalized) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`gjc auth-gateway ${action} requires --provider=<id>; an unscoped gateway is disabled to prevent model-id ambiguity.`,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return normalized;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function redactBrokerUrl(rawUrl: string): string {
|
|
196
|
+
try {
|
|
197
|
+
const url = new URL(rawUrl);
|
|
198
|
+
url.username = "";
|
|
199
|
+
url.password = "";
|
|
200
|
+
url.search = "";
|
|
201
|
+
url.hash = "";
|
|
202
|
+
return url.origin === "null" ? "<configured broker>" : url.origin;
|
|
203
|
+
} catch {
|
|
204
|
+
return "<configured broker>";
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
133
208
|
async function fetchBrokerSnapshot(client: AuthBrokerClient): Promise<SnapshotResponse> {
|
|
134
209
|
const result = await client.fetchSnapshot();
|
|
135
210
|
if (result.status !== 200) throw new Error("Auth broker returned no initial snapshot");
|
|
136
211
|
return result.snapshot;
|
|
137
212
|
}
|
|
138
213
|
|
|
214
|
+
export function hasEnabledProviderCredential(
|
|
215
|
+
snapshot: Pick<AuthCredentialSnapshot, "credentials">,
|
|
216
|
+
provider: string,
|
|
217
|
+
): boolean {
|
|
218
|
+
return snapshot.credentials.some(entry => entry.provider === provider);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function matchesProviderCredential(
|
|
222
|
+
entry: AuthCredentialSnapshot["credentials"][number],
|
|
223
|
+
apiKey: string,
|
|
224
|
+
): boolean {
|
|
225
|
+
if (entry.credential.type === "api_key") return entry.credential.key === apiKey;
|
|
226
|
+
return entry.credential.access === apiKey || extractStructuredApiKeyToken(apiKey) === entry.credential.access;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function assertEnabledProviderCredential(
|
|
230
|
+
snapshot: Pick<AuthCredentialSnapshot, "credentials">,
|
|
231
|
+
provider: string,
|
|
232
|
+
): void {
|
|
233
|
+
if (!hasEnabledProviderCredential(snapshot, provider)) {
|
|
234
|
+
throw new Error(`Auth gateway scope ${provider} has no enabled broker credential`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
139
238
|
async function runServe(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
239
|
+
const provider = requireProviderScope(flags.provider, "serve");
|
|
140
240
|
const brokerConfig = (await resolveStartupAuthConfig()).broker;
|
|
141
241
|
if (!brokerConfig) {
|
|
142
242
|
throw new Error(
|
|
@@ -144,89 +244,95 @@ async function runServe(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
|
144
244
|
);
|
|
145
245
|
}
|
|
146
246
|
const bind = flags.bind ?? DEFAULT_AUTH_GATEWAY_BIND;
|
|
147
|
-
const
|
|
247
|
+
const models = getBundledModels(provider as GeneratedProvider);
|
|
248
|
+
if (!models.some(isAuthGatewayModelBrokerConsumable)) {
|
|
249
|
+
throw new Error(`Auth gateway scope ${provider} has no broker-consumable models`);
|
|
250
|
+
}
|
|
148
251
|
|
|
149
252
|
// Build a broker-backed AuthStorage — same pattern as discoverAuthStorage()
|
|
150
253
|
// in sdk/session.ts. The gateway never touches local SQLite.
|
|
151
254
|
const client = createBrokerClient(brokerConfig);
|
|
152
255
|
const initialSnapshot = await fetchBrokerSnapshot(client);
|
|
256
|
+
assertEnabledProviderCredential(initialSnapshot, provider);
|
|
153
257
|
const store = new RemoteAuthCredentialStore({ client, initialSnapshot });
|
|
154
258
|
// Refresh + usage both flow through the store's broker hooks automatically —
|
|
155
259
|
// `RemoteAuthCredentialStore.refreshOAuthCredential` and `.fetchUsageReports`.
|
|
156
260
|
// AuthStorage discovers them when no explicit option overrides them, so the
|
|
157
261
|
// gateway only needs to construct the store and pass it in.
|
|
158
262
|
const storage = new AuthStorage(store, {
|
|
159
|
-
sourceLabel: `broker ${brokerConfig.url}`,
|
|
263
|
+
sourceLabel: `broker ${redactBrokerUrl(brokerConfig.url)}`,
|
|
160
264
|
});
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
// to providers we hold credentials for. Format handlers ask `resolveModel`
|
|
165
|
-
// to translate a client-requested `model` field into a pi-ai `Model<Api>`
|
|
166
|
-
// before dispatch; `listModels` powers `/v1/models`.
|
|
167
|
-
const snapshot = storage.exportSnapshot();
|
|
168
|
-
const providersWithCreds = new Set<string>();
|
|
169
|
-
for (const entry of snapshot.credentials) providersWithCreds.add(entry.provider);
|
|
170
|
-
const modelById = new Map<string, Model<Api>>();
|
|
171
|
-
for (const provider of getBundledProviders()) {
|
|
172
|
-
if (!providersWithCreds.has(provider)) continue;
|
|
173
|
-
for (const model of getBundledModels(provider as GeneratedProvider)) {
|
|
174
|
-
// First-write-wins so a canonical model id collisions across providers
|
|
175
|
-
// stick to the provider listed first by getBundledProviders.
|
|
176
|
-
if (!modelById.has(model.id)) modelById.set(model.id, model);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
265
|
+
try {
|
|
266
|
+
await storage.reload();
|
|
267
|
+
assertEnabledProviderCredential(storage.exportSnapshot(), provider);
|
|
179
268
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
bearerTokens: gatewayToken ? [gatewayToken] : [],
|
|
184
|
-
version: VERSION,
|
|
185
|
-
resolveModel: (id: string) => modelById.get(id),
|
|
186
|
-
listModels: () => modelById.values(),
|
|
187
|
-
});
|
|
188
|
-
process.stdout.write(`auth-gateway listening on ${handle.url}\n`);
|
|
189
|
-
if (gatewayToken) {
|
|
190
|
-
process.stdout.write(`bearer token: ${getTokenFilePath()} (chmod 0600)\n`);
|
|
191
|
-
} else {
|
|
192
|
-
process.stdout.write(`auth: disabled (--no-auth) — any client can call this gateway\n`);
|
|
193
|
-
}
|
|
194
|
-
process.stdout.write(`upstream broker: ${brokerConfig.url}\n`);
|
|
195
|
-
|
|
196
|
-
const stopped = Promise.withResolvers<void>();
|
|
197
|
-
let shutdownStarted = false;
|
|
198
|
-
const stop = async (signal: NodeJS.Signals): Promise<void> => {
|
|
199
|
-
if (shutdownStarted) return;
|
|
200
|
-
shutdownStarted = true;
|
|
201
|
-
process.stdout.write(`\nReceived ${signal}, shutting down...\n`);
|
|
202
|
-
let closeError: unknown;
|
|
203
|
-
try {
|
|
204
|
-
await handle.close();
|
|
205
|
-
} catch (error) {
|
|
206
|
-
closeError = error;
|
|
207
|
-
} finally {
|
|
208
|
-
storage.close();
|
|
269
|
+
const catalog = createAuthGatewayModelCatalog(provider, models);
|
|
270
|
+
if (catalog.models.length === 0) {
|
|
271
|
+
throw new Error(`Auth gateway scope ${provider} has no source-backed models`);
|
|
209
272
|
}
|
|
210
|
-
|
|
211
|
-
|
|
273
|
+
const modelById = new Map(catalog.models.map(model => [model.id, model] as const));
|
|
274
|
+
const gatewayToken = flags.noAuth ? null : await ensureToken();
|
|
275
|
+
const handle = startAuthGateway({
|
|
276
|
+
storage,
|
|
277
|
+
hasProviderCredential: () => store.snapshot.credentials.some(entry => entry.provider === provider),
|
|
278
|
+
reloadProviderCredentials: async signal => {
|
|
279
|
+
await store.refreshSnapshot(signal);
|
|
280
|
+
},
|
|
281
|
+
validateProviderCredential: (candidateProvider, apiKey) =>
|
|
282
|
+
store.snapshot.credentials.some(
|
|
283
|
+
entry => entry.provider === candidateProvider && matchesProviderCredential(entry, apiKey),
|
|
284
|
+
),
|
|
285
|
+
bind,
|
|
286
|
+
providerScope: { provider },
|
|
287
|
+
bearerTokens: gatewayToken ? [gatewayToken] : [],
|
|
288
|
+
version: VERSION,
|
|
289
|
+
resolveModel: (id: string) => modelById.get(id),
|
|
290
|
+
listModels: () => catalog.models,
|
|
291
|
+
});
|
|
292
|
+
process.stdout.write(`auth-gateway listening on ${handle.url}\n`);
|
|
293
|
+
process.stdout.write(`scope: ${provider}\n`);
|
|
294
|
+
if (gatewayToken) {
|
|
295
|
+
process.stdout.write(`bearer token: ${getTokenFilePath()} (chmod 0600)\n`);
|
|
212
296
|
} else {
|
|
213
|
-
|
|
297
|
+
process.stdout.write(`auth: disabled (--no-auth) — non-browser local clients can call this gateway\n`);
|
|
214
298
|
}
|
|
215
|
-
|
|
216
|
-
const onSigint = (): void => {
|
|
217
|
-
void stop("SIGINT");
|
|
218
|
-
};
|
|
219
|
-
const onSigterm = (): void => {
|
|
220
|
-
void stop("SIGTERM");
|
|
221
|
-
};
|
|
222
|
-
process.once("SIGINT", onSigint);
|
|
223
|
-
process.once("SIGTERM", onSigterm);
|
|
299
|
+
process.stdout.write(`upstream broker: ${redactBrokerUrl(brokerConfig.url)}\n`);
|
|
224
300
|
|
|
225
|
-
|
|
226
|
-
|
|
301
|
+
const stopped = Promise.withResolvers<void>();
|
|
302
|
+
let shutdownStarted = false;
|
|
303
|
+
const stop = async (signal: NodeJS.Signals): Promise<void> => {
|
|
304
|
+
if (shutdownStarted) return;
|
|
305
|
+
shutdownStarted = true;
|
|
306
|
+
process.stdout.write(`\nReceived ${signal}, shutting down...\n`);
|
|
307
|
+
let closeError: unknown;
|
|
308
|
+
try {
|
|
309
|
+
await handle.close();
|
|
310
|
+
} catch (error) {
|
|
311
|
+
closeError = error;
|
|
312
|
+
}
|
|
313
|
+
if (closeError) {
|
|
314
|
+
stopped.reject(closeError);
|
|
315
|
+
} else {
|
|
316
|
+
stopped.resolve();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
const onSigint = (): void => {
|
|
320
|
+
void stop("SIGINT");
|
|
321
|
+
};
|
|
322
|
+
const onSigterm = (): void => {
|
|
323
|
+
void stop("SIGTERM");
|
|
324
|
+
};
|
|
325
|
+
process.once("SIGINT", onSigint);
|
|
326
|
+
process.once("SIGTERM", onSigterm);
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
await stopped.promise;
|
|
330
|
+
} finally {
|
|
331
|
+
process.off("SIGINT", onSigint);
|
|
332
|
+
process.off("SIGTERM", onSigterm);
|
|
333
|
+
}
|
|
227
334
|
} finally {
|
|
228
|
-
|
|
229
|
-
process.off("SIGTERM", onSigterm);
|
|
335
|
+
storage.close();
|
|
230
336
|
}
|
|
231
337
|
}
|
|
232
338
|
|
|
@@ -253,20 +359,24 @@ async function runStatus(flags: AuthGatewayCommandArgs["flags"]): Promise<void>
|
|
|
253
359
|
const token = await readToken();
|
|
254
360
|
const brokerConfig = (await resolveStartupAuthConfig()).broker;
|
|
255
361
|
const tokenFile = getTokenFilePath();
|
|
362
|
+
const provider = normalizeProviderScope(flags.provider);
|
|
256
363
|
if (!brokerConfig) {
|
|
257
364
|
const status = {
|
|
258
365
|
ready: false,
|
|
259
366
|
reason: "broker_not_configured",
|
|
260
367
|
error: { code: "broker_not_configured", message: "Auth broker is not configured." },
|
|
368
|
+
scope: provider,
|
|
261
369
|
tokenFile,
|
|
262
370
|
tokenPresent: token !== null,
|
|
263
371
|
broker: null,
|
|
264
372
|
brokerConfigured: false,
|
|
265
373
|
brokerAuthenticated: false,
|
|
374
|
+
credentialCount: null,
|
|
266
375
|
};
|
|
267
376
|
if (flags.json) {
|
|
268
377
|
process.stdout.write(`${JSON.stringify(status)}\n`);
|
|
269
378
|
} else {
|
|
379
|
+
process.stdout.write(`scope: ${provider ?? "(required: --provider=<id>)"}\n`);
|
|
270
380
|
process.stdout.write(`${chalk.yellow("No broker configured.")} Set GJC_AUTH_BROKER_URL.\n`);
|
|
271
381
|
process.stdout.write(
|
|
272
382
|
`token: ${status.tokenPresent ? chalk.green("present") : chalk.red("missing")} at ${status.tokenFile}\n`,
|
|
@@ -275,54 +385,98 @@ async function runStatus(flags: AuthGatewayCommandArgs["flags"]): Promise<void>
|
|
|
275
385
|
process.exitCode = 1;
|
|
276
386
|
return;
|
|
277
387
|
}
|
|
388
|
+
if (!provider) {
|
|
389
|
+
const status = {
|
|
390
|
+
ready: false,
|
|
391
|
+
reason: "provider_scope_required",
|
|
392
|
+
error: {
|
|
393
|
+
code: "provider_scope_required",
|
|
394
|
+
message: "A provider scope is required to report gateway readiness.",
|
|
395
|
+
},
|
|
396
|
+
scope: null,
|
|
397
|
+
tokenFile,
|
|
398
|
+
tokenPresent: token !== null,
|
|
399
|
+
broker: redactBrokerUrl(brokerConfig.url),
|
|
400
|
+
brokerConfigured: true,
|
|
401
|
+
brokerAuthenticated: false,
|
|
402
|
+
credentialCount: null,
|
|
403
|
+
};
|
|
404
|
+
if (flags.json) {
|
|
405
|
+
process.stdout.write(`${JSON.stringify(status)}\n`);
|
|
406
|
+
} else {
|
|
407
|
+
process.stdout.write(`scope: (required: --provider=<id>)\n`);
|
|
408
|
+
process.stdout.write(`${chalk.yellow("not ready")} provider scope is required\n`);
|
|
409
|
+
process.stdout.write(
|
|
410
|
+
`token: ${status.tokenPresent ? chalk.green("present") : chalk.red("missing")} at ${status.tokenFile}\n`,
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
process.exitCode = 1;
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
278
416
|
|
|
279
417
|
try {
|
|
280
418
|
const snapshot = await fetchBrokerSnapshot(createBrokerClient(brokerConfig));
|
|
281
419
|
const tokenPresent = token !== null;
|
|
420
|
+
const noAuth = flags.noAuth === true;
|
|
421
|
+
const credentialCount = snapshot.credentials.filter(entry => entry.provider === provider).length;
|
|
422
|
+
const catalog = createAuthGatewayModelCatalog(provider, getBundledModels(provider as GeneratedProvider));
|
|
423
|
+
const modelCount = catalog.models.length;
|
|
424
|
+
const { ready, reason } = resolveAuthGatewayReadiness({ noAuth, tokenPresent, credentialCount, modelCount });
|
|
282
425
|
const status = {
|
|
283
|
-
ready
|
|
284
|
-
reason
|
|
426
|
+
ready,
|
|
427
|
+
reason,
|
|
285
428
|
tokenFile,
|
|
286
429
|
tokenPresent,
|
|
287
|
-
broker: brokerConfig.url,
|
|
430
|
+
broker: redactBrokerUrl(brokerConfig.url),
|
|
288
431
|
brokerConfigured: true,
|
|
289
432
|
brokerAuthenticated: true,
|
|
290
|
-
|
|
433
|
+
scope: provider,
|
|
434
|
+
credentialCount,
|
|
435
|
+
modelCount,
|
|
291
436
|
};
|
|
292
437
|
if (flags.json) {
|
|
293
438
|
process.stdout.write(`${JSON.stringify(status)}\n`);
|
|
294
439
|
} else {
|
|
295
|
-
const brokerLine = `upstream broker: ${brokerConfig.url} (${
|
|
296
|
-
|
|
440
|
+
const brokerLine = `upstream broker: ${redactBrokerUrl(brokerConfig.url)} (${credentialCount} scoped credential${
|
|
441
|
+
credentialCount === 1 ? "" : "s"
|
|
297
442
|
})`;
|
|
298
|
-
process.stdout.write(
|
|
443
|
+
process.stdout.write(`scope: ${provider}\n`);
|
|
444
|
+
process.stdout.write(`${ready ? chalk.green("ready") : chalk.yellow("not ready")} ${brokerLine}\n`);
|
|
299
445
|
process.stdout.write(
|
|
300
446
|
`token: ${tokenPresent ? chalk.green("present") : chalk.red("missing")} at ${status.tokenFile}\n`,
|
|
301
447
|
);
|
|
302
|
-
if (!tokenPresent) {
|
|
448
|
+
if (!tokenPresent && !noAuth) {
|
|
303
449
|
process.stdout.write(
|
|
304
450
|
"Run `gjc auth-gateway token` or `gjc auth-gateway serve` to create a bearer token.\n",
|
|
305
451
|
);
|
|
306
452
|
}
|
|
453
|
+
if (credentialCount === 0) {
|
|
454
|
+
process.stdout.write(`No enabled broker credential is available for scope ${provider}.\n`);
|
|
455
|
+
}
|
|
456
|
+
if (modelCount === 0) {
|
|
457
|
+
process.stdout.write(`No source-backed models are available for scope ${provider}.\n`);
|
|
458
|
+
}
|
|
307
459
|
}
|
|
308
|
-
if (!
|
|
460
|
+
if (!ready) process.exitCode = 1;
|
|
309
461
|
} catch (error) {
|
|
310
462
|
const status = {
|
|
311
463
|
ready: false,
|
|
312
464
|
reason: "broker_unavailable",
|
|
313
465
|
tokenFile,
|
|
314
466
|
tokenPresent: token !== null,
|
|
315
|
-
broker: brokerConfig.url,
|
|
467
|
+
broker: redactBrokerUrl(brokerConfig.url),
|
|
316
468
|
brokerConfigured: true,
|
|
317
469
|
brokerAuthenticated: false,
|
|
470
|
+
scope: provider,
|
|
318
471
|
error: { code: "broker_unavailable", message: "Auth broker is unavailable." },
|
|
319
472
|
};
|
|
320
473
|
if (flags.json) {
|
|
321
474
|
process.stdout.write(`${JSON.stringify(status)}\n`);
|
|
322
475
|
} else {
|
|
323
476
|
process.stdout.write(
|
|
324
|
-
`${chalk.red("FAILED")} upstream broker: ${brokerConfig.url}: ${safeDiagnostic(error, "Auth broker is unavailable.")}\n`,
|
|
477
|
+
`${chalk.red("FAILED")} upstream broker: ${redactBrokerUrl(brokerConfig.url)}: ${safeDiagnostic(error, "Auth broker is unavailable.")}\n`,
|
|
325
478
|
);
|
|
479
|
+
process.stdout.write(`scope: ${provider}\n`);
|
|
326
480
|
process.stdout.write(
|
|
327
481
|
`token: ${status.tokenPresent ? chalk.green("present") : chalk.red("missing")} at ${status.tokenFile}\n`,
|
|
328
482
|
);
|
|
@@ -333,6 +487,9 @@ async function runStatus(flags: AuthGatewayCommandArgs["flags"]): Promise<void>
|
|
|
333
487
|
|
|
334
488
|
export async function runAuthGatewayCommand(cmd: AuthGatewayCommandArgs): Promise<void> {
|
|
335
489
|
try {
|
|
490
|
+
if (cmd.flags.provider !== undefined && !normalizeProviderScope(cmd.flags.provider)) {
|
|
491
|
+
throw new Error("Invalid provider scope.");
|
|
492
|
+
}
|
|
336
493
|
switch (cmd.action) {
|
|
337
494
|
case "serve":
|
|
338
495
|
await runServe(cmd.flags);
|
|
@@ -368,6 +525,7 @@ export async function runAuthGatewayCommand(cmd: AuthGatewayCommandArgs): Promis
|
|
|
368
525
|
* dedicated diagnostic is the only way to see which credentials failed.
|
|
369
526
|
*/
|
|
370
527
|
async function runCheck(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
528
|
+
const provider = normalizeProviderScope(flags.provider);
|
|
371
529
|
const brokerConfig = (await resolveStartupAuthConfig()).broker;
|
|
372
530
|
if (!brokerConfig) {
|
|
373
531
|
throw new Error(
|
|
@@ -378,17 +536,32 @@ async function runCheck(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
|
378
536
|
const client = createBrokerClient(brokerConfig);
|
|
379
537
|
const initialSnapshot = await fetchBrokerSnapshot(client);
|
|
380
538
|
const store = new RemoteAuthCredentialStore({ client, initialSnapshot });
|
|
381
|
-
const storage = new AuthStorage(store, { sourceLabel: `broker ${brokerConfig.url}` });
|
|
539
|
+
const storage = new AuthStorage(store, { sourceLabel: `broker ${redactBrokerUrl(brokerConfig.url)}` });
|
|
382
540
|
try {
|
|
383
541
|
await storage.reload();
|
|
384
|
-
const results =
|
|
542
|
+
const results = filterCredentialCheckResults(
|
|
543
|
+
await storage.checkCredentials(provider ? { provider } : undefined),
|
|
544
|
+
provider,
|
|
545
|
+
);
|
|
546
|
+
const scopedCredentialCount = provider
|
|
547
|
+
? store.snapshot.credentials.filter(entry => entry.provider === provider).length
|
|
548
|
+
: store.snapshot.credentials.length;
|
|
549
|
+
const failed = results.filter(row => row.ok === false).length;
|
|
385
550
|
|
|
386
551
|
if (flags.json) {
|
|
387
|
-
const credentials = results.map(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
552
|
+
const credentials = results.map(sanitizeCredentialCheckResult);
|
|
553
|
+
process.stdout.write(
|
|
554
|
+
`${JSON.stringify(
|
|
555
|
+
{
|
|
556
|
+
broker: redactBrokerUrl(brokerConfig.url),
|
|
557
|
+
scope: provider,
|
|
558
|
+
credentialCount: scopedCredentialCount,
|
|
559
|
+
credentials,
|
|
560
|
+
},
|
|
561
|
+
null,
|
|
562
|
+
2,
|
|
563
|
+
)}\n`,
|
|
564
|
+
);
|
|
392
565
|
} else {
|
|
393
566
|
const grouped = new Map<string, typeof results>();
|
|
394
567
|
for (const row of results) {
|
|
@@ -397,7 +570,11 @@ async function runCheck(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
|
397
570
|
grouped.set(row.provider, list);
|
|
398
571
|
}
|
|
399
572
|
const providers = [...grouped.keys()].sort();
|
|
400
|
-
process.stdout.write(`broker: ${brokerConfig.url}\n`);
|
|
573
|
+
process.stdout.write(`broker: ${redactBrokerUrl(brokerConfig.url)}\n`);
|
|
574
|
+
process.stdout.write(`scope: ${provider ?? "(all providers; diagnostic only)"}\n`);
|
|
575
|
+
if (provider && scopedCredentialCount === 0) {
|
|
576
|
+
process.stdout.write(`No enabled broker credential is available for scope ${provider}.\n`);
|
|
577
|
+
}
|
|
401
578
|
for (const provider of providers) {
|
|
402
579
|
const rows = grouped.get(provider) ?? [];
|
|
403
580
|
process.stdout.write(`\n${chalk.bold(provider)} (${rows.length})\n`);
|
|
@@ -408,25 +585,24 @@ async function runCheck(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
|
408
585
|
: row.ok === false
|
|
409
586
|
? chalk.red("FAIL ")
|
|
410
587
|
: chalk.yellow("unknown ");
|
|
411
|
-
const identity =
|
|
412
|
-
row.email ?? row.accountId ?? (row.type === "api_key" ? "(api key)" : "(no identity on credential)");
|
|
588
|
+
const identity = row.type === "api_key" ? "(api key)" : "(identity hidden)";
|
|
413
589
|
const remote = row.remoteRefresh ? chalk.dim(" [remote-refresh]") : "";
|
|
414
590
|
const reason = row.reason
|
|
415
|
-
? chalk.dim(` — ${
|
|
591
|
+
? chalk.dim(` — ${row.ok === false ? "Credential check failed." : "Credential status unavailable."}`)
|
|
416
592
|
: "";
|
|
417
593
|
process.stdout.write(
|
|
418
594
|
` ${status} id=${row.id.toString().padStart(3)} ${row.type.padEnd(7)} ${identity}${remote}${reason}\n`,
|
|
419
595
|
);
|
|
420
596
|
}
|
|
421
597
|
}
|
|
422
|
-
const failed = results.filter(row => row.ok === false).length;
|
|
423
598
|
const unverifiable = results.filter(row => row.ok === null).length;
|
|
424
599
|
const passing = results.filter(row => row.ok === true).length;
|
|
425
600
|
process.stdout.write(
|
|
426
601
|
`\n${chalk.green(`${passing} ok`)}, ${chalk.red(`${failed} failed`)}, ${chalk.yellow(`${unverifiable} unverifiable`)}, ${results.length} total\n`,
|
|
427
602
|
);
|
|
428
|
-
if (failed > 0) process.exitCode = 1;
|
|
429
603
|
}
|
|
604
|
+
if (failed > 0) process.exitCode = 1;
|
|
605
|
+
if (provider && scopedCredentialCount === 0) process.exitCode = 1;
|
|
430
606
|
} finally {
|
|
431
607
|
storage.close();
|
|
432
608
|
}
|
package/src/cli/config-cli.ts
CHANGED
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
validateAutoroutingProvenance,
|
|
17
17
|
validateAutoroutingSetup,
|
|
18
18
|
} from "../config/autorouting-contract";
|
|
19
|
+
import { loadEffectiveModelProfiles } from "../config/model-preset-registry";
|
|
19
20
|
import { resolveModelProfileName } from "../config/model-profile-contract";
|
|
20
|
-
import { mergeModelProfiles } from "../config/model-profiles";
|
|
21
21
|
import { ModelsConfigFile } from "../config/model-registry";
|
|
22
22
|
import {
|
|
23
23
|
getDefault,
|
|
@@ -548,7 +548,7 @@ function handlePath(): void {
|
|
|
548
548
|
*/
|
|
549
549
|
export function collectConfigAdvisories(): string[] {
|
|
550
550
|
const profileName = settings.get("modelProfile.default");
|
|
551
|
-
const profiles =
|
|
551
|
+
const profiles = loadEffectiveModelProfiles(ModelsConfigFile.load()?.profiles);
|
|
552
552
|
const resolvedProfileName = profileName ? resolveModelProfileName(profileName, profiles) : undefined;
|
|
553
553
|
const delegation = resolveEagerTaskDelegation({
|
|
554
554
|
settings,
|
package/src/cli/fast-help.ts
CHANGED
|
@@ -9,6 +9,7 @@ export function getExtraHelpText(): string {
|
|
|
9
9
|
${APP_NAME} state - Inspect or manage persisted GJC state
|
|
10
10
|
${APP_NAME} auth-broker - Manage the auth-broker (credential vault)
|
|
11
11
|
${APP_NAME} accounts - List, check, pin, and remove stored OAuth accounts
|
|
12
|
+
${APP_NAME} models presets - Inspect, refresh, pin, rollback, or disable the signed model preset registry
|
|
12
13
|
${APP_NAME} auth-gateway - Run an auth-gateway forward proxy
|
|
13
14
|
${APP_NAME} harness - Run harness control-plane commands
|
|
14
15
|
${APP_NAME} coordinator - Manage coordinator/runtime coordination helpers
|
|
@@ -82,6 +83,8 @@ Environment Variables:
|
|
|
82
83
|
GJC_SMOL_MODEL - Override smol/fast model (see --smol)
|
|
83
84
|
GJC_SLOW_MODEL - Override slow/reasoning model (see --slow)
|
|
84
85
|
GJC_PLAN_MODEL - Override planning model (see --plan)
|
|
86
|
+
GJC_MODEL_PRESET_REGISTRY_URL - HTTPS latest.json override for the signed preset registry
|
|
87
|
+
GJC_MODEL_PRESET_REGISTRY_DISABLED - Disable registry fetch/use (1/true/yes/on)
|
|
85
88
|
GJC_NO_PTY - Disable PTY-based interactive bash execution
|
|
86
89
|
--tmux - Launch interactive startup inside a fresh tmux session
|
|
87
90
|
gjc session - List, inspect, create, remove, or attach tagged GJC-managed tmux sessions
|