@gajae-code/coding-agent 0.18.7 → 0.18.8
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 +279 -1
- package/dist/types/async/job-manager.d.ts +1 -1
- package/dist/types/capability/mcp.d.ts +2 -0
- package/dist/types/capability/skill.d.ts +2 -0
- package/dist/types/capability/types.d.ts +2 -0
- package/dist/types/cli/public-command-errors.d.ts +3 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/autorouting-tier-map.d.ts +348 -9
- package/dist/types/config/file-lock.d.ts +1 -0
- package/dist/types/config/model-bindings-applier.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +11 -3
- package/dist/types/config/model-registry.d.ts +4 -9
- package/dist/types/config/skill-settings-defaults.d.ts +2 -0
- package/dist/types/cursor-delete-path.d.ts +1 -0
- package/dist/types/cursor-mcp-name.d.ts +8 -0
- package/dist/types/customization/inventory.d.ts +2 -0
- package/dist/types/debug/report-bundle-parent.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.d.ts +31 -0
- package/dist/types/defaults/gjc-skills.generated.d.ts +5 -6
- package/dist/types/discovery/helpers.d.ts +6 -1
- package/dist/types/export/html/css-color.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/types.d.ts +7 -0
- package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +14 -1
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +2 -0
- package/dist/types/extensibility/plugins/plugin-link-path.d.ts +2 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +3 -1
- package/dist/types/extensibility/skill-management.d.ts +3 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-crystallize.d.ts +74 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +11 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +0 -5
- package/dist/types/gjc-runtime/state-argv.d.ts +1 -1
- package/dist/types/gjc-runtime/state-migrations.d.ts +8 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +95 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +11 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -0
- package/dist/types/internal-urls/skill-path.d.ts +1 -0
- package/dist/types/lsp/workspace-path.d.ts +1 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +1 -0
- package/dist/types/modes/components/extensions/state-manager.d.ts +4 -3
- package/dist/types/modes/controllers/input-controller.d.ts +9 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/utils/interrupt-ownership.d.ts +3 -0
- package/dist/types/modes/utils/keybinding-matchers.d.ts +1 -0
- package/dist/types/modes/utils/macos-option-forwarding.d.ts +17 -0
- package/dist/types/progress/collect-project-progress.d.ts +38 -0
- package/dist/types/progress/progress-contract.d.ts +154 -0
- package/dist/types/progress/progress-snapshot.d.ts +11 -0
- package/dist/types/progress/project-progress.d.ts +141 -0
- package/dist/types/progress/render-progress.d.ts +28 -0
- package/dist/types/runtime-mcp/oauth-public-url.d.ts +1 -0
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +1 -0
- package/dist/types/runtime-mcp/smithery-registry.d.ts +24 -0
- package/dist/types/runtime-mcp/types.d.ts +6 -0
- package/dist/types/sdk/acp/adapter.d.ts +1 -1
- package/dist/types/sdk/broker/broker-exit.d.ts +6 -2
- package/dist/types/sdk/broker/broker.d.ts +18 -1
- package/dist/types/sdk/broker/session-index.d.ts +12 -6
- package/dist/types/sdk/bus/index.d.ts +12 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -1
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +3 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/sdk/session.d.ts +8 -0
- package/dist/types/session/agent-session.d.ts +38 -9
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/internal/managed-gc-retirement-codec.d.ts +32 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +79 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +26 -1
- package/dist/types/session/internal/managed-task-owner-cleanup.d.ts +62 -0
- package/dist/types/session/internal/task-artifact-owner-access.d.ts +2 -0
- package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +9 -1
- package/dist/types/session/session-manager.d.ts +31 -5
- package/dist/types/session/session-retirement.d.ts +31 -7
- package/dist/types/session/session-storage.d.ts +62 -2
- package/dist/types/session/task-artifact-owner-codec.d.ts +2 -0
- package/dist/types/setup/credential-auto-import.d.ts +1 -1
- package/dist/types/setup/credential-import.d.ts +6 -4
- package/dist/types/skill-state/active-state.d.ts +38 -0
- package/dist/types/slash-commands/helpers/progress-report.d.ts +8 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/tools/bash-skill-urls.d.ts +1 -1
- package/dist/types/tools/index.d.ts +3 -0
- package/dist/types/tools/python.d.ts +9 -1
- package/dist/types/tools/recipe/recipe-guard.d.ts +7 -0
- package/dist/types/tools/restricted-cwd.d.ts +1 -0
- package/dist/types/tools/todo-write.d.ts +6 -0
- package/dist/types/utils/tools-checksum.d.ts +7 -0
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +21 -0
- package/scripts/verify-managed-empty-stop.ts +28 -0
- package/src/async/job-manager.ts +228 -122
- package/src/capability/index.ts +17 -0
- package/src/capability/mcp.ts +2 -0
- package/src/capability/skill.ts +2 -0
- package/src/capability/types.ts +2 -0
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/customize-doctor.ts +15 -2
- package/src/cli/public-command-errors.ts +21 -1
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/skills-cli.ts +5 -0
- package/src/commands/deep-interview.ts +47 -8
- package/src/commands/sdk.ts +28 -8
- package/src/config/autorouting-tier-map.ts +117 -7
- package/src/config/file-lock.ts +307 -68
- package/src/config/mcp-schema.json +4 -0
- package/src/config/model-bindings-applier.ts +20 -0
- package/src/config/model-profile-activation.ts +240 -46
- package/src/config/model-registry.ts +47 -153
- package/src/config/skill-settings-defaults.ts +7 -0
- package/src/coordinator-mcp/policy.ts +3 -2
- package/src/cursor-delete-path.ts +10 -0
- package/src/cursor-mcp-name.ts +15 -0
- package/src/cursor.ts +13 -2
- package/src/customization/inventory.ts +3 -0
- package/src/debug/report-bundle-parent.ts +22 -0
- package/src/debug/report-bundle.ts +3 -0
- package/src/debug/system-info.ts +13 -1
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +67 -4
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.ts +80 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +105 -10
- package/src/defaults/gjc/skills/ralplan/SKILL.md +6 -4
- package/src/defaults/gjc-defaults.test.ts +18 -1
- package/src/defaults/gjc-defaults.ts +3 -0
- package/src/defaults/gjc-skills.generated.ts +58 -36
- package/src/discovery/agents.ts +6 -1
- package/src/discovery/builtin.ts +10 -0
- package/src/discovery/helpers.ts +159 -20
- package/src/discovery/mcp-json.ts +6 -0
- package/src/discovery/ssh.ts +1 -1
- package/src/discovery/substitute-plugin-root.ts +3 -1
- package/src/edit/file-read-cache.ts +1 -1
- package/src/eval/py/executor.ts +380 -120
- package/src/export/html/css-color.ts +9 -0
- package/src/export/html/index.ts +5 -4
- package/src/export/html/template.generated.ts +1 -1
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +7 -0
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +73 -8
- package/src/extensibility/plugins/manager.ts +3 -2
- package/src/extensibility/plugins/marketplace/cache.ts +15 -0
- package/src/extensibility/plugins/marketplace/manager.ts +11 -3
- package/src/extensibility/plugins/plugin-link-path.ts +12 -0
- package/src/extensibility/runtime-skill-discovery.ts +20 -2
- package/src/extensibility/skill-management.ts +6 -2
- package/src/extensibility/skills.ts +6 -1
- package/src/gjc-runtime/deep-interview-crystallize.ts +1814 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +20 -2
- package/src/gjc-runtime/deep-interview-runtime.ts +1415 -13
- package/src/gjc-runtime/deep-interview-stage.ts +98 -21
- package/src/gjc-runtime/gc-runtime.ts +206 -9
- package/src/gjc-runtime/launch-worktree.ts +14 -4
- package/src/gjc-runtime/ralplan-runtime.ts +447 -52
- package/src/gjc-runtime/state-argv.ts +2 -0
- package/src/gjc-runtime/state-migrations.ts +91 -29
- package/src/gjc-runtime/state-runtime.ts +3716 -135
- package/src/gjc-runtime/state-writer.ts +83 -8
- package/src/gjc-runtime/ultragoal-runtime.ts +16 -4
- package/src/gjc-runtime/workflow-manifest.generated.json +70 -42
- package/src/gjc-runtime/workflow-manifest.ts +54 -21
- package/src/harness-control-plane/operate.ts +12 -4
- package/src/harness-control-plane/owner.ts +5 -1
- package/src/hashline/parser.ts +48 -9
- package/src/hashline/recovery.ts +13 -4
- package/src/internal-urls/docs-index.generated.ts +18 -17
- package/src/internal-urls/skill-path.ts +19 -0
- package/src/internal-urls/skill-protocol.ts +2 -0
- package/src/lsp/edits.ts +6 -0
- package/src/lsp/workspace-path.ts +51 -0
- package/src/main.ts +195 -31
- package/src/modes/acp/acp-agent.ts +88 -4
- package/src/modes/components/custom-editor.ts +14 -0
- package/src/modes/components/customization/customization-dashboard.ts +12 -0
- package/src/modes/components/extensions/extension-dashboard.ts +2 -2
- package/src/modes/components/extensions/state-manager.ts +15 -5
- package/src/modes/components/model-selector.ts +1 -4
- package/src/modes/components/provider-onboarding-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +4 -0
- package/src/modes/controllers/event-controller.ts +11 -4
- package/src/modes/controllers/input-controller.ts +74 -29
- package/src/modes/controllers/runtime-mcp-command-controller.ts +8 -3
- package/src/modes/controllers/selector-controller.ts +28 -15
- package/src/modes/interactive-mode.ts +4 -0
- package/src/modes/runtime-init.ts +4 -0
- package/src/modes/utils/abort-message.ts +3 -1
- package/src/modes/utils/interrupt-ownership.ts +12 -0
- package/src/modes/utils/keybinding-matchers.ts +4 -0
- package/src/modes/utils/macos-option-forwarding.ts +80 -0
- package/src/progress/collect-project-progress.ts +153 -0
- package/src/progress/progress-contract.ts +172 -0
- package/src/progress/progress-snapshot.ts +140 -0
- package/src/progress/project-progress.ts +446 -0
- package/src/progress/render-progress.ts +209 -0
- package/src/prompts/system/master-mode.md +1 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/runtime-mcp/config-writer.ts +10 -6
- package/src/runtime-mcp/config.ts +1 -0
- package/src/runtime-mcp/oauth-flow.ts +5 -0
- package/src/runtime-mcp/oauth-public-url.ts +8 -0
- package/src/runtime-mcp/plugin-network-boundary.ts +4 -0
- package/src/runtime-mcp/smithery-registry.ts +22 -3
- package/src/runtime-mcp/transports/http.ts +2 -2
- package/src/runtime-mcp/types.ts +6 -0
- package/src/sdk/acp/adapter.ts +93 -8
- package/src/sdk/broker/broker-exit.ts +52 -23
- package/src/sdk/broker/broker.ts +75 -6
- package/src/sdk/broker/ensure.ts +2 -0
- package/src/sdk/broker/lifecycle.ts +711 -66
- package/src/sdk/broker/session-index.ts +191 -81
- package/src/sdk/bus/chat-daemon-cli.ts +38 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +238 -43
- package/src/sdk/bus/telegram-daemon-contract.ts +6 -1
- package/src/sdk/cli/session-cli.ts +17 -3
- package/src/sdk/client/client.ts +28 -8
- package/src/sdk/host/query/handlers.ts +9 -1
- package/src/sdk/host/session-runtime.test.ts +2647 -294
- package/src/sdk/host/session-runtime.ts +426 -109
- package/src/sdk/host/surface-policy.ts +1 -0
- package/src/sdk/index.ts +8 -0
- package/src/sdk/lifecycle-session.ts +3 -1
- package/src/sdk/prompt-deadline-manager.ts +15 -0
- package/src/sdk/protocol/operation-inventory.generated.json +146 -0
- package/src/sdk/protocol/operation-registry.ts +9 -2
- package/src/sdk/router/session-router.ts +75 -12
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +67 -38
- package/src/session/agent-session.ts +623 -224
- package/src/session/artifacts.ts +174 -70
- package/src/session/internal/managed-gc-retirement-codec.ts +319 -0
- package/src/session/internal/managed-session-scope.ts +3457 -462
- package/src/session/internal/managed-session-storage.ts +376 -61
- package/src/session/internal/managed-task-owner-cleanup.ts +473 -0
- package/src/session/internal/task-artifact-owner-access.ts +19 -3
- package/src/session/internal/task-artifact-owner-transcript.ts +547 -1
- package/src/session/session-manager.ts +939 -133
- package/src/session/session-retirement.ts +573 -14
- package/src/session/session-storage.ts +417 -14
- package/src/session/task-artifact-owner-codec.ts +71 -8
- package/src/session/task-artifact-owner-retirement.ts +21 -19
- package/src/setup/credential-auto-import.ts +12 -3
- package/src/setup/credential-import.ts +176 -5
- package/src/setup/paseo/announce.ts +6 -1
- package/src/skill-state/active-state.ts +132 -2
- package/src/slash-commands/builtin-registry.ts +39 -9
- package/src/slash-commands/helpers/progress-report.ts +23 -0
- package/src/stt/setup.ts +3 -5
- package/src/task/commands.ts +3 -1
- package/src/task/executor.ts +4 -0
- package/src/task/index.ts +6 -0
- package/src/tools/ask.ts +205 -6
- package/src/tools/ast-edit.ts +4 -0
- package/src/tools/bash-allowed-prefixes.ts +15 -0
- package/src/tools/bash-skill-urls.ts +56 -3
- package/src/tools/bash.ts +48 -79
- package/src/tools/descriptors.ts +5 -1
- package/src/tools/eval.ts +56 -36
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/index.ts +3 -0
- package/src/tools/python.ts +187 -66
- package/src/tools/recipe/index.ts +9 -0
- package/src/tools/recipe/recipe-guard.ts +19 -0
- package/src/tools/restricted-cwd.ts +10 -0
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +28 -1
- package/src/tools/todo-write.ts +10 -1
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/write.ts +1 -0
- package/src/utils/tools-checksum.ts +34 -0
- package/src/utils/tools-manager.ts +24 -6
- package/src/web/search/providers/codex.ts +3 -2
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type Context,
|
|
14
14
|
codexContextOverrideKey,
|
|
15
15
|
createModelManager,
|
|
16
|
+
createTrustedStrippedModelClone,
|
|
16
17
|
Effort,
|
|
17
18
|
enrichModelThinking,
|
|
18
19
|
getBundledModels,
|
|
@@ -49,6 +50,8 @@ import {
|
|
|
49
50
|
readBoundedModelsJson,
|
|
50
51
|
resolveLoopbackOpenAIBaseUrl,
|
|
51
52
|
} from "@gajae-code/ai/utils/discovery/openai-compatible";
|
|
53
|
+
// Internal-only: registerFinalizedModelClone is not part of the public @gajae-code/ai surface
|
|
54
|
+
import { registerFinalizedModelClone } from "@gajae-code/ai/utils/trusted-model-clone";
|
|
52
55
|
|
|
53
56
|
// Sentinels for local-only OAuth tokens — declared inline to avoid loading provider
|
|
54
57
|
// modules at startup. Must match the provider OAuth modules.
|
|
@@ -1771,9 +1774,6 @@ export class ModelRegistry {
|
|
|
1771
1774
|
{
|
|
1772
1775
|
fresh: boolean;
|
|
1773
1776
|
modelIds: ReadonlySet<string>;
|
|
1774
|
-
profileModelIds?: ReadonlySet<string>;
|
|
1775
|
-
profileFresh?: boolean;
|
|
1776
|
-
profileEndpoint?: string;
|
|
1777
1777
|
authGeneration: string;
|
|
1778
1778
|
endpoint: string;
|
|
1779
1779
|
}
|
|
@@ -2746,20 +2746,7 @@ export class ModelRegistry {
|
|
|
2746
2746
|
}));
|
|
2747
2747
|
}
|
|
2748
2748
|
#stripModelBaseUrlQueries(models: readonly Model<Api>[]): Model<Api>[] {
|
|
2749
|
-
return models.map(model =>
|
|
2750
|
-
if (!model.baseUrl) return model;
|
|
2751
|
-
try {
|
|
2752
|
-
const parsed = new URL(model.baseUrl);
|
|
2753
|
-
parsed.username = "";
|
|
2754
|
-
parsed.password = "";
|
|
2755
|
-
parsed.search = "";
|
|
2756
|
-
parsed.hash = "";
|
|
2757
|
-
return { ...model, baseUrl: parsed.toString().replace(/\/$/, "") };
|
|
2758
|
-
} catch {
|
|
2759
|
-
const { baseUrl: _baseUrl, ...withoutBaseUrl } = model;
|
|
2760
|
-
return withoutBaseUrl as Model<Api>;
|
|
2761
|
-
}
|
|
2762
|
-
});
|
|
2749
|
+
return models.map(model => createTrustedStrippedModelClone(model));
|
|
2763
2750
|
}
|
|
2764
2751
|
#stripUrlUserinfo(url: string | undefined): string | undefined {
|
|
2765
2752
|
if (!url) return url;
|
|
@@ -3288,6 +3275,11 @@ export class ModelRegistry {
|
|
|
3288
3275
|
result.provider,
|
|
3289
3276
|
this.#providerEvidenceApiKeys.get(result.provider),
|
|
3290
3277
|
) &&
|
|
3278
|
+
result.configurationGeneration ===
|
|
3279
|
+
this.authStorage.getProviderConfigurationGeneration(
|
|
3280
|
+
result.provider,
|
|
3281
|
+
this.#authStorageConfigOwner,
|
|
3282
|
+
) &&
|
|
3291
3283
|
result.endpoint ===
|
|
3292
3284
|
this.#normalizeDiscoveryEvidenceEndpoint(
|
|
3293
3285
|
this.#effectiveDiscoveryProviderConfig(providerConfig).baseUrl ?? "",
|
|
@@ -3309,7 +3301,10 @@ export class ModelRegistry {
|
|
|
3309
3301
|
this.#providerEvidenceApiKeys.get(result.provider),
|
|
3310
3302
|
) ||
|
|
3311
3303
|
result.configurationGeneration !==
|
|
3312
|
-
this.authStorage.getProviderConfigurationGeneration(
|
|
3304
|
+
this.authStorage.getProviderConfigurationGeneration(
|
|
3305
|
+
result.provider,
|
|
3306
|
+
this.#authStorageConfigOwner,
|
|
3307
|
+
) ||
|
|
3313
3308
|
result.endpoint !==
|
|
3314
3309
|
this.#normalizeDiscoveryEvidenceEndpoint(
|
|
3315
3310
|
this.#effectiveDiscoveryProviderConfig(providerConfig).baseUrl ?? "",
|
|
@@ -3334,9 +3329,6 @@ export class ModelRegistry {
|
|
|
3334
3329
|
| {
|
|
3335
3330
|
fresh: boolean;
|
|
3336
3331
|
modelIds: ReadonlySet<string>;
|
|
3337
|
-
profileModelIds?: ReadonlySet<string>;
|
|
3338
|
-
profileFresh?: boolean;
|
|
3339
|
-
profileEndpoint?: string;
|
|
3340
3332
|
authGeneration: string;
|
|
3341
3333
|
endpoint: string;
|
|
3342
3334
|
}
|
|
@@ -3481,12 +3473,9 @@ export class ModelRegistry {
|
|
|
3481
3473
|
.map(([provider, evidence]) => [
|
|
3482
3474
|
provider,
|
|
3483
3475
|
evidence.fresh,
|
|
3484
|
-
evidence.profileFresh,
|
|
3485
3476
|
evidence.authGeneration,
|
|
3486
3477
|
evidence.endpoint,
|
|
3487
|
-
evidence.profileEndpoint,
|
|
3488
3478
|
[...evidence.modelIds].sort(),
|
|
3489
|
-
evidence.profileModelIds === undefined ? undefined : [...evidence.profileModelIds].sort(),
|
|
3490
3479
|
]),
|
|
3491
3480
|
configured: [...this.#configuredDiscoveryEvidence.entries()]
|
|
3492
3481
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
@@ -3540,7 +3529,10 @@ export class ModelRegistry {
|
|
|
3540
3529
|
? this.authStorage.has(provider) ||
|
|
3541
3530
|
this.authStorage.hasAuth(provider, undefined, { owner: this.#authStorageConfigOwner })
|
|
3542
3531
|
: !this.#isCredentiallessProvider(provider);
|
|
3543
|
-
let preflightAuthConfigurationGeneration = this.authStorage.getProviderConfigurationGeneration(
|
|
3532
|
+
let preflightAuthConfigurationGeneration = this.authStorage.getProviderConfigurationGeneration(
|
|
3533
|
+
provider,
|
|
3534
|
+
this.#authStorageConfigOwner,
|
|
3535
|
+
);
|
|
3544
3536
|
let preflightOAuthRefreshGeneration = this.authStorage.getProviderOAuthRefreshGeneration(provider);
|
|
3545
3537
|
if (shouldPreflightAuth) {
|
|
3546
3538
|
if (optionalAuth && isCurrentPreflight()) this.#credentiallessAuthFallbackProviders.delete(provider);
|
|
@@ -3555,7 +3547,10 @@ export class ModelRegistry {
|
|
|
3555
3547
|
credentialSessionId,
|
|
3556
3548
|
}),
|
|
3557
3549
|
);
|
|
3558
|
-
const currentAuthConfigurationGeneration = this.authStorage.getProviderConfigurationGeneration(
|
|
3550
|
+
const currentAuthConfigurationGeneration = this.authStorage.getProviderConfigurationGeneration(
|
|
3551
|
+
provider,
|
|
3552
|
+
this.#authStorageConfigOwner,
|
|
3553
|
+
);
|
|
3559
3554
|
if (preflightAuthConfigurationGeneration !== currentAuthConfigurationGeneration) {
|
|
3560
3555
|
const currentOAuthRefreshGeneration = this.authStorage.getProviderOAuthRefreshGeneration(provider);
|
|
3561
3556
|
if (
|
|
@@ -3633,6 +3628,9 @@ export class ModelRegistry {
|
|
|
3633
3628
|
const isCurrentEndpoint = () =>
|
|
3634
3629
|
endpoint ===
|
|
3635
3630
|
this.#normalizeDiscoveryEvidenceEndpoint(this.#effectiveDiscoveryProviderConfig(providerConfig).baseUrl ?? "");
|
|
3631
|
+
const isCurrentAuthConfiguration = () =>
|
|
3632
|
+
preflightAuthConfigurationGeneration ===
|
|
3633
|
+
this.authStorage.getProviderConfigurationGeneration(provider, this.#authStorageConfigOwner);
|
|
3636
3634
|
const isCurrentProviderRefresh = () =>
|
|
3637
3635
|
providerRefresh === undefined ||
|
|
3638
3636
|
("providerId" in providerRefresh
|
|
@@ -3704,7 +3702,7 @@ export class ModelRegistry {
|
|
|
3704
3702
|
},
|
|
3705
3703
|
getEvidenceGeneration: provider => this.#getProviderEvidenceGeneration(provider.provider, preflightApiKey),
|
|
3706
3704
|
cacheDynamicModelProvenance: cacheLookupProvenance,
|
|
3707
|
-
canPublishCache: () => isCurrentEndpoint() && isCurrentProviderRefresh(),
|
|
3705
|
+
canPublishCache: () => isCurrentAuthConfiguration() && isCurrentEndpoint() && isCurrentProviderRefresh(),
|
|
3708
3706
|
});
|
|
3709
3707
|
const authGeneration =
|
|
3710
3708
|
mergeInput.authGeneration ??
|
|
@@ -3712,6 +3710,7 @@ export class ModelRegistry {
|
|
|
3712
3710
|
const current =
|
|
3713
3711
|
mergeInput.current &&
|
|
3714
3712
|
authGeneration === this.#getProviderEvidenceGeneration(effectiveProviderConfig.provider, preflightApiKey) &&
|
|
3713
|
+
isCurrentAuthConfiguration() &&
|
|
3715
3714
|
isCurrentEndpoint();
|
|
3716
3715
|
if (!current) {
|
|
3717
3716
|
return {
|
|
@@ -3899,9 +3898,15 @@ export class ModelRegistry {
|
|
|
3899
3898
|
// The token is only needed if the dynamic fetch fires (cache miss),
|
|
3900
3899
|
// and failures there are handled gracefully.
|
|
3901
3900
|
const peekKey = async (descriptor: { providerId: string }) => {
|
|
3902
|
-
const configurationGeneration = this.authStorage.getProviderConfigurationGeneration(
|
|
3901
|
+
const configurationGeneration = this.authStorage.getProviderConfigurationGeneration(
|
|
3902
|
+
descriptor.providerId,
|
|
3903
|
+
this.#authStorageConfigOwner,
|
|
3904
|
+
);
|
|
3903
3905
|
const apiKey = await this.#peekApiKeyForProvider(descriptor.providerId, { credentialSessionId });
|
|
3904
|
-
if (
|
|
3906
|
+
if (
|
|
3907
|
+
configurationGeneration !==
|
|
3908
|
+
this.authStorage.getProviderConfigurationGeneration(descriptor.providerId, this.#authStorageConfigOwner)
|
|
3909
|
+
) {
|
|
3905
3910
|
return { apiKey: undefined, authGeneration: undefined };
|
|
3906
3911
|
}
|
|
3907
3912
|
return {
|
|
@@ -4071,13 +4076,6 @@ export class ModelRegistry {
|
|
|
4071
4076
|
this.#descriptorDiscoveryEvidence.set(options.providerId, {
|
|
4072
4077
|
fresh: result.fetched,
|
|
4073
4078
|
modelIds: new Set(models.map(model => model.id)),
|
|
4074
|
-
...(result.dynamicModelIds === undefined
|
|
4075
|
-
? {}
|
|
4076
|
-
: {
|
|
4077
|
-
profileModelIds: new Set(result.dynamicModelIds),
|
|
4078
|
-
profileFresh: !result.stale,
|
|
4079
|
-
profileEndpoint: endpoint,
|
|
4080
|
-
}),
|
|
4081
4079
|
authGeneration,
|
|
4082
4080
|
endpoint: this.#normalizeDiscoveryEvidenceEndpoint(models[0]?.baseUrl ?? endpoint),
|
|
4083
4081
|
});
|
|
@@ -5005,6 +5003,14 @@ export class ModelRegistry {
|
|
|
5005
5003
|
}
|
|
5006
5004
|
const generated = this.#generatedAuthHeaders.get(models[index]!);
|
|
5007
5005
|
if (generated) this.#generatedAuthHeaders.set(result[index]!, generated);
|
|
5006
|
+
// Register finalized clone as trusted if the original is trusted
|
|
5007
|
+
// registerFinalizedModelClone builds a fresh trusted object from the original's snapshot
|
|
5008
|
+
if (result[index]) {
|
|
5009
|
+
const registeredClone = registerFinalizedModelClone(models[index]!, result[index]);
|
|
5010
|
+
if (registeredClone) {
|
|
5011
|
+
result[index] = registeredClone;
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5008
5014
|
}
|
|
5009
5015
|
return result;
|
|
5010
5016
|
}
|
|
@@ -5648,9 +5654,10 @@ export class ModelRegistry {
|
|
|
5648
5654
|
|
|
5649
5655
|
/**
|
|
5650
5656
|
* Get selectable models with auth configured.
|
|
5651
|
-
* This is a fast check that doesn't refresh OAuth tokens.
|
|
5652
|
-
* authoritative
|
|
5653
|
-
*
|
|
5657
|
+
* This is a fast check that doesn't refresh OAuth tokens. The bundled catalog
|
|
5658
|
+
* is authoritative for visibility: live discovery only enriches entries and
|
|
5659
|
+
* adds unknown ids, and never removes a bundled model. A provider that cannot
|
|
5660
|
+
* serve a model reports its own error when the model is used.
|
|
5654
5661
|
*/
|
|
5655
5662
|
getAvailable(): Model<Api>[] {
|
|
5656
5663
|
this.#synchronizeEnvironmentCredentials();
|
|
@@ -5664,82 +5671,12 @@ export class ModelRegistry {
|
|
|
5664
5671
|
) {
|
|
5665
5672
|
return this.#availableModelsCache;
|
|
5666
5673
|
}
|
|
5667
|
-
|
|
5668
|
-
const bundledIdsByProvider = new Map<string, Set<string>>();
|
|
5669
|
-
this.#availableModelsCache = this.#models.filter(model => {
|
|
5670
|
-
if (!this.#isModelAvailable(model, disabledProviders)) return false;
|
|
5671
|
-
|
|
5672
|
-
let liveIds = authoritativeDiscoveryIds.get(model.provider);
|
|
5673
|
-
if (!authoritativeDiscoveryIds.has(model.provider)) {
|
|
5674
|
-
liveIds = this.#getAuthoritativeDiscoveredModelIds(model.provider);
|
|
5675
|
-
authoritativeDiscoveryIds.set(model.provider, liveIds);
|
|
5676
|
-
}
|
|
5677
|
-
// Undefined means discovery has not run successfully for the current
|
|
5678
|
-
// provider context. Keep the bundled catalog as the explicit fallback.
|
|
5679
|
-
if (liveIds === undefined) return true;
|
|
5680
|
-
if (this.#hasCustomModelOverlay(model.provider, model.id)) return true;
|
|
5681
|
-
|
|
5682
|
-
const activity = this.#providerActivity.get(model.provider);
|
|
5683
|
-
if (!activity?.staticModelIds.has(model.id)) return liveIds.has(model.id);
|
|
5684
|
-
|
|
5685
|
-
let bundledIds = bundledIdsByProvider.get(model.provider);
|
|
5686
|
-
if (!bundledIds) {
|
|
5687
|
-
bundledIds = new Set(
|
|
5688
|
-
(getBundledModels(model.provider as Parameters<typeof getBundledModels>[0]) as Model<Api>[]).map(
|
|
5689
|
-
candidate => candidate.id,
|
|
5690
|
-
),
|
|
5691
|
-
);
|
|
5692
|
-
bundledIdsByProvider.set(model.provider, bundledIds);
|
|
5693
|
-
}
|
|
5694
|
-
return !bundledIds.has(model.id) || liveIds.has(model.id);
|
|
5695
|
-
});
|
|
5674
|
+
this.#availableModelsCache = this.#models.filter(model => this.#isModelAvailable(model, disabledProviders));
|
|
5696
5675
|
this.#availableModelsDisabledProviders = disabledProviderKey;
|
|
5697
5676
|
this.#availableModelsEnvFingerprint = envFingerprint;
|
|
5698
5677
|
return this.#availableModelsCache;
|
|
5699
5678
|
}
|
|
5700
5679
|
|
|
5701
|
-
/**
|
|
5702
|
-
* Return the current live model ids only when discovery produced an
|
|
5703
|
-
* authoritative catalog for the provider and endpoint. An unavailable or
|
|
5704
|
-
* failed discovery returns undefined so callers retain the bundled fallback.
|
|
5705
|
-
*/
|
|
5706
|
-
#getAuthoritativeDiscoveredModelIds(provider: string): ReadonlySet<string> | undefined {
|
|
5707
|
-
const descriptorEvidence = this.#descriptorDiscoveryEvidence.get(provider);
|
|
5708
|
-
if (descriptorEvidence?.profileFresh && descriptorEvidence.profileModelIds !== undefined) {
|
|
5709
|
-
try {
|
|
5710
|
-
if (
|
|
5711
|
-
descriptorEvidence.authGeneration === this.#getProviderEvidenceGeneration(provider) &&
|
|
5712
|
-
descriptorEvidence.profileEndpoint ===
|
|
5713
|
-
this.#normalizeDiscoveryEvidenceEndpoint(this.#getProviderBaseUrlForDiscovery(provider) ?? "")
|
|
5714
|
-
) {
|
|
5715
|
-
return descriptorEvidence.profileModelIds;
|
|
5716
|
-
}
|
|
5717
|
-
} catch {
|
|
5718
|
-
// A provider context that can no longer be verified must use its fallback.
|
|
5719
|
-
}
|
|
5720
|
-
}
|
|
5721
|
-
|
|
5722
|
-
const configuredEvidence = this.#configuredDiscoveryEvidence.get(provider);
|
|
5723
|
-
if (!configuredEvidence) return undefined;
|
|
5724
|
-
const discoveryState = this.#discoveryManager.getState(provider);
|
|
5725
|
-
if (
|
|
5726
|
-
discoveryState?.status !== "ok" &&
|
|
5727
|
-
discoveryState?.status !== "cached" &&
|
|
5728
|
-
discoveryState?.status !== "empty"
|
|
5729
|
-
) {
|
|
5730
|
-
return undefined;
|
|
5731
|
-
}
|
|
5732
|
-
try {
|
|
5733
|
-
return configuredEvidence.authGeneration === this.#getProviderEvidenceGeneration(provider) &&
|
|
5734
|
-
configuredEvidence.endpoint ===
|
|
5735
|
-
this.#normalizeDiscoveryEvidenceEndpoint(this.#getProviderBaseUrlForDiscovery(provider) ?? "")
|
|
5736
|
-
? configuredEvidence.modelIds
|
|
5737
|
-
: undefined;
|
|
5738
|
-
} catch {
|
|
5739
|
-
return undefined;
|
|
5740
|
-
}
|
|
5741
|
-
}
|
|
5742
|
-
|
|
5743
5680
|
#synchronizeEnvironmentCredentials(): void {
|
|
5744
5681
|
// Runtime registrations own a provider while their credential is present.
|
|
5745
5682
|
// Refresh them first so a missing runtime env key can hand ownership back to
|
|
@@ -5753,49 +5690,6 @@ export class ModelRegistry {
|
|
|
5753
5690
|
}
|
|
5754
5691
|
}
|
|
5755
5692
|
|
|
5756
|
-
/**
|
|
5757
|
-
* Get authenticated models, excluding bundled entries that a fresh provider
|
|
5758
|
-
* catalog has positively shown to be unavailable. Bundled entries remain
|
|
5759
|
-
* usable until live catalog evidence exists so offline startup is unchanged.
|
|
5760
|
-
*/
|
|
5761
|
-
getAvailableForProfileActivation(): Model<Api>[] {
|
|
5762
|
-
const bundledIdsByProvider = new Map<string, Set<string>>();
|
|
5763
|
-
// Evidence staleness depends only on the provider, and resolving it scans the
|
|
5764
|
-
// catalog for the provider base URL. Decide it once per provider per call so a
|
|
5765
|
-
// multi-thousand-model catalog is not rescanned for every model.
|
|
5766
|
-
const staleEvidenceByProvider = new Map<string, boolean>();
|
|
5767
|
-
return this.getAvailable().filter(model => {
|
|
5768
|
-
const evidence = this.#descriptorDiscoveryEvidence.get(model.provider);
|
|
5769
|
-
if (!evidence?.profileFresh || evidence.profileModelIds === undefined) return true;
|
|
5770
|
-
if (this.#hasCustomModelOverlay(model.provider, model.id)) return true;
|
|
5771
|
-
let bundledModelIds = bundledIdsByProvider.get(model.provider);
|
|
5772
|
-
if (!bundledModelIds) {
|
|
5773
|
-
bundledModelIds = new Set(
|
|
5774
|
-
(getBundledModels(model.provider as Parameters<typeof getBundledModels>[0]) as Model<Api>[]).map(
|
|
5775
|
-
candidate => candidate.id,
|
|
5776
|
-
),
|
|
5777
|
-
);
|
|
5778
|
-
bundledIdsByProvider.set(model.provider, bundledModelIds);
|
|
5779
|
-
}
|
|
5780
|
-
if (!bundledModelIds.has(model.id)) return true;
|
|
5781
|
-
let staleEvidence = staleEvidenceByProvider.get(model.provider);
|
|
5782
|
-
if (staleEvidence === undefined) {
|
|
5783
|
-
staleEvidence =
|
|
5784
|
-
evidence.authGeneration !== this.#getProviderEvidenceGeneration(model.provider) ||
|
|
5785
|
-
evidence.profileEndpoint !==
|
|
5786
|
-
this.#normalizeDiscoveryEvidenceEndpoint(this.#getProviderBaseUrlForDiscovery(model.provider) ?? "");
|
|
5787
|
-
staleEvidenceByProvider.set(model.provider, staleEvidence);
|
|
5788
|
-
}
|
|
5789
|
-
if (staleEvidence) return true;
|
|
5790
|
-
return evidence.profileModelIds.has(model.id);
|
|
5791
|
-
});
|
|
5792
|
-
}
|
|
5793
|
-
|
|
5794
|
-
#hasCustomModelOverlay(provider: string, id: string): boolean {
|
|
5795
|
-
const matches = (overlay: CustomModelOverlay) => overlay.provider === provider && overlay.id === id;
|
|
5796
|
-
return this.#customModelOverlays.some(matches) || this.#runtimeModelOverlays.some(matches);
|
|
5797
|
-
}
|
|
5798
|
-
|
|
5799
5693
|
#hasFreshOrStaticModelEvidence(model: Model<Api>): boolean {
|
|
5800
5694
|
const evidence = this.#providerActivity.get(model.provider);
|
|
5801
5695
|
if (
|
|
@@ -51,6 +51,13 @@ export function resolveSkillScopeTrust(
|
|
|
51
51
|
return DEFAULT_SKILL_SCOPE_TRUST;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/** Resolve permission to read a user's external skill symlinks from user-owned config only. */
|
|
55
|
+
export function resolveGlobalUserSkillLinkTrust(
|
|
56
|
+
settings: Pick<SkillDiscoverySettings, "trustUserSkills" | "enablePiUser">,
|
|
57
|
+
): boolean {
|
|
58
|
+
return resolveSkillScopeTrust(settings, "user");
|
|
59
|
+
}
|
|
60
|
+
|
|
54
61
|
export const DEFAULT_SKILL_DISCOVERY_SETTINGS: SkillDiscoverySettings = {
|
|
55
62
|
enabled: true,
|
|
56
63
|
enableSkillCommands: true,
|
|
@@ -122,8 +122,9 @@ function parseRootList(value: string | undefined): string[] {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
function resolveManagedWorktreeRoot(root: string, configured: string | undefined): string {
|
|
125
|
-
|
|
126
|
-
const
|
|
125
|
+
// Function replacers so a `$` in the home or repository path is kept verbatim.
|
|
126
|
+
const template = (configured?.trim() || "{repo}/.worktrees").replace(/^~(?=\/|$)/, () => os.homedir());
|
|
127
|
+
const resolved = template.replaceAll("{repo}", () => path.basename(root));
|
|
127
128
|
return path.resolve(path.isAbsolute(resolved) ? resolved : path.join(path.dirname(root), resolved));
|
|
128
129
|
}
|
|
129
130
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export async function assertDeleteInsideWorkspace(cwd: string, filePath: string): Promise<void> {
|
|
5
|
+
const root = await fs.realpath(cwd);
|
|
6
|
+
const target = await fs.realpath(filePath);
|
|
7
|
+
if (target !== root && !target.startsWith(`${root}${path.sep}`)) {
|
|
8
|
+
throw new Error(`Delete escapes the workspace: ${filePath}`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools Cursor already runs on a dedicated exec channel.
|
|
3
|
+
* Keep this aligned with CURSOR_NATIVE_TOOL_NAMES in packages/ai/src/providers/cursor.ts.
|
|
4
|
+
*/
|
|
5
|
+
const CURSOR_DEDICATED_CHANNEL_TOOLS = new Set(["bash", "read", "write", "delete", "ls", "grep", "lsp", "todo_write"]);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Name to dispatch from a Cursor MCP call.
|
|
9
|
+
* Dedicated-channel tools are refused here. Advertised session tools such as eval stay allowed.
|
|
10
|
+
*/
|
|
11
|
+
export function cursorMcpDispatchName(call: { toolName?: string; name?: string }): string | null {
|
|
12
|
+
const toolName = call.toolName || call.name || "";
|
|
13
|
+
if (toolName.length === 0 || CURSOR_DEDICATED_CHANNEL_TOOLS.has(toolName)) return null;
|
|
14
|
+
return toolName;
|
|
15
|
+
}
|
package/src/cursor.ts
CHANGED
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
piTimeout,
|
|
24
24
|
} from "@gajae-code/ai/providers/cursor/exec-modern";
|
|
25
25
|
import { sanitizeText } from "@gajae-code/utils";
|
|
26
|
+
import { assertDeleteInsideWorkspace } from "./cursor-delete-path";
|
|
27
|
+
import { cursorMcpDispatchName } from "./cursor-mcp-name";
|
|
26
28
|
import { resolveToCwd } from "./tools/path-utils";
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -184,6 +186,7 @@ async function executeDelete(
|
|
|
184
186
|
throw new Error(`Path is not a file: ${pathArg}`);
|
|
185
187
|
}
|
|
186
188
|
|
|
189
|
+
await assertDeleteInsideWorkspace(options.cwd, absolutePath);
|
|
187
190
|
fs.rmSync(absolutePath);
|
|
188
191
|
|
|
189
192
|
const sizeText = fileStat.size ? ` (${fileStat.size} bytes)` : "";
|
|
@@ -646,11 +649,19 @@ export class CursorExecHandlers implements ICursorExecHandlers {
|
|
|
646
649
|
|
|
647
650
|
async mcp(call: CursorMcpCall, signal?: AbortSignal, markNonAbortable?: () => void) {
|
|
648
651
|
const options = this.#optionsForCall();
|
|
649
|
-
const
|
|
652
|
+
const requestedName = call.toolName || call.name || "";
|
|
653
|
+
const toolName = cursorMcpDispatchName(call);
|
|
650
654
|
const toolCallId = decodeToolCallId(call.toolCallId);
|
|
655
|
+
const availableTools = Array.from(options.tools.keys()).filter(
|
|
656
|
+
name => cursorMcpDispatchName({ toolName: name }) !== null,
|
|
657
|
+
);
|
|
658
|
+
if (!toolName) {
|
|
659
|
+
const message = formatMcpToolErrorMessage(requestedName, availableTools);
|
|
660
|
+
const result = buildToolErrorResult(message);
|
|
661
|
+
return createToolResultMessage(toolCallId, requestedName || "mcp", result, true);
|
|
662
|
+
}
|
|
651
663
|
const tool = options.tools.get(toolName);
|
|
652
664
|
if (!tool) {
|
|
653
|
-
const availableTools = Array.from(options.tools.keys()).filter(name => name.startsWith("mcp__"));
|
|
654
665
|
const message = formatMcpToolErrorMessage(toolName, availableTools);
|
|
655
666
|
const result = buildToolErrorResult(message);
|
|
656
667
|
return createToolResultMessage(toolCallId, toolName, result, true);
|
|
@@ -35,6 +35,8 @@ export interface LoadCustomizationInventoryOptions {
|
|
|
35
35
|
home?: string;
|
|
36
36
|
/** Skill management policy snapshot (trust, include/ignore, disabledExtensions). */
|
|
37
37
|
policy?: SkillManagementPolicy;
|
|
38
|
+
/** User-owned permission to follow external user skill symlinks. */
|
|
39
|
+
allowExternalUserSkillSymlinks?: boolean;
|
|
38
40
|
/** Disabled extension ids (`skill:<name>` / `mcp:<name>`) from settings. */
|
|
39
41
|
disabledExtensions?: string[];
|
|
40
42
|
}
|
|
@@ -94,6 +96,7 @@ async function loadSkillRows(options: LoadCustomizationInventoryOptions, _warnin
|
|
|
94
96
|
cwd: options.cwd,
|
|
95
97
|
home: options.home,
|
|
96
98
|
policy: options.policy,
|
|
99
|
+
allowExternalUserSkillSymlinks: options.allowExternalUserSkillSymlinks,
|
|
97
100
|
});
|
|
98
101
|
const managedPaths = new Set<string>();
|
|
99
102
|
for (const record of records) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** True when a session header names this parent file or its basename. */
|
|
2
|
+
export function sessionBelongsToParent(headerLine: string, parentBasename: string): boolean {
|
|
3
|
+
let parentSession: unknown;
|
|
4
|
+
try {
|
|
5
|
+
parentSession = (JSON.parse(headerLine) as { parentSession?: unknown }).parentSession;
|
|
6
|
+
} catch {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (typeof parentSession !== "string" || parentSession.length === 0) return false;
|
|
10
|
+
const normalized = parentSession.replaceAll("\\", "/");
|
|
11
|
+
const base =
|
|
12
|
+
normalized
|
|
13
|
+
.split("/")
|
|
14
|
+
.pop()
|
|
15
|
+
?.replace(/\.jsonl$/, "") ?? "";
|
|
16
|
+
return (
|
|
17
|
+
normalized === parentBasename ||
|
|
18
|
+
base === parentBasename ||
|
|
19
|
+
normalized.endsWith(`/${parentBasename}`) ||
|
|
20
|
+
normalized.endsWith(`/${parentBasename}.jsonl`)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
resolveEquivalentPath,
|
|
18
18
|
} from "@gajae-code/utils";
|
|
19
19
|
import type { CpuProfile, HeapSnapshot } from "./profiler";
|
|
20
|
+
import { sessionBelongsToParent } from "./report-bundle-parent";
|
|
20
21
|
import { collectSystemInfo, sanitizeEnv } from "./system-info";
|
|
21
22
|
|
|
22
23
|
/** Maximum number of log lines to load into memory at once. */
|
|
@@ -283,6 +284,8 @@ async function addSubagentSessions(
|
|
|
283
284
|
const archivePath = `subagents/${filename}`;
|
|
284
285
|
try {
|
|
285
286
|
const content = await Bun.file(filePath).text();
|
|
287
|
+
const headerLine = content.split("\n", 1)[0] ?? "";
|
|
288
|
+
if (!sessionBelongsToParent(headerLine, parentBasename)) continue;
|
|
286
289
|
data[archivePath] = content;
|
|
287
290
|
files.push(archivePath);
|
|
288
291
|
|
package/src/debug/system-info.ts
CHANGED
|
@@ -99,7 +99,19 @@ export function formatSystemInfo(info: SystemInfo): string {
|
|
|
99
99
|
|
|
100
100
|
/** Sanitize environment variables by redacting sensitive values */
|
|
101
101
|
export function sanitizeEnv(env: Record<string, string | undefined>): Record<string, string> {
|
|
102
|
-
const SENSITIVE_PATTERNS = [
|
|
102
|
+
const SENSITIVE_PATTERNS = [
|
|
103
|
+
/key/i,
|
|
104
|
+
/secret/i,
|
|
105
|
+
/token/i,
|
|
106
|
+
/pass/i,
|
|
107
|
+
/auth/i,
|
|
108
|
+
/credential/i,
|
|
109
|
+
/api/i,
|
|
110
|
+
/private/i,
|
|
111
|
+
/cookie/i,
|
|
112
|
+
/dsn/i,
|
|
113
|
+
/url$/i,
|
|
114
|
+
];
|
|
103
115
|
|
|
104
116
|
const result: Record<string, string> = {};
|
|
105
117
|
for (const [k, v] of Object.entries(env)) {
|
|
@@ -2,12 +2,18 @@ import type {
|
|
|
2
2
|
Api,
|
|
3
3
|
AssistantMessageEventStream,
|
|
4
4
|
Context,
|
|
5
|
+
FetchImpl,
|
|
5
6
|
Model,
|
|
6
7
|
SimpleStreamOptions,
|
|
7
8
|
} from '@gajae-code/ai/core';
|
|
8
9
|
import { streamOpenAIResponses } from '@gajae-code/ai/providers/openai-responses';
|
|
10
|
+
import {
|
|
11
|
+
getGrokCliVersion,
|
|
12
|
+
parseMinimumVersionFrom426,
|
|
13
|
+
updateVersionFromError,
|
|
14
|
+
} from './version-manager';
|
|
9
15
|
|
|
10
|
-
|
|
16
|
+
type FetchInput = Parameters<FetchImpl>[0];
|
|
11
17
|
|
|
12
18
|
/**
|
|
13
19
|
* Stream function that adds Grok CLI-specific headers to requests.
|
|
@@ -16,6 +22,7 @@ const GROK_CLI_VERSION = '0.2.33';
|
|
|
16
22
|
* - x-grok-conv-id: <session/conversation ID>
|
|
17
23
|
* - x-grok-model-override: <model ID>
|
|
18
24
|
* - x-xai-token-auth: xai-grok-cli
|
|
25
|
+
* - x-grok-client-version: learned from HTTP 426 responses; defaults to 1.0.13 and retries once on upgrade
|
|
19
26
|
*/
|
|
20
27
|
export function streamGrokCli(
|
|
21
28
|
model: Model<Api>,
|
|
@@ -23,10 +30,14 @@ export function streamGrokCli(
|
|
|
23
30
|
options?: SimpleStreamOptions,
|
|
24
31
|
): AssistantMessageEventStream {
|
|
25
32
|
const sessionId = options?.sessionId;
|
|
33
|
+
|
|
34
|
+
// Get the Grok CLI version: learned from 426 responses or fallback
|
|
35
|
+
const grokCliVersion = getGrokCliVersion();
|
|
36
|
+
|
|
26
37
|
const headers: Record<string, string> = {
|
|
27
38
|
...options?.headers,
|
|
28
39
|
'x-grok-client-identifier': 'gjc-grok-cli',
|
|
29
|
-
'x-grok-client-version':
|
|
40
|
+
'x-grok-client-version': grokCliVersion,
|
|
30
41
|
'x-xai-token-auth': 'xai-grok-cli',
|
|
31
42
|
'x-grok-model-override': model.id,
|
|
32
43
|
};
|
|
@@ -40,11 +51,63 @@ export function streamGrokCli(
|
|
|
40
51
|
api: 'openai-responses',
|
|
41
52
|
} as Model<'openai-responses'>;
|
|
42
53
|
|
|
54
|
+
// Wrap fetch to intercept 426 errors and extract version info
|
|
55
|
+
const baseFetch = options?.fetch ?? (globalThis.fetch.bind(globalThis) as FetchImpl);
|
|
56
|
+
const wrappedFetch = wrapFetchForVersionHandling(baseFetch);
|
|
57
|
+
|
|
43
58
|
return streamOpenAIResponses(responsesModel, context, {
|
|
44
59
|
...options,
|
|
45
60
|
headers,
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
fetch: wrappedFetch,
|
|
62
|
+
onResponse(response, _responseModel, scope, signal) {
|
|
63
|
+
return options?.onResponse?.(response, model, scope, signal);
|
|
48
64
|
},
|
|
49
65
|
});
|
|
50
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Wraps a fetch function to learn from HTTP 426 responses and retry once with a newer version.
|
|
70
|
+
*/
|
|
71
|
+
function wrapFetchForVersionHandling(baseFetch: FetchImpl): FetchImpl {
|
|
72
|
+
return Object.assign(
|
|
73
|
+
async (input: FetchInput, init?: RequestInit): Promise<Response> => {
|
|
74
|
+
const firstInput =
|
|
75
|
+
input instanceof Request ? (input.clone() as unknown as FetchInput) : input;
|
|
76
|
+
const response = await baseFetch(firstInput, init);
|
|
77
|
+
|
|
78
|
+
if (response.status !== 426) return response;
|
|
79
|
+
|
|
80
|
+
let errorText: string;
|
|
81
|
+
try {
|
|
82
|
+
errorText = await response.clone().text();
|
|
83
|
+
} catch {
|
|
84
|
+
return response;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!parseMinimumVersionFrom426(errorText)) return response;
|
|
88
|
+
|
|
89
|
+
const retryHeaders = new Headers(
|
|
90
|
+
init?.headers ?? (input instanceof Request ? input.headers : undefined),
|
|
91
|
+
);
|
|
92
|
+
const requestedVersion = retryHeaders.get('x-grok-client-version');
|
|
93
|
+
const learnedVersion = updateVersionFromError(errorText);
|
|
94
|
+
if (!requestedVersion || learnedVersion === requestedVersion) return response;
|
|
95
|
+
|
|
96
|
+
retryHeaders.set('x-grok-client-version', learnedVersion);
|
|
97
|
+
const retryInput =
|
|
98
|
+
input instanceof Request ? (input.clone() as unknown as FetchInput) : input;
|
|
99
|
+
const retryResponse = await baseFetch(retryInput, { ...init, headers: retryHeaders });
|
|
100
|
+
|
|
101
|
+
if (retryResponse.status === 426) {
|
|
102
|
+
try {
|
|
103
|
+
updateVersionFromError(await retryResponse.clone().text());
|
|
104
|
+
} catch {
|
|
105
|
+
// Keep the retry response intact if its body cannot be inspected.
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return retryResponse;
|
|
110
|
+
},
|
|
111
|
+
{ preconnect: baseFetch.preconnect },
|
|
112
|
+
) as FetchImpl;
|
|
113
|
+
}
|