@aiwg/cli 2026.10.10 → 2026.10.11
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/agentic/code/providers/model-capabilities.v1.json +78 -14
- package/dist/src/cli/handlers/sessions.js +198 -15
- package/dist/src/cli/handlers/use.js +12 -4
- package/dist/src/config/worker-context.js +337 -0
- package/dist/src/mcp/tools/worker-invoke.mjs +108 -10
- package/dist/src/models/model-capabilities.v1.json +78 -14
- package/dist/src/models/provider-policy.js +7 -0
- package/dist/src/policy/authorization.js +29 -1
- package/dist/src/process/aiwg-probe-command.d.mts +15 -0
- package/dist/src/process/aiwg-probe-command.mjs +37 -0
- package/dist/src/sessions/adapters/grokbot.js +7 -0
- package/dist/src/sessions/batch-import.js +34 -6
- package/dist/src/sessions/contracts.js +19 -0
- package/dist/src/sessions/coverage-preflight.js +7 -1
- package/dist/src/sessions/fortemi-export-mapping.js +33 -3
- package/dist/src/sessions/host-catalog.js +157 -0
- package/dist/src/sessions/image-blobs.js +141 -0
- package/dist/src/sessions/importer.js +23 -3
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/refresh.js +25 -2
- package/dist/src/sessions/repository.js +164 -22
- package/dist/src/sessions/workspace-discovery.js +5 -2
- package/package.json +7 -1
- package/tools/ralph-external/lib/muse-adapter.mjs +10 -0
- package/tools/ralph-external/lib/worker-context.mjs +237 -0
- package/tools/ralph-external/lib/worker-invocation-ancestry.mjs +132 -0
- package/tools/ralph-external/lib/worker-invocation-processes.mjs +123 -0
- package/tools/ralph-external/lib/worker-isolation-status.mjs +48 -0
- package/tools/ralph-external/lib/worker-isolation.mjs +17 -29
- package/tools/ralph-external/lib/worker-launch-cli.mjs +3 -1
- package/tools/ralph-external/lib/worker-overflow.mjs +48 -13
- package/tools/ralph-external/lib/worker-retry-evidence.mjs +103 -0
- package/tools/ralph-external/lib/worker-termination.mjs +82 -0
- package/tools/ralph-external/session-launcher.mjs +51 -96
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
"verifiedAt": "2026-07-20",
|
|
5
5
|
"providers": {
|
|
6
6
|
"antigravity": {
|
|
7
|
+
"sessionEnvAllowlist": [
|
|
8
|
+
"GEMINI_API_KEY"
|
|
9
|
+
],
|
|
7
10
|
"agent": "native",
|
|
8
11
|
"skill": "native",
|
|
9
12
|
"globalChild": "inherited",
|
|
@@ -19,7 +22,7 @@
|
|
|
19
22
|
"invalidPinFallback": "Provider validation/error; never assume fallback",
|
|
20
23
|
"configTarget": "agy launch arguments; custom-agent model tiers are not projected from generic AIWG model ids",
|
|
21
24
|
"artifactFormat": "YAML frontmatter plus Markdown; runtime --model and --effort flags",
|
|
22
|
-
"verification": "Pinned offline contract (--help/--version only); authenticated model selection was not executed",
|
|
25
|
+
"verification": "Pinned offline contract (--help/--version only); authenticated model selection was not executed. Session credential evidence: $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
23
26
|
"sourceUrl": "https://antigravity.google/docs/cli/subagents/",
|
|
24
27
|
"verifiedAt": "2026-09-04",
|
|
25
28
|
"workerHealthAdapter": {
|
|
@@ -154,7 +157,7 @@
|
|
|
154
157
|
"Native MCP/client, MSP/ACP, gateway and conversation capabilities do not establish worker authority.",
|
|
155
158
|
"--dangerously-skip-permissions and --remote-control are never part of the direct profile; neither was ever shipped as a new argv-prompt path.",
|
|
156
159
|
"A soft-denied tool permission request (exit 0, stderr notice naming the allow-rule needed) is NOT the same as success; its exact stderr wording is not evidenced from help or changelog, so this is an open, honestly-marked detection gap rather than an invented check (tools/ralph-external/lib/antigravity-adapter.mjs ANTIGRAVITY_SOFT_DENY_RISK_NOTE).",
|
|
157
|
-
"GEMINI_API_KEY
|
|
160
|
+
"GEMINI_API_KEY is documented at https://antigravity.google/docs/install/ (reviewed 2026-10-26): settings.json must also set modelProvider to gemini; the key alone has no effect. Earlier 1.3.3 probes only exercised missing account login. This documentation confirms the credential name, not authenticated execution or qualification of this version-bound worker profile.",
|
|
158
161
|
"The 1.3.3 --effort enum (low|medium|high|xhigh|max) supersedes the stale 1.1.26-pinned three-value set in tools/providers/antigravity-transport.mjs (a separate, unedited legacy transport used by the MCP/doctor bridge, not this direct-shell profile).",
|
|
159
162
|
"Flag validation happens BEFORE auth: live probe F, `agy --print=x --input-format bogus --output-format stream-json`, returned \"Error: unknown --input-format \\\"bogus\\\" (want text or stream-json)\" without reaching the auth stop, confirming --input-format is validated against exactly {text, stream-json} independent of login state.",
|
|
160
163
|
"The brief reaches agy through adapter-frame: the installed buildWorkerStdinFrame hook supplies exactly one NDJSON user message and EOF. The stdin control stays unqualified pending one authenticated smoke run."
|
|
@@ -865,6 +868,9 @@
|
|
|
865
868
|
}
|
|
866
869
|
},
|
|
867
870
|
"cursor": {
|
|
871
|
+
"sessionEnvAllowlist": [
|
|
872
|
+
"CURSOR_API_KEY"
|
|
873
|
+
],
|
|
868
874
|
"agent": "native",
|
|
869
875
|
"skill": "unsupported",
|
|
870
876
|
"globalChild": "inherited",
|
|
@@ -873,7 +879,7 @@
|
|
|
873
879
|
"invalidPinFallback": "Plan/admin fallback may apply; record observed result",
|
|
874
880
|
"configTarget": ".cursor/agents/*.md",
|
|
875
881
|
"artifactFormat": "YAML frontmatter plus Markdown",
|
|
876
|
-
"verification": "Schema fixture and entitled Cursor invocation",
|
|
882
|
+
"verification": "Schema fixture and entitled Cursor invocation. Session credential evidence: $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
877
883
|
"sourceUrl": "https://cursor.com/docs/subagents",
|
|
878
884
|
"verifiedAt": "2026-07-20",
|
|
879
885
|
"workerHealthAdapter": {
|
|
@@ -1465,6 +1471,9 @@
|
|
|
1465
1471
|
}
|
|
1466
1472
|
},
|
|
1467
1473
|
"warp": {
|
|
1474
|
+
"sessionEnvAllowlist": [
|
|
1475
|
+
"WARP_API_KEY"
|
|
1476
|
+
],
|
|
1468
1477
|
"agent": "global-only",
|
|
1469
1478
|
"skill": "unsupported",
|
|
1470
1479
|
"globalChild": "native",
|
|
@@ -1473,7 +1482,7 @@
|
|
|
1473
1482
|
"invalidPinFallback": "Profile availability dependent",
|
|
1474
1483
|
"configTarget": "Warp agent profile or run configuration",
|
|
1475
1484
|
"artifactFormat": "Saved profile / run control plane",
|
|
1476
|
-
"verification": "Inspect active profile and run metadata",
|
|
1485
|
+
"verification": "Inspect active profile and run metadata. Session credential evidence: $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
1477
1486
|
"sourceUrl": "https://docs.warp.dev/agent-platform/capabilities/agent-profiles-permissions",
|
|
1478
1487
|
"verifiedAt": "2026-07-20",
|
|
1479
1488
|
"workerHealthAdapter": {
|
|
@@ -2284,6 +2293,7 @@
|
|
|
2284
2293
|
}
|
|
2285
2294
|
},
|
|
2286
2295
|
"windsurf": {
|
|
2296
|
+
"sessionEnvAllowlist": [],
|
|
2287
2297
|
"agent": "unsupported",
|
|
2288
2298
|
"skill": "unsupported",
|
|
2289
2299
|
"globalChild": "inherited",
|
|
@@ -2292,7 +2302,7 @@
|
|
|
2292
2302
|
"invalidPinFallback": "No portable custom-child selector",
|
|
2293
2303
|
"configTarget": "No supported portable artifact field",
|
|
2294
2304
|
"artifactFormat": "Informational policy only",
|
|
2295
|
-
"verification": "Assert unsupported fields are omitted",
|
|
2305
|
+
"verification": "Assert unsupported fields are omitted. Session environment is explicitly empty: desktop/cloud login owns authentication; no CLI credential variable is evidenced. Coverage-only: no worker execution or qualified worker adapter. See $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
2296
2306
|
"sourceUrl": "https://docs.devin.ai/desktop/cascade/skills",
|
|
2297
2307
|
"verifiedAt": "2026-07-20",
|
|
2298
2308
|
"workerHealthCoverage": {
|
|
@@ -2312,6 +2322,22 @@
|
|
|
2312
2322
|
}
|
|
2313
2323
|
},
|
|
2314
2324
|
"openclaw": {
|
|
2325
|
+
"sessionEnvAllowlist": [
|
|
2326
|
+
"OPENAI_API_KEY",
|
|
2327
|
+
"ANTHROPIC_API_KEY",
|
|
2328
|
+
"ANTHROPIC_OAUTH_TOKEN",
|
|
2329
|
+
"GEMINI_API_KEY",
|
|
2330
|
+
"GOOGLE_API_KEY",
|
|
2331
|
+
"OPENROUTER_API_KEY",
|
|
2332
|
+
"MISTRAL_API_KEY",
|
|
2333
|
+
"XAI_API_KEY",
|
|
2334
|
+
"OPENCLAW_HOME",
|
|
2335
|
+
"OPENCLAW_STATE_DIR",
|
|
2336
|
+
"OPENCLAW_CONFIG_PATH",
|
|
2337
|
+
"OPENCLAW_GATEWAY_URL",
|
|
2338
|
+
"OPENCLAW_GATEWAY_TOKEN",
|
|
2339
|
+
"OPENCLAW_GATEWAY_PASSWORD"
|
|
2340
|
+
],
|
|
2315
2341
|
"agent": "native",
|
|
2316
2342
|
"skill": "unsupported",
|
|
2317
2343
|
"globalChild": "native",
|
|
@@ -2320,7 +2346,7 @@
|
|
|
2320
2346
|
"invalidPinFallback": "Provider/account fallback must be observed",
|
|
2321
2347
|
"configTarget": "OpenClaw subagent configuration",
|
|
2322
2348
|
"artifactFormat": "JSON/JSONC runtime configuration",
|
|
2323
|
-
"verification": "Inspect resolved subagent metadata",
|
|
2349
|
+
"verification": "Inspect resolved subagent metadata. Session credential evidence: $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
2324
2350
|
"sourceUrl": "https://docs.openclaw.ai/tools/subagents",
|
|
2325
2351
|
"verifiedAt": "2026-07-20",
|
|
2326
2352
|
"workerHealthAdapter": {
|
|
@@ -2508,6 +2534,7 @@
|
|
|
2508
2534
|
}
|
|
2509
2535
|
},
|
|
2510
2536
|
"grokbot": {
|
|
2537
|
+
"sessionEnvAllowlist": [],
|
|
2511
2538
|
"agent": "unsupported",
|
|
2512
2539
|
"skill": "unsupported",
|
|
2513
2540
|
"globalChild": "informational",
|
|
@@ -2516,7 +2543,7 @@
|
|
|
2516
2543
|
"invalidPinFallback": "Report unsupported; do not fabricate xAI/Grok model pins as native",
|
|
2517
2544
|
"configTarget": "Grok Bot has no verified AIWG-owned model config path",
|
|
2518
2545
|
"artifactFormat": "Informational only",
|
|
2519
|
-
"verification": "Confirm steward models --route --provider grokbot emits unsupported/informational",
|
|
2546
|
+
"verification": "Confirm steward models --route --provider grokbot emits unsupported/informational. Session environment is explicitly empty: desktop/cloud login owns authentication; no CLI credential variable is evidenced. Coverage-only: no worker execution or qualified worker adapter. See $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
2520
2547
|
"sourceUrl": "https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-grokbot-provider-target.md",
|
|
2521
2548
|
"verifiedAt": "2026-09-15",
|
|
2522
2549
|
"workerHealthCoverage": {
|
|
@@ -2536,6 +2563,10 @@
|
|
|
2536
2563
|
}
|
|
2537
2564
|
},
|
|
2538
2565
|
"grok-build": {
|
|
2566
|
+
"sessionEnvAllowlist": [
|
|
2567
|
+
"XAI_API_KEY",
|
|
2568
|
+
"GROK_HOME"
|
|
2569
|
+
],
|
|
2539
2570
|
"agent": "inherited",
|
|
2540
2571
|
"skill": "inherited",
|
|
2541
2572
|
"globalChild": "native",
|
|
@@ -2544,7 +2575,7 @@
|
|
|
2544
2575
|
"invalidPinFallback": "Report the unavailable alias; use the sole discovered model only when exactly one is available",
|
|
2545
2576
|
"configTarget": "$GROK_HOME/config.toml [models] and [model.<alias>] (read-only discovery)",
|
|
2546
2577
|
"artifactFormat": "Grok Build model alias",
|
|
2547
|
-
"verification": "grok inspect --json plus bounded parsing of model fields from reported config layers",
|
|
2578
|
+
"verification": "grok inspect --json plus bounded parsing of model fields from reported config layers. Session credential evidence: $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
2548
2579
|
"sourceUrl": "https://docs.x.ai/build/settings",
|
|
2549
2580
|
"verifiedAt": "2026-09-21",
|
|
2550
2581
|
"workerHealthAdapter": {
|
|
@@ -2736,6 +2767,25 @@
|
|
|
2736
2767
|
}
|
|
2737
2768
|
},
|
|
2738
2769
|
"hermes": {
|
|
2770
|
+
"sessionEnvAllowlist": [
|
|
2771
|
+
"OPENAI_API_KEY",
|
|
2772
|
+
"ANTHROPIC_API_KEY",
|
|
2773
|
+
"ANTHROPIC_TOKEN",
|
|
2774
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
2775
|
+
"GEMINI_API_KEY",
|
|
2776
|
+
"GOOGLE_API_KEY",
|
|
2777
|
+
"OPENROUTER_API_KEY",
|
|
2778
|
+
"GROQ_API_KEY",
|
|
2779
|
+
"MISTRAL_API_KEY",
|
|
2780
|
+
"XAI_API_KEY",
|
|
2781
|
+
"DEEPSEEK_API_KEY",
|
|
2782
|
+
"OPENAI_BASE_URL",
|
|
2783
|
+
"ANTHROPIC_BASE_URL",
|
|
2784
|
+
"OPENROUTER_BASE_URL",
|
|
2785
|
+
"CUSTOM_BASE_URL",
|
|
2786
|
+
"HERMES_HOME",
|
|
2787
|
+
"HERMES_INFERENCE_PROVIDER"
|
|
2788
|
+
],
|
|
2739
2789
|
"agent": "global-only",
|
|
2740
2790
|
"skill": "unsupported",
|
|
2741
2791
|
"globalChild": "native",
|
|
@@ -2744,7 +2794,7 @@
|
|
|
2744
2794
|
"invalidPinFallback": "Provider resolution is global; report actual model",
|
|
2745
2795
|
"configTarget": "Hermes delegation configuration",
|
|
2746
2796
|
"artifactFormat": "Global CLI/config setting",
|
|
2747
|
-
"verification": "Inspect Hermes delegation configuration",
|
|
2797
|
+
"verification": "Inspect Hermes delegation configuration. Session credential evidence: $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
2748
2798
|
"sourceUrl": "https://hermes-agent.nousresearch.com/docs/user-guide/features/delegation",
|
|
2749
2799
|
"verifiedAt": "2026-07-20",
|
|
2750
2800
|
"workerHealthAdapter": {
|
|
@@ -2927,6 +2977,19 @@
|
|
|
2927
2977
|
}
|
|
2928
2978
|
},
|
|
2929
2979
|
"openhuman": {
|
|
2980
|
+
"sessionEnvAllowlist": [
|
|
2981
|
+
"OPENHUMAN_CORE_TOKEN",
|
|
2982
|
+
"OPENHUMAN_CORE_RPC_URL",
|
|
2983
|
+
"OPENHUMAN_CORE_HOST",
|
|
2984
|
+
"OPENHUMAN_CORE_PORT",
|
|
2985
|
+
"OPENHUMAN_WORKSPACE",
|
|
2986
|
+
"OPENHUMAN_DOTENV_PATH",
|
|
2987
|
+
"OPENHUMAN_KEYRING_MASTER_KEY",
|
|
2988
|
+
"OPENHUMAN_KEYRING_MASTER_KEY_FILE",
|
|
2989
|
+
"OPENHUMAN_APP_ENV",
|
|
2990
|
+
"BACKEND_URL",
|
|
2991
|
+
"OPENHUMAN_MODEL"
|
|
2992
|
+
],
|
|
2930
2993
|
"agent": "compiled",
|
|
2931
2994
|
"skill": "unsupported",
|
|
2932
2995
|
"globalChild": "inherited",
|
|
@@ -2935,7 +2998,7 @@
|
|
|
2935
2998
|
"invalidPinFallback": "Exact pins validate; semantic hints route dynamically",
|
|
2936
2999
|
"configTarget": "OpenHuman agent TOML",
|
|
2937
3000
|
"artifactFormat": "Standalone TOML agent definition",
|
|
2938
|
-
"verification": "Parse against OpenHuman definition schema",
|
|
3001
|
+
"verification": "Parse against OpenHuman definition schema. Session credential evidence: $AIWG_ROOT/docs/cli/sensitive-values.md#provider-recipient-exceptions (#3624).",
|
|
2939
3002
|
"sourceUrl": "https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/harness/definition.rs",
|
|
2940
3003
|
"verifiedAt": "2026-07-20",
|
|
2941
3004
|
"workerHealthAdapter": {
|
|
@@ -3154,6 +3217,7 @@
|
|
|
3154
3217
|
"${effort}",
|
|
3155
3218
|
"--workspace",
|
|
3156
3219
|
"${workspace}",
|
|
3220
|
+
"--trust-workspace",
|
|
3157
3221
|
"--approval-mode",
|
|
3158
3222
|
"never",
|
|
3159
3223
|
"--approval-judge",
|
|
@@ -3246,8 +3310,8 @@
|
|
|
3246
3310
|
},
|
|
3247
3311
|
"trust": {
|
|
3248
3312
|
"support": "unqualified",
|
|
3249
|
-
"mapping": "[]",
|
|
3250
|
-
"evidence": "Installed muse exec --help (Muse Code 1.4.12, 2026-10-23); bounded renderer checked on operator qualification; no backend attestation."
|
|
3313
|
+
"mapping": "[\"--trust-workspace\"]",
|
|
3314
|
+
"evidence": "Installed muse exec --help (Muse Code 1.4.12, 2026-10-23); bounded renderer checked on operator qualification; no backend attestation. Tier 0 workspaces are conductor-prepared worker trees the conductor owns, so the profile binds --trust-workspace by default (#3685: untrusted Muse loads project_sources=0 with user skills only and empty hook admission; trusted loads project_sources=1, project skills and hooks)."
|
|
3251
3315
|
},
|
|
3252
3316
|
"children": {
|
|
3253
3317
|
"support": "unqualified",
|
|
@@ -3268,13 +3332,13 @@
|
|
|
3268
3332
|
"Live qualification is an open S1 blocker; installed help and synthetic/echo mechanics are not paid inference qualification.",
|
|
3269
3333
|
"Configured-model events provide runtime-configured identity only, never backend attestation.",
|
|
3270
3334
|
"Contributor data policy is explicit; shared policy denies contributor models and never silently selects the CLI default.",
|
|
3271
|
-
"Workspace trust
|
|
3335
|
+
"Workspace trust is bound on for conductor-prepared worker trees (the conductor owns the worktree), so project rules/skills/hooks load; only a host-qualified trust mapping may change it. Approval-mode never and approval-judge off retain the sandbox. Muse requires a qualified external boundary.",
|
|
3272
3336
|
"Host qualification must bind an absolute output-schema mapping and include that schema in runtimeFiles.",
|
|
3273
3337
|
"Muse JSONL strict normalization needs the shared strict-parser hook; the MCP bridge must consume the selected provider parser. MSP is not MCP.",
|
|
3274
3338
|
"Semantic step/tool completion grammar and native session-log layout remain unavailable; unrelated logs, deltas and CPU cannot establish progress.",
|
|
3275
3339
|
"Shared version gate: installation requires the raw trimmed banner Muse Code 1.4.4 (1.4.4-R5419.1), but semver selection requires 1.4.4-R5419.1. No normalization exists; keep unqualified until the shared owner binds raw and normalized versions.",
|
|
3276
3340
|
"Operator qualification approves the installed direct renderer, not authenticated inference or backend model identity.",
|
|
3277
|
-
"Workspace trust
|
|
3341
|
+
"Workspace trust is on for conductor-prepared worker trees. Only never approval is supported. Explicit unsupported controls block dispatch.",
|
|
3278
3342
|
"Self-delegation must be explicitly allowed by policy; no native child-denial flag is assumed."
|
|
3279
3343
|
],
|
|
3280
3344
|
"health": {
|
|
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { basename, dirname, isAbsolute, join, resolve, } from 'node:path';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
import { providerScopeWarnings } from '../../sessions/coverage-preflight.js';
|
|
6
|
-
import { CLAUDE_ADAPTER_VERSION, ClaudeSessionAdapter, CODEX_ADAPTER_VERSION, CodexSessionAdapter, COPILOT_ADAPTER_VERSION, CopilotSessionAdapter, CURSOR_ADAPTER_VERSION, CursorSessionAdapter, FACTORY_ADAPTER_VERSION, FactorySessionAdapter, HERMES_ADAPTER_VERSION, HermesSessionAdapter, OPENCODE_ADAPTER_VERSION, OpenCodeSessionAdapter, OPENCLAW_ADAPTER_VERSION, OpenClawSessionAdapter, OPENHUMAN_ADAPTER_VERSION, OpenHumanSessionAdapter, GROKBOT_ADAPTER_VERSION, GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS, GrokbotSessionAdapter, GROK_BUILD_ADAPTER_VERSION, GROK_BUILD_CLI_EXPORT_LOCATOR_CLASS, GrokBuildSessionAdapter, grokBuildList, grokBuildSearch, grokBuildExport, grokHeadlessSessionIdFromFile, MUSE_ADAPTER_VERSION, MuseSessionAdapter, PI_ADAPTER_VERSION, PiSessionAdapter, DEEPSEEK_HARNESS_ADAPTER_VERSION, DeepSeekHarnessSessionAdapter, OmpSessionAdapter, OMP_ADAPTER_VERSION, WARP_ADAPTER_VERSION, WarpSessionAdapter, DEVIN_DESKTOP_ADAPTER_VERSION, DevinDesktopSessionAdapter, CandidateExtractionService, GENERIC_ADAPTER_VERSION, GenericSessionInterchangeAdapter, IncrementalSessionImporter, ImportLeaseContentionError, FilesystemMemoryDestination, FilesystemPromotionDispositionCoordinator, MemoryPromotionGateway, SESSION_CONTRACT_VERSION, SessionContractError, SessionRepository, SessionSourceSchema, StructuralCandidateExtractor, resolveMemoryConsumerManifest, assertSessionProviderId, acquireImportLease, defaultDiscoveryManifestPath, discoverWorkspaceHistories, createSessionAdapterRegistry, coveragePreflight, expectedSessionProviders, deriveSessionTimeline, importDiscoveryManifest, previewDiscoveryImport, publicDiscoveryManifest, readDiscoveryManifest, redactSourceLocator, sha256, parseTimelineGap, writeDiscoveryManifest, buildSessionExportPlan, reverifySessionExportPlan, buildSessionAiwgFortemiIndexExport, recoverAiwgFortemiIndexFromFullV1Shard, embedAttachmentsInFullV1Shard, recoverEmbeddedAttachments, SESSION_EXPORT_PLAN_SCHEMA_VERSION, } from '../../sessions/index.js';
|
|
6
|
+
import { CLAUDE_ADAPTER_VERSION, ClaudeSessionAdapter, CODEX_ADAPTER_VERSION, CodexSessionAdapter, COPILOT_ADAPTER_VERSION, CopilotSessionAdapter, CURSOR_ADAPTER_VERSION, CursorSessionAdapter, FACTORY_ADAPTER_VERSION, FactorySessionAdapter, HERMES_ADAPTER_VERSION, HermesSessionAdapter, OPENCODE_ADAPTER_VERSION, OpenCodeSessionAdapter, OPENCLAW_ADAPTER_VERSION, OpenClawSessionAdapter, OPENHUMAN_ADAPTER_VERSION, OpenHumanSessionAdapter, GROKBOT_ADAPTER_VERSION, GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS, GrokbotSessionAdapter, GROK_BUILD_ADAPTER_VERSION, GROK_BUILD_CLI_EXPORT_LOCATOR_CLASS, GrokBuildSessionAdapter, grokBuildList, grokBuildSearch, grokBuildExport, grokHeadlessSessionIdFromFile, MUSE_ADAPTER_VERSION, MuseSessionAdapter, PI_ADAPTER_VERSION, PiSessionAdapter, DEEPSEEK_HARNESS_ADAPTER_VERSION, DeepSeekHarnessSessionAdapter, OmpSessionAdapter, OMP_ADAPTER_VERSION, WARP_ADAPTER_VERSION, WarpSessionAdapter, DEVIN_DESKTOP_ADAPTER_VERSION, DevinDesktopSessionAdapter, CandidateExtractionService, GENERIC_ADAPTER_VERSION, GenericSessionInterchangeAdapter, IncrementalSessionImporter, ImportLeaseContentionError, FilesystemMemoryDestination, FilesystemPromotionDispositionCoordinator, MemoryPromotionGateway, SESSION_CONTRACT_VERSION, SessionContractError, SessionRepository, SessionSourceSchema, StructuralCandidateExtractor, resolveMemoryConsumerManifest, assertSessionProviderId, acquireImportLease, countUniqueSessionsAcrossCatalogs, defaultDiscoveryManifestPath, defaultHostCatalogPath, HOST_CATALOG_WORKSPACE_ID, indexIdentitiesBySessionId, manifestNeedsHostCatalog, mergeCrossCatalogRows, mergeSessionLists, resolveHostReferences, summarizeSessionAnalyticsFacts, discoverWorkspaceHistories, createSessionAdapterRegistry, coveragePreflight, expectedSessionProviders, deriveSessionTimeline, importDiscoveryManifest, previewDiscoveryImport, publicDiscoveryManifest, readDiscoveryManifest, redactSourceLocator, sha256, parseTimelineGap, writeDiscoveryManifest, buildSessionExportPlan, reverifySessionExportPlan, buildSessionAiwgFortemiIndexExport, recoverAiwgFortemiIndexFromFullV1Shard, embedAttachmentsInFullV1Shard, recoverEmbeddedAttachments, SESSION_EXPORT_PLAN_SCHEMA_VERSION, } from '../../sessions/index.js';
|
|
7
7
|
import { resolveImportExclusions } from '../../sessions/import-exclusions.js';
|
|
8
8
|
import { resolveImportLimits } from '../../sessions/import-limits.js';
|
|
9
9
|
import { classifyGrokbotBlobName } from '../../sessions/adapters/grokbot-locator.js';
|
|
@@ -227,18 +227,35 @@ async function executeCommand(ctx, args) {
|
|
|
227
227
|
limit,
|
|
228
228
|
cursor,
|
|
229
229
|
});
|
|
230
|
+
// Account-scoped sessions live once in the host catalog; the
|
|
231
|
+
// workspace holds references (#3232). Read through them on the
|
|
232
|
+
// opening page so the workspace lists its referenced sessions.
|
|
233
|
+
// Cursor pages continue the local snapshot. Totals dedupe legacy
|
|
234
|
+
// copied rows against references, counting each session once.
|
|
235
|
+
const hostView = cursor
|
|
236
|
+
? null
|
|
237
|
+
: readHostReferencedSessions(repository, { provider, tag: args.values.get('--tag') });
|
|
238
|
+
const items = hostView && hostView.sessions.length > 0
|
|
239
|
+
? mergeSessionLists(result.items, hostView.sessions).slice(0, limit)
|
|
240
|
+
: result.items;
|
|
241
|
+
const total = hostView && hostView.references.length > 0
|
|
242
|
+
? countUniqueSessionsAcrossCatalogs([{
|
|
243
|
+
identities: repository.listSessionIdentities(workspaceId),
|
|
244
|
+
references: hostView.resolvedReferences,
|
|
245
|
+
}])
|
|
246
|
+
: result.total;
|
|
230
247
|
const coverage = {
|
|
231
248
|
...repository.getCoverage(workspaceId),
|
|
232
249
|
catalogScope: catalogScope(ctx, args, repository, workspaceId),
|
|
233
250
|
};
|
|
234
251
|
const response = {
|
|
235
|
-
items
|
|
252
|
+
items,
|
|
236
253
|
page: {
|
|
237
254
|
limit,
|
|
238
255
|
cursor: cursor ?? null,
|
|
239
256
|
nextCursor: result.nextCursor,
|
|
240
257
|
snapshotRowid: result.snapshotRowid,
|
|
241
|
-
total
|
|
258
|
+
total,
|
|
242
259
|
},
|
|
243
260
|
coverage,
|
|
244
261
|
};
|
|
@@ -314,10 +331,15 @@ async function executeCommand(ctx, args) {
|
|
|
314
331
|
const session = matches[0];
|
|
315
332
|
if (!session)
|
|
316
333
|
throw new CliError('SESSION_NOT_FOUND', `session not found: ${id}${scope.hint ? `; ${scope.hint}` : ''}`, EXIT.unavailable, { catalogScope: scope });
|
|
334
|
+
// Image references resolve against the blob store: available blobs
|
|
335
|
+
// report their reference, missing ones an explicit unavailable
|
|
336
|
+
// state. Bytes stay out of the response; fetch by digest (#3265).
|
|
337
|
+
const events = repository.listEvents(session.sessionId, session.workspaceId)
|
|
338
|
+
.map((event) => ({ ...event, images: repository.resolveEventImages(event) }));
|
|
317
339
|
return ok(command, {
|
|
318
340
|
session,
|
|
319
341
|
tags: repository.listTags(session.sessionId, session.workspaceId),
|
|
320
|
-
events
|
|
342
|
+
events,
|
|
321
343
|
catalogScope: catalogScope(ctx, args, repository, session.workspaceId),
|
|
322
344
|
});
|
|
323
345
|
}
|
|
@@ -326,7 +348,8 @@ async function executeCommand(ctx, args) {
|
|
|
326
348
|
const { workspaceId } = readAuthorizationContext(ctx, args, command, repository);
|
|
327
349
|
const providerInput = args.values.get('--provider');
|
|
328
350
|
const provider = providerInput ? assertSessionProviderId(providerInput) : undefined;
|
|
329
|
-
const
|
|
351
|
+
const limit = boundedInteger(args.values.get('--limit'), 50, 1, 500, '--limit');
|
|
352
|
+
const searchOptions = {
|
|
330
353
|
query,
|
|
331
354
|
workspaceId,
|
|
332
355
|
providers: provider ? [provider] : undefined,
|
|
@@ -341,13 +364,24 @@ async function executeCommand(ctx, args) {
|
|
|
341
364
|
sensitivity: args.values.get('--sensitivity'),
|
|
342
365
|
extractionState: args.values.get('--extraction-state'),
|
|
343
366
|
controlEvents: controlEventMode(args.values.get('--control-events')),
|
|
344
|
-
limit
|
|
367
|
+
limit,
|
|
345
368
|
cursor: args.values.get('--cursor'),
|
|
346
|
-
}
|
|
369
|
+
};
|
|
370
|
+
const result = repository.search(searchOptions);
|
|
371
|
+
// Read through host references on the opening page so workspace
|
|
372
|
+
// search finds referenced account-scoped sessions. Each session
|
|
373
|
+
// counts once: host hits for sessions already present locally
|
|
374
|
+
// (legacy copied rows) are dropped by provider + native session.
|
|
375
|
+
const hostRead = searchOptions.cursor
|
|
376
|
+
? null
|
|
377
|
+
: searchHostReferencedSessions(repository, searchOptions, provider);
|
|
378
|
+
const items = hostRead && hostRead.hits.length > 0
|
|
379
|
+
? mergeCrossCatalogRows(result.items, hostRead.hits, indexIdentitiesBySessionId(repository.listSessionIdentities(workspaceId)), indexIdentitiesBySessionId(hostRead.hostIdentities), (hit) => [hit.provider, hit.eventId].join(' ')).slice(0, limit)
|
|
380
|
+
: result.items;
|
|
347
381
|
return ok(command, {
|
|
348
|
-
items
|
|
382
|
+
items,
|
|
349
383
|
catalogScope: catalogScope(ctx, args, repository, workspaceId),
|
|
350
|
-
page: { limit
|
|
384
|
+
page: { limit,
|
|
351
385
|
nextCursor: result.nextCursor },
|
|
352
386
|
});
|
|
353
387
|
}
|
|
@@ -355,14 +389,22 @@ async function executeCommand(ctx, args) {
|
|
|
355
389
|
const view = requiredPositional(args, 0, 'analytics view');
|
|
356
390
|
const { workspaceId } = readAuthorizationContext(ctx, args, command, repository);
|
|
357
391
|
const query = analyticsQuery(args, workspaceId);
|
|
392
|
+
// Host references resolve to facts stored under the host catalog;
|
|
393
|
+
// each session counts once by provider + native session id. Without
|
|
394
|
+
// references the single-catalog path below is unchanged.
|
|
395
|
+
const mergedFacts = readWorkspaceAnalyticsFacts(repository, query);
|
|
358
396
|
if (view === 'summary') {
|
|
359
397
|
return ok(command, {
|
|
360
398
|
view,
|
|
361
|
-
summary:
|
|
399
|
+
summary: mergedFacts
|
|
400
|
+
? summarizeSessionAnalyticsFacts(mergedFacts, workspaceId)
|
|
401
|
+
: repository.analyticsSummary(query),
|
|
362
402
|
});
|
|
363
403
|
}
|
|
364
404
|
const categories = analyticsCategories(view);
|
|
365
|
-
const items =
|
|
405
|
+
const items = mergedFacts
|
|
406
|
+
? mergedFacts.filter((fact) => categories.includes(fact.category))
|
|
407
|
+
: repository.listAnalyticsFacts({ ...query, categories });
|
|
366
408
|
return ok(command, {
|
|
367
409
|
analyticsVersion: '1.0.0',
|
|
368
410
|
view,
|
|
@@ -1075,7 +1117,10 @@ async function exportBuild(ctx, args, repository, command) {
|
|
|
1075
1117
|
...output,
|
|
1076
1118
|
bytesEmbedded: includeBytes && outputBytesByRegistrationId.has(output.registrationId),
|
|
1077
1119
|
}));
|
|
1078
|
-
const index = buildSessionAiwgFortemiIndexExport(plan.workspaceId, sessions, eventsBySessionId, outputs, catalogTagsBySessionId
|
|
1120
|
+
const index = buildSessionAiwgFortemiIndexExport(plan.workspaceId, sessions, eventsBySessionId, outputs, catalogTagsBySessionId,
|
|
1121
|
+
// Resolve image references against the live catalog: available blobs
|
|
1122
|
+
// export as references, missing ones as explicit unavailable (#3265).
|
|
1123
|
+
(event) => repository.resolveEventImages(event));
|
|
1079
1124
|
// aiwgFortemiIndexToKnowledgeShardWithReport targets the declared
|
|
1080
1125
|
// full-v1/2.0.0 archive contract and validates losslessness -- unlike the
|
|
1081
1126
|
// plain aiwgFortemiIndexToKnowledgeShard (core-v1), which silently embeds
|
|
@@ -1355,18 +1400,33 @@ async function importDiscovered(ctx, args) {
|
|
|
1355
1400
|
...(carryPath ? { carryForward: redactSourceLocator(carryPath) } : {}),
|
|
1356
1401
|
});
|
|
1357
1402
|
}
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1360
|
-
|
|
1403
|
+
const waitMs = boundedInteger(args.values.get('--lock-wait-ms'), 5_000, 0, 300_000, '--lock-wait-ms');
|
|
1404
|
+
const lease = await acquireImportLease(databasePath(ctx, args), sha256(['discovered-import', manifest.manifestId, manifest.workspaceId].join('\0')), { waitMs });
|
|
1405
|
+
let hostLease;
|
|
1361
1406
|
try {
|
|
1362
1407
|
const previous = carryPath ? new SessionRepository(carryPath, { readonly: true }) : undefined;
|
|
1363
1408
|
let repository;
|
|
1409
|
+
let hostRepository;
|
|
1364
1410
|
try {
|
|
1365
1411
|
repository = openRepository(ctx, args);
|
|
1412
|
+
// Account-scoped providers (Grok Bot) import once into the host
|
|
1413
|
+
// catalog; the workspace catalog records a reference (#3232). The
|
|
1414
|
+
// host catalog is only opened when the manifest actually holds an
|
|
1415
|
+
// account-scoped source.
|
|
1416
|
+
const hostCatalogPath = defaultHostCatalogPath();
|
|
1417
|
+
if (manifestNeedsHostCatalog(manifest.sources)) {
|
|
1418
|
+
mkdirSync(dirname(hostCatalogPath), { recursive: true, mode: 0o700 });
|
|
1419
|
+
// The workspace lease does not cover the shared host catalog; serialize
|
|
1420
|
+
// host writers the same way the hourly refresh does.
|
|
1421
|
+
hostLease = await acquireImportLease(hostCatalogPath, `host-import-${process.pid}`, { waitMs });
|
|
1422
|
+
hostRepository = new SessionRepository(hostCatalogPath);
|
|
1423
|
+
}
|
|
1366
1424
|
const interruptedRuns = repository.interruptRunningBatchImports();
|
|
1367
1425
|
const receipt = await importDiscoveryManifest({
|
|
1368
1426
|
manifest,
|
|
1369
1427
|
repository,
|
|
1428
|
+
hostRepository,
|
|
1429
|
+
hostCatalogPath,
|
|
1370
1430
|
carryForward: previous,
|
|
1371
1431
|
limits,
|
|
1372
1432
|
exclude,
|
|
@@ -1388,10 +1448,12 @@ async function importDiscovered(ctx, args) {
|
|
|
1388
1448
|
}
|
|
1389
1449
|
finally {
|
|
1390
1450
|
repository?.close();
|
|
1451
|
+
hostRepository?.close();
|
|
1391
1452
|
previous?.close();
|
|
1392
1453
|
}
|
|
1393
1454
|
}
|
|
1394
1455
|
finally {
|
|
1456
|
+
await hostLease?.release();
|
|
1395
1457
|
await lease.release();
|
|
1396
1458
|
}
|
|
1397
1459
|
}
|
|
@@ -1718,6 +1780,127 @@ function catalogScope(ctx, args, repository, workspaceId) {
|
|
|
1718
1780
|
: null,
|
|
1719
1781
|
};
|
|
1720
1782
|
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Host-catalog read-through for account-scoped sessions (#3232). The
|
|
1785
|
+
* workspace catalog holds references instead of copies; each reference
|
|
1786
|
+
* records its host catalog path. Every referenced catalog opens read-only
|
|
1787
|
+
* and closes before returning. Unreadable catalogs contribute nothing, so
|
|
1788
|
+
* local rows still list when the host catalog is missing.
|
|
1789
|
+
*/
|
|
1790
|
+
function eachReferencedHostCatalog(repository, provider, read) {
|
|
1791
|
+
const references = repository.listHostSessionReferences()
|
|
1792
|
+
.filter((reference) => !provider || reference.provider === provider);
|
|
1793
|
+
if (references.length === 0)
|
|
1794
|
+
return [];
|
|
1795
|
+
const byCatalog = new Map();
|
|
1796
|
+
for (const reference of references) {
|
|
1797
|
+
const group = byCatalog.get(reference.hostCatalog);
|
|
1798
|
+
if (group)
|
|
1799
|
+
group.push(reference);
|
|
1800
|
+
else
|
|
1801
|
+
byCatalog.set(reference.hostCatalog, [reference]);
|
|
1802
|
+
}
|
|
1803
|
+
const reads = [];
|
|
1804
|
+
for (const [catalogPath, group] of byCatalog) {
|
|
1805
|
+
let host;
|
|
1806
|
+
try {
|
|
1807
|
+
host = new SessionRepository(catalogPath, { readonly: true });
|
|
1808
|
+
}
|
|
1809
|
+
catch {
|
|
1810
|
+
continue;
|
|
1811
|
+
}
|
|
1812
|
+
try {
|
|
1813
|
+
reads.push({ references: group, value: read(host, group) });
|
|
1814
|
+
}
|
|
1815
|
+
finally {
|
|
1816
|
+
host.close();
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
return reads;
|
|
1820
|
+
}
|
|
1821
|
+
function readHostReferencedSessions(repository, filters) {
|
|
1822
|
+
const reads = eachReferencedHostCatalog(repository, filters.provider, (host, group) => {
|
|
1823
|
+
const page = host.listSessions({
|
|
1824
|
+
provider: filters.provider,
|
|
1825
|
+
workspaceId: HOST_CATALOG_WORKSPACE_ID,
|
|
1826
|
+
limit: group.length,
|
|
1827
|
+
});
|
|
1828
|
+
const sessions = resolveHostReferences(group, page.items)
|
|
1829
|
+
.filter((session) => !filters.tag || host.listTags(session.sessionId).includes(filters.tag));
|
|
1830
|
+
const resolvedSourceIds = new Set(sessions.map((session) => session.sourceId));
|
|
1831
|
+
return {
|
|
1832
|
+
sessions,
|
|
1833
|
+
resolvedReferences: group.filter((reference) => resolvedSourceIds.has(reference.sourceId)),
|
|
1834
|
+
};
|
|
1835
|
+
});
|
|
1836
|
+
return {
|
|
1837
|
+
references: reads.flatMap((read) => read.references),
|
|
1838
|
+
resolvedReferences: reads.flatMap((read) => read.value.resolvedReferences),
|
|
1839
|
+
sessions: reads.flatMap((read) => read.value.sessions),
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
function searchHostReferencedSessions(repository, searchOptions, provider) {
|
|
1843
|
+
const reads = eachReferencedHostCatalog(repository, provider, (host) => {
|
|
1844
|
+
const result = host.search({
|
|
1845
|
+
...searchOptions,
|
|
1846
|
+
workspaceId: HOST_CATALOG_WORKSPACE_ID,
|
|
1847
|
+
cursor: undefined,
|
|
1848
|
+
});
|
|
1849
|
+
return {
|
|
1850
|
+
hits: result.items,
|
|
1851
|
+
hostIdentities: host.listSessionIdentities(HOST_CATALOG_WORKSPACE_ID),
|
|
1852
|
+
};
|
|
1853
|
+
});
|
|
1854
|
+
return {
|
|
1855
|
+
hits: reads.flatMap((read) => read.value.hits),
|
|
1856
|
+
hostIdentities: reads.flatMap((read) => read.value.hostIdentities),
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1859
|
+
function readHostReferencedAnalyticsFacts(repository, query) {
|
|
1860
|
+
// query.sessionId is a workspace-local internal id; host rows carry host
|
|
1861
|
+
// stable ids, so resolve it to a provider + native session key first.
|
|
1862
|
+
let sessionKey = null;
|
|
1863
|
+
if (query.sessionId) {
|
|
1864
|
+
const session = repository.getSession(query.sessionId, query.workspaceId);
|
|
1865
|
+
if (!session)
|
|
1866
|
+
return { facts: [], hostIdentities: [] };
|
|
1867
|
+
sessionKey = `${session.provider} ${session.nativeSessionId}`;
|
|
1868
|
+
}
|
|
1869
|
+
const reads = eachReferencedHostCatalog(repository, query.provider, (host, group) => {
|
|
1870
|
+
const wanted = new Set(group.map((reference) => `${reference.provider} ${reference.nativeSessionId}`));
|
|
1871
|
+
const identities = host.listSessionIdentities(HOST_CATALOG_WORKSPACE_ID);
|
|
1872
|
+
const hostSessionIds = new Set(identities
|
|
1873
|
+
.filter((identity) => wanted.has(`${identity.provider} ${identity.nativeSessionId}`))
|
|
1874
|
+
.map((identity) => identity.sessionId));
|
|
1875
|
+
const { sessionId: _localSessionId, ...hostQuery } = query;
|
|
1876
|
+
const facts = host.listAnalyticsFacts({ ...hostQuery, workspaceId: HOST_CATALOG_WORKSPACE_ID })
|
|
1877
|
+
.filter((fact) => hostSessionIds.has(fact.sessionId)
|
|
1878
|
+
&& (!sessionKey || `${fact.provider} ${hostSessionKey(fact.sessionId, identities)}` === sessionKey));
|
|
1879
|
+
return { facts, identities };
|
|
1880
|
+
});
|
|
1881
|
+
return {
|
|
1882
|
+
facts: reads.flatMap((read) => read.value.facts),
|
|
1883
|
+
hostIdentities: reads.flatMap((read) => read.value.identities),
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
function hostSessionKey(sessionId, identities) {
|
|
1887
|
+
return identities.find((identity) => identity.sessionId === sessionId)?.nativeSessionId ?? null;
|
|
1888
|
+
}
|
|
1889
|
+
/**
|
|
1890
|
+
* Workspace analytics facts with host references resolved. Returns null
|
|
1891
|
+
* when the workspace holds no references so callers keep the exact
|
|
1892
|
+
* single-catalog query path (SQL limit/filter semantics unchanged).
|
|
1893
|
+
*/
|
|
1894
|
+
function readWorkspaceAnalyticsFacts(repository, query) {
|
|
1895
|
+
const references = repository.listHostSessionReferences()
|
|
1896
|
+
.filter((reference) => !query.provider || reference.provider === query.provider);
|
|
1897
|
+
if (references.length === 0)
|
|
1898
|
+
return null;
|
|
1899
|
+
const hostRead = readHostReferencedAnalyticsFacts(repository, query);
|
|
1900
|
+
if (hostRead.facts.length === 0)
|
|
1901
|
+
return null;
|
|
1902
|
+
return mergeCrossCatalogRows(repository.listAnalyticsFacts(query), hostRead.facts, indexIdentitiesBySessionId(repository.listSessionIdentities(query.workspaceId)), indexIdentitiesBySessionId(hostRead.hostIdentities), (fact) => `${fact.provider} ${fact.factId}`);
|
|
1903
|
+
}
|
|
1721
1904
|
async function configuredImportLimits(ctx, args, workspace) {
|
|
1722
1905
|
const selectedWorkspace = workspace ?? (args.values.has('--workspace')
|
|
1723
1906
|
? resolve(ctx.cwd, args.values.get('--workspace')) : ctx.cwd);
|
|
@@ -29,7 +29,7 @@ import { loadCliCommandsContribution, registerCliCommands, registerHooks, } from
|
|
|
29
29
|
import { translateSkillsToCommands, providerNeedsCommands } from '../../plugin/skill-command-translator.js';
|
|
30
30
|
import * as ui from '../ui.js';
|
|
31
31
|
import { readAiwgConfig, writeAiwgConfig, updateInstalled, hashManifest, emptyConfig, getProjectDir, getConfigPath } from '../../config/aiwg-config.js';
|
|
32
|
-
import { appendGitignore } from '../../config/gitignore.js';
|
|
32
|
+
import { AIWG_RUNTIME_PATTERNS, appendGitignore } from '../../config/gitignore.js';
|
|
33
33
|
import { getLogger } from '../log.js';
|
|
34
34
|
import { installCockpit } from './cockpit.js';
|
|
35
35
|
import { initHandler } from './init.js';
|
|
@@ -501,11 +501,19 @@ function getProviderKernelSkillsPath(provider) {
|
|
|
501
501
|
const PROVIDER_GENERATED_GITIGNORE_PATTERNS = {
|
|
502
502
|
codex: ['.codex/', '.agents/'],
|
|
503
503
|
};
|
|
504
|
-
|
|
504
|
+
/**
|
|
505
|
+
* Patterns `aiwg use` ensures in the project's .gitignore on every deploy:
|
|
506
|
+
* the AIWG runtime subdirs doctor expects, plus any provider-generated dirs.
|
|
507
|
+
* Append-only via appendGitignore — operator content is never rewritten (#3635).
|
|
508
|
+
*/
|
|
509
|
+
export function gitignorePatternsForDeploy(provider) {
|
|
510
|
+
return [...AIWG_RUNTIME_PATTERNS, ...(PROVIDER_GENERATED_GITIGNORE_PATTERNS[provider] ?? [])];
|
|
511
|
+
}
|
|
512
|
+
export async function ensureProviderGeneratedDirsIgnored(projectRoot, provider, opts) {
|
|
505
513
|
if (opts.dryRun)
|
|
506
514
|
return;
|
|
507
|
-
const patterns =
|
|
508
|
-
if (
|
|
515
|
+
const patterns = gitignorePatternsForDeploy(provider);
|
|
516
|
+
if (patterns.length === 0)
|
|
509
517
|
return;
|
|
510
518
|
try {
|
|
511
519
|
const result = await appendGitignore(projectRoot, patterns);
|