@aiwg/cli 2026.10.1 → 2026.10.4

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.
Files changed (361) hide show
  1. package/README.md +2 -2
  2. package/agentic/code/providers/capability-matrix.yaml +270 -0
  3. package/agentic/code/providers/model-capabilities.v1.json +3183 -24
  4. package/bin/aiwg.mjs +135 -47
  5. package/dist/src/a2a/codecs.js +9 -0
  6. package/dist/src/agents/grounding/knowledge-base.js +54 -6
  7. package/dist/src/artifacts/browser-export.js +6 -0
  8. package/dist/src/artifacts/checksum-manifest.js +1 -0
  9. package/dist/src/artifacts/citation-parser.js +173 -92
  10. package/dist/src/artifacts/citation-table-schema.js +59 -0
  11. package/dist/src/artifacts/cli.js +57 -18
  12. package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
  13. package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
  14. package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
  15. package/dist/src/artifacts/corpus-views/renderers.js +3 -3
  16. package/dist/src/artifacts/discovery-eval.js +6 -4
  17. package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
  18. package/dist/src/artifacts/fortemi-core-sync.js +166 -40
  19. package/dist/src/artifacts/framework-capabilities.js +171 -0
  20. package/dist/src/artifacts/framework-index-paths.js +73 -0
  21. package/dist/src/artifacts/framework-source-digest.js +75 -0
  22. package/dist/src/artifacts/index-builder.js +285 -131
  23. package/dist/src/artifacts/index-files.js +132 -18
  24. package/dist/src/artifacts/index-preparation.js +65 -0
  25. package/dist/src/artifacts/index-refresh.js +576 -0
  26. package/dist/src/artifacts/index-worker.mjs +9 -0
  27. package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
  28. package/dist/src/artifacts/prebuilt-deployment.js +46 -0
  29. package/dist/src/artifacts/prebuilt-relations.js +80 -0
  30. package/dist/src/artifacts/query-engine.js +410 -88
  31. package/dist/src/artifacts/relations-builder.js +168 -0
  32. package/dist/src/artifacts/relations.js +148 -0
  33. package/dist/src/artifacts/repair.js +9 -4
  34. package/dist/src/artifacts/stats.js +5 -2
  35. package/dist/src/artifacts/types.js +30 -10
  36. package/dist/src/artifacts/watcher.js +1 -1
  37. package/dist/src/auth/credential-store.js +2 -1
  38. package/dist/src/catalog/cli.d.mts +5 -0
  39. package/dist/src/channel/manager.d.mts +20 -0
  40. package/dist/src/channel/manager.mjs +78 -12
  41. package/dist/src/cli/child-process-result.js +40 -0
  42. package/dist/src/cli/command-log.js +2 -3
  43. package/dist/src/cli/env.js +38 -16
  44. package/dist/src/cli/flag-parsing.js +236 -0
  45. package/dist/src/cli/handlers/artifacts.js +3 -0
  46. package/dist/src/cli/handlers/auth.js +3 -0
  47. package/dist/src/cli/handlers/decision.js +218 -5
  48. package/dist/src/cli/handlers/diagnose.js +13 -5
  49. package/dist/src/cli/handlers/effect.js +4 -2
  50. package/dist/src/cli/handlers/evidence.js +3 -0
  51. package/dist/src/cli/handlers/feedback.js +14 -5
  52. package/dist/src/cli/handlers/help.js +1 -0
  53. package/dist/src/cli/handlers/index.js +3 -1
  54. package/dist/src/cli/handlers/init.js +248 -30
  55. package/dist/src/cli/handlers/lint.js +5 -0
  56. package/dist/src/cli/handlers/mc.js +23 -0
  57. package/dist/src/cli/handlers/models.js +169 -10
  58. package/dist/src/cli/handlers/ralph-launcher.js +2 -0
  59. package/dist/src/cli/handlers/ralph.js +3 -0
  60. package/dist/src/cli/handlers/refresh.js +28 -0
  61. package/dist/src/cli/handlers/regenerate.js +14 -0
  62. package/dist/src/cli/handlers/resource-versions.js +3 -0
  63. package/dist/src/cli/handlers/rules.js +195 -0
  64. package/dist/src/cli/handlers/run.js +4 -0
  65. package/dist/src/cli/handlers/runtime-info.js +25 -11
  66. package/dist/src/cli/handlers/script-runner.js +19 -8
  67. package/dist/src/cli/handlers/session.js +406 -62
  68. package/dist/src/cli/handlers/sessions.js +243 -76
  69. package/dist/src/cli/handlers/setup-manifest.js +474 -79
  70. package/dist/src/cli/handlers/setup.js +180 -39
  71. package/dist/src/cli/handlers/steward.js +11 -0
  72. package/dist/src/cli/handlers/subcommands.js +60 -3
  73. package/dist/src/cli/handlers/team.js +18 -8
  74. package/dist/src/cli/handlers/uhp.js +3 -0
  75. package/dist/src/cli/handlers/use.js +307 -55
  76. package/dist/src/cli/handlers/utilities.js +125 -26
  77. package/dist/src/cli/handlers/version.js +8 -0
  78. package/dist/src/cli/prompt-utils.js +72 -0
  79. package/dist/src/cli/provider-resolution.js +11 -0
  80. package/dist/src/cli/router.js +15 -1
  81. package/dist/src/cli/services/deployment-verification.js +19 -9
  82. package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
  83. package/dist/src/cli/skill-usage.js +2 -3
  84. package/dist/src/config/aiwg-config.js +349 -35
  85. package/dist/src/config/cli.js +256 -23
  86. package/dist/src/config/decision-config.js +106 -0
  87. package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
  88. package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -0
  89. package/dist/src/config/gitignore.js +50 -0
  90. package/dist/src/config/index-graph-overrides.js +36 -0
  91. package/dist/src/config/project-artifacts-health.d.mts +37 -0
  92. package/dist/src/config/project-artifacts-health.mjs +14 -3
  93. package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
  94. package/dist/src/config/user-config-dir.d.mts +9 -0
  95. package/dist/src/config/user-config.js +38 -11
  96. package/dist/src/config/user-registry.js +23 -15
  97. package/dist/src/config/user-state.js +7 -0
  98. package/dist/src/decision/adapters/jev.js +75 -27
  99. package/dist/src/decision/ask.js +203 -43
  100. package/dist/src/decision/context-live-qualification.js +2 -2
  101. package/dist/src/decision/driver.js +14 -7
  102. package/dist/src/decision/ensemble/aggregate.js +23 -10
  103. package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
  104. package/dist/src/decision/entry.js +25 -6
  105. package/dist/src/decision/graph-live-qualification.js +1 -1
  106. package/dist/src/decision/graph-run.js +9 -0
  107. package/dist/src/decision/heldout/collector.js +15 -14
  108. package/dist/src/decision/heldout/contract.js +30 -7
  109. package/dist/src/decision/index.js +1 -0
  110. package/dist/src/decision/interop.js +60 -8
  111. package/dist/src/decision/jev-credentials.js +15 -1
  112. package/dist/src/decision/ledger.js +942 -0
  113. package/dist/src/decision/offload-activation.js +137 -0
  114. package/dist/src/decision/offload.js +550 -0
  115. package/dist/src/decision/qualification/load.js +4 -6
  116. package/dist/src/decision/savings.js +28 -0
  117. package/dist/src/decision/validate.js +6 -3
  118. package/dist/src/effects/dispatch-verifier.js +252 -0
  119. package/dist/src/effects/index.js +1 -0
  120. package/dist/src/effects/types.js +5 -1
  121. package/dist/src/effects/verifiers/git.js +2 -1
  122. package/dist/src/effects/verifiers/tracker.js +26 -14
  123. package/dist/src/extensions/commands/definitions.js +19 -0
  124. package/dist/src/extensions/project-local-remove.js +36 -1
  125. package/dist/src/features/installer.js +2 -2
  126. package/dist/src/flow/graph-metadata.js +5 -0
  127. package/dist/src/gates/providers/loader.js +64 -18
  128. package/dist/src/installation/manager-command.d.mts +18 -0
  129. package/dist/src/installation/manager-command.mjs +15 -3
  130. package/dist/src/installation/manager.d.mts +49 -0
  131. package/dist/src/installation/manager.mjs +95 -5
  132. package/dist/src/issues/cli.js +4 -4
  133. package/dist/src/issues/local.js +24 -5
  134. package/dist/src/jobs/runner.js +1 -1
  135. package/dist/src/lint/cli.js +27 -1
  136. package/dist/src/lint/loader.js +2 -1
  137. package/dist/src/lint/reporters.js +25 -1
  138. package/dist/src/lint/rule-activation.js +43 -0
  139. package/dist/src/lint/runner.js +137 -62
  140. package/dist/src/mcp/adapters/codex-runtime.js +366 -56
  141. package/dist/src/mcp/claude-install.d.mts +4 -0
  142. package/dist/src/mcp/claude-install.mjs +41 -0
  143. package/dist/src/mcp/cli.d.mts +1 -0
  144. package/dist/src/mcp/cli.mjs +620 -85
  145. package/dist/src/mcp/config-file.d.mts +28 -0
  146. package/dist/src/mcp/config-file.mjs +279 -0
  147. package/dist/src/mcp/config-layers.d.mts +36 -0
  148. package/dist/src/mcp/config-layers.mjs +348 -0
  149. package/dist/src/mcp/credentials.d.mts +51 -0
  150. package/dist/src/mcp/credentials.mjs +484 -0
  151. package/dist/src/mcp/grok-build-config.d.mts +6 -0
  152. package/dist/src/mcp/grok-build-config.mjs +17 -27
  153. package/dist/src/mcp/helpers.mjs +109 -4
  154. package/dist/src/mcp/muse-native-config.d.mts +13 -0
  155. package/dist/src/mcp/muse-native-config.mjs +1 -0
  156. package/dist/src/mcp/omp-config.d.mts +4 -0
  157. package/dist/src/mcp/omp-config.mjs +50 -29
  158. package/dist/src/mcp/profiles.js +97 -23
  159. package/dist/src/mcp/profiles.mjs +99 -27
  160. package/dist/src/mcp/registry.js +248 -131
  161. package/dist/src/mcp/registry.mjs +169 -100
  162. package/dist/src/mcp/server-config.d.mts +3 -0
  163. package/dist/src/mcp/server-config.mjs +89 -0
  164. package/dist/src/mcp/server.mjs +127 -82
  165. package/dist/src/mcp/test-simple.mjs +2 -1
  166. package/dist/src/mcp/toml-editor.d.mts +4 -0
  167. package/dist/src/mcp/toml-string.d.mts +1 -0
  168. package/dist/src/mcp/toml-string.mjs +9 -0
  169. package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
  170. package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
  171. package/dist/src/mcp/tool-filters.d.mts +46 -0
  172. package/dist/src/mcp/tool-filters.mjs +357 -0
  173. package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
  174. package/dist/src/mcp/tools/decision.mjs +22 -3
  175. package/dist/src/mcp/tools/discovery.mjs +62 -55
  176. package/dist/src/mcp/tools/orchestration.mjs +50 -2
  177. package/dist/src/mcp/tools/subsystems.mjs +39 -8
  178. package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
  179. package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
  180. package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
  181. package/dist/src/memory/project-registry.js +2 -2
  182. package/dist/src/mission-protocol/codecs.js +647 -1
  183. package/dist/src/mission-protocol/types.js +110 -0
  184. package/dist/src/mission-protocol/worker-status.js +2 -0
  185. package/dist/src/models/config-loader.js +76 -14
  186. package/dist/src/models/grok-build-models.js +93 -41
  187. package/dist/src/models/model-capabilities.v1.json +3183 -24
  188. package/dist/src/models/model-discovery.js +931 -67
  189. package/dist/src/models/provider-policy.js +719 -11
  190. package/dist/src/models/qualification-digest.d.mts +2 -0
  191. package/dist/src/models/qualification-digest.mjs +17 -0
  192. package/dist/src/models/resolver.js +261 -0
  193. package/dist/src/models/worker-direct-readiness.js +550 -0
  194. package/dist/src/models/worker-dispatch-offer.js +169 -0
  195. package/dist/src/models/worker-health-readiness.js +144 -0
  196. package/dist/src/models/worker-installation.d.mts +39 -0
  197. package/dist/src/models/worker-installation.mjs +986 -0
  198. package/dist/src/models/wrapper-route.js +18 -0
  199. package/dist/src/ops/registry.js +9 -14
  200. package/dist/src/plugins/standalone-packager.js +4 -3
  201. package/dist/src/process/bounded-child-process.d.mts +84 -0
  202. package/dist/src/process/bounded-child-process.mjs +430 -0
  203. package/dist/src/process/cli-command.d.mts +16 -0
  204. package/dist/src/process/cli-command.mjs +75 -0
  205. package/dist/src/process/signal-child.d.mts +6 -0
  206. package/dist/src/process/signal-child.mjs +7 -0
  207. package/dist/src/providers/capability-matrix.js +8 -0
  208. package/dist/src/providers/capability-matrix.yaml +270 -0
  209. package/dist/src/providers/deployed-skill-roots.js +20 -0
  210. package/dist/src/providers/grok-build-acp.js +3 -2
  211. package/dist/src/providers/grok-build-headless.js +53 -23
  212. package/dist/src/providers/grok-build-inspect.js +1 -0
  213. package/dist/src/providers/omp-agent.d.mts +8 -0
  214. package/dist/src/providers/omp-diagnostics.d.mts +1 -0
  215. package/dist/src/providers/omp-paths.d.mts +13 -0
  216. package/dist/src/providers/provider-definitions.js +9 -1
  217. package/dist/src/providers/provider-definitions.mjs +9 -2
  218. package/dist/src/providers/skill-ownership.d.mts +9 -0
  219. package/dist/src/providers/skill-ownership.mjs +88 -0
  220. package/dist/src/rules/activation.d.mts +21 -0
  221. package/dist/src/rules/activation.mjs +62 -0
  222. package/dist/src/rules/inline-budget.d.mts +26 -0
  223. package/dist/src/rules/inline-budget.mjs +66 -0
  224. package/dist/src/rules/inventory.js +129 -0
  225. package/dist/src/rules/pin-state.js +73 -0
  226. package/dist/src/rules/pins.d.mts +14 -0
  227. package/dist/src/rules/pins.mjs +112 -0
  228. package/dist/src/rules/rule-frontmatter.schema.json +197 -0
  229. package/dist/src/serve/executor-registry.js +16 -24
  230. package/dist/src/serve/fleet-mission-conductor.js +9 -0
  231. package/dist/src/serve/mission-conductor.js +47 -12
  232. package/dist/src/serve/shared-host-scheduler.js +2 -0
  233. package/dist/src/serve/worker-invocation.js +558 -0
  234. package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
  235. package/dist/src/serve/worker-stdin-frame.mjs +107 -0
  236. package/dist/src/sessions/adapter-registry.js +49 -0
  237. package/dist/src/sessions/adapters/claude.js +39 -54
  238. package/dist/src/sessions/adapters/codex.js +82 -67
  239. package/dist/src/sessions/adapters/copilot.js +4 -4
  240. package/dist/src/sessions/adapters/cursor.js +40 -57
  241. package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
  242. package/dist/src/sessions/adapters/factory.js +31 -27
  243. package/dist/src/sessions/adapters/generic.js +43 -9
  244. package/dist/src/sessions/adapters/grok-build.js +11 -11
  245. package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
  246. package/dist/src/sessions/adapters/grokbot.js +434 -24
  247. package/dist/src/sessions/adapters/hermes.js +27 -29
  248. package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
  249. package/dist/src/sessions/adapters/muse.js +200 -104
  250. package/dist/src/sessions/adapters/omp.js +28 -14
  251. package/dist/src/sessions/adapters/openclaw.js +89 -79
  252. package/dist/src/sessions/adapters/opencode.js +27 -24
  253. package/dist/src/sessions/adapters/openhuman.js +18 -60
  254. package/dist/src/sessions/adapters/pi.js +30 -14
  255. package/dist/src/sessions/adapters/warp.js +3 -3
  256. package/dist/src/sessions/adapters/windsurf.js +19 -48
  257. package/dist/src/sessions/batch-contracts.js +25 -5
  258. package/dist/src/sessions/batch-import.js +72 -51
  259. package/dist/src/sessions/candidates.js +47 -11
  260. package/dist/src/sessions/contracts.js +75 -2
  261. package/dist/src/sessions/coverage-preflight.js +134 -0
  262. package/dist/src/sessions/discovery.js +3 -0
  263. package/dist/src/sessions/export-plan.js +4 -3
  264. package/dist/src/sessions/grok-build-cli.js +67 -5
  265. package/dist/src/sessions/import-exclusions.js +72 -0
  266. package/dist/src/sessions/import-lease.js +34 -18
  267. package/dist/src/sessions/import-limits.js +37 -0
  268. package/dist/src/sessions/importer.js +84 -46
  269. package/dist/src/sessions/index.js +2 -0
  270. package/dist/src/sessions/lifecycle.js +45 -0
  271. package/dist/src/sessions/policy.js +133 -25
  272. package/dist/src/sessions/readers.js +106 -53
  273. package/dist/src/sessions/refresh.js +106 -0
  274. package/dist/src/sessions/repository.js +199 -63
  275. package/dist/src/sessions/workspace-discovery.js +315 -88
  276. package/dist/src/sessions/workspace-matching.js +107 -0
  277. package/dist/src/skills/adapters/clawhub.js +10 -8
  278. package/dist/src/skills/adapters/openclaw.js +10 -7
  279. package/dist/src/skills/importer.js +1 -0
  280. package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
  281. package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
  282. package/dist/src/smiths/context-pipeline/finalization.js +6 -5
  283. package/dist/src/smiths/context-pipeline/generator.js +21 -4
  284. package/dist/src/smiths/context-pipeline/parallelism-section.js +195 -14
  285. package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
  286. package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
  287. package/dist/src/smiths/mcpsmith/example.js +1 -1
  288. package/dist/src/smiths/mcpsmith/generator.js +1 -1
  289. package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
  290. package/dist/src/smiths/toolsmith/runtime-discovery.mjs +85 -31
  291. package/dist/src/storage/backends/fs.js +18 -76
  292. package/dist/src/storage/backends/logseq.js +68 -7
  293. package/dist/src/storage/backends/obsidian.js +1 -0
  294. package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
  295. package/dist/src/testing/generators/test-code-generator.js +57 -30
  296. package/dist/src/tracker/forge-http.js +2 -1
  297. package/dist/src/uhp/client.js +11 -1
  298. package/dist/src/uhp/mission.js +5 -0
  299. package/dist/src/update/checker.d.mts +2 -0
  300. package/dist/src/update/checker.mjs +5 -5
  301. package/dist/src/update/notifier.mjs +54 -2
  302. package/dist/src/update/service.d.mts +22 -0
  303. package/dist/src/utils/contained-filesystem.d.mts +37 -0
  304. package/dist/src/utils/contained-filesystem.mjs +683 -0
  305. package/dist/src/utils/temporary-directory.js +36 -0
  306. package/dist/src/writing/example-generator.js +1 -1
  307. package/dist/src/writing/fidelity.js +18 -1
  308. package/package.json +32 -2
  309. package/schemas/mission-v1.schema.json +2429 -0
  310. package/schemas/models/model-catalog.v1.schema.json +301 -0
  311. package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
  312. package/schemas/models/model-policy.v1.schema.json +14 -0
  313. package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
  314. package/tools/_resolve-impl.mjs +39 -2
  315. package/tools/agents/deploy-agents.mjs +64 -23
  316. package/tools/agents/providers/base.mjs +153 -166
  317. package/tools/agents/providers/claude.mjs +8 -24
  318. package/tools/agents/providers/codex.mjs +18 -11
  319. package/tools/agents/providers/cursor.mjs +19 -18
  320. package/tools/agents/providers/grok-build.mjs +3 -1
  321. package/tools/agents/providers/grokbot.mjs +11 -12
  322. package/tools/agents/providers/hermes.mjs +62 -49
  323. package/tools/agents/providers/omp.mjs +5 -2
  324. package/tools/agents/providers/openclaw-translator.mjs +19 -5
  325. package/tools/agents/providers/openclaw.mjs +9 -4
  326. package/tools/agents/providers/pi.mjs +5 -0
  327. package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
  328. package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
  329. package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
  330. package/tools/agents/providers/rule-delivery.mjs +1270 -0
  331. package/tools/agents/providers/warp.mjs +20 -26
  332. package/tools/cli/decision-offload-report.mjs +40 -0
  333. package/tools/cli/workspace-status.mjs +862 -0
  334. package/tools/plugin/package-plugins.mjs +186 -8
  335. package/tools/plugin/plugin-links.mjs +114 -0
  336. package/tools/providers/antigravity-transport.mjs +3 -1
  337. package/tools/providers/deepseek-harness-transport.mjs +360 -0
  338. package/tools/providers/omp-transport.mjs +194 -0
  339. package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
  340. package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
  341. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
  342. package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
  343. package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
  344. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
  345. package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
  346. package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
  347. package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
  348. package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
  349. package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
  350. package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
  351. package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
  352. package/tools/ralph-external/lib/session-environment.mjs +28 -0
  353. package/tools/ralph-external/lib/systemd-client.mjs +49 -0
  354. package/tools/ralph-external/lib/worker-health.mjs +439 -0
  355. package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
  356. package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
  357. package/tools/ralph-external/process-monitor.mjs +1017 -0
  358. package/tools/ralph-external/session-launcher.mjs +5057 -0
  359. package/tools/scripts/resource-preflight.mjs +541 -0
  360. package/tools/skills/deploy-skills-codex.mjs +2 -1
  361. package/vscode-extension/schemas/aiwg.config.v1.json +2916 -0
@@ -1,11 +1,47 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { z } from 'zod';
3
+ import { redactSessionText, redactSessionValue } from './policy.js';
3
4
  export const SESSION_CONTRACT_VERSION = '1.0.0';
4
5
  export const SESSION_PROVIDER_IDS = [
5
6
  'claude', 'codex', 'copilot', 'cursor', 'factory', 'hermes',
6
7
  'opencode', 'openclaw', 'openhuman', 'grokbot', 'grok-build', 'pi', 'omp', 'deepseek-harness', 'warp', 'devin-desktop', 'muse', 'generic',
7
8
  ];
8
9
  export const SessionProviderIdSchema = z.enum(SESSION_PROVIDER_IDS);
10
+ // Expected scope must also represent providers unknown to this runtime.
11
+ export const ExpectedSessionProviderSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
12
+ export const SessionRuntimeIdentitySchema = z.object({
13
+ packageName: z.string(),
14
+ version: z.string(),
15
+ packageRoot: z.string(),
16
+ executable: z.string(),
17
+ nodeVersion: z.string(),
18
+ installationMethod: z.string(),
19
+ installationState: z.enum(['aligned', 'mismatch', 'stale', 'unrecorded', 'unknown']),
20
+ canonicalRoot: z.string().nullable(),
21
+ diagnostics: z.array(z.string()),
22
+ });
23
+ export const SessionCoveragePreflightSchema = z.object({
24
+ expectedProviders: z.array(ExpectedSessionProviderSchema).min(1),
25
+ expectedProviderBasis: z.enum(['explicit', 'declared-default', 'legacy']),
26
+ supportedProviders: z.array(ExpectedSessionProviderSchema),
27
+ runtime: SessionRuntimeIdentitySchema,
28
+ status: z.enum(['partial', 'complete']),
29
+ unresolvedProviders: z.array(ExpectedSessionProviderSchema),
30
+ ledger: z.array(z.object({
31
+ provider: ExpectedSessionProviderSchema,
32
+ disposition: z.enum([
33
+ 'missing-adapter', 'unsupported', 'authorization-required', 'export-required',
34
+ 'unavailable', 'no-sources', 'not-checked', 'pending-import', 'import-incomplete',
35
+ 'scope-incomplete', 'acquired',
36
+ ]),
37
+ adapterVersion: z.string().nullable(),
38
+ supportedOperations: z.array(z.string()),
39
+ acquisitionModes: z.array(z.string()),
40
+ sourceCount: z.number().int().nonnegative(),
41
+ boundaries: z.array(z.string()),
42
+ remediation: z.string().nullable(),
43
+ })),
44
+ });
9
45
  export const SESSION_PROVIDER_ALIASES = Object.freeze({
10
46
  windsurf: 'devin-desktop',
11
47
  dsh: 'deepseek-harness',
@@ -327,11 +363,48 @@ export function sha256(value) {
327
363
  function stableId(prefix, ...parts) {
328
364
  return `${prefix}_${createHash('sha256').update(parts.join('\0')).digest('hex')}`;
329
365
  }
366
+ export const SessionRejectionDetailSchema = z.union([
367
+ z.object({ limit: z.string(), configured: z.number(), observed: z.number(),
368
+ setting: z.string().optional(), origin: z.enum(['flag', 'env', 'config', 'default']).optional() }),
369
+ z.object({ issues: z.array(z.object({ path: z.string(), code: z.string() })) }),
370
+ ]);
371
+ export function schemaIssueDetail(path, code = 'custom') {
372
+ return { issues: [{ path, code }] };
373
+ }
374
+ export function assertSessionResourceLimit(limit, configured, observed) {
375
+ if (observed > configured) {
376
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'session resource limit exceeded', {
377
+ limit, configured, observed,
378
+ });
379
+ }
380
+ }
381
+ /** Extract schema locations and validator codes without messages or input values. */
382
+ export function schemaRejectionDetail(error) {
383
+ const issues = [];
384
+ const visit = (entries) => {
385
+ for (const issue of entries) {
386
+ if (issues.length >= 20)
387
+ return;
388
+ if (issue.code === 'invalid_union') {
389
+ for (const branch of issue.unionErrors)
390
+ visit(branch.issues);
391
+ }
392
+ else {
393
+ issues.push({ path: issue.path.join('.') || '<root>', code: issue.code });
394
+ }
395
+ }
396
+ };
397
+ visit(error.issues);
398
+ return redactSessionValue({ issues }).value;
399
+ }
330
400
  export class SessionContractError extends Error {
331
401
  code;
332
- constructor(code, message) {
333
- super(message);
402
+ detail;
403
+ constructor(code, message, detail) {
404
+ super(redactSessionText(message).text);
334
405
  this.code = code;
406
+ this.detail = detail;
407
+ this.detail = redactSessionValue(detail).value;
335
408
  this.name = 'SessionContractError';
336
409
  }
337
410
  }
@@ -0,0 +1,134 @@
1
+ import { readFileSync, realpathSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { findPackageRoot } from '../cli/find-package-root.js';
5
+ import { inspectInstallation } from '../installation/manager.mjs';
6
+ import { ExpectedSessionProviderSchema, SESSION_PROVIDER_ALIASES, SESSION_PROVIDER_IDS, SessionContractError, SessionCoveragePreflightSchema, SessionRuntimeIdentitySchema, } from './contracts.js';
7
+ import { createSessionAdapterRegistry } from './adapter-registry.js';
8
+ export function expectedSessionProviders(values) {
9
+ const providers = values.map((value) => {
10
+ const canonical = SESSION_PROVIDER_ALIASES[value.trim()]
11
+ ?? value.trim();
12
+ if (!ExpectedSessionProviderSchema.safeParse(canonical).success) {
13
+ throw new SessionContractError('INVALID_ARGUMENT', `invalid expected provider: ${value}`);
14
+ }
15
+ return canonical;
16
+ });
17
+ if (providers.length === 0) {
18
+ throw new SessionContractError('INVALID_ARGUMENT', 'expected providers must not be empty');
19
+ }
20
+ return [...new Set(providers)].sort();
21
+ }
22
+ /** Resolve the code actually loaded, independently of cwd, AIWG_ROOT and corpus redirects. */
23
+ export function sessionRuntimeIdentity() {
24
+ const packageRoot = findPackageRoot(dirname(fileURLToPath(import.meta.url)));
25
+ if (!packageRoot)
26
+ throw new SessionContractError('INVALID_ARGUMENT', 'cannot locate the running AIWG package');
27
+ const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
28
+ const executable = process.argv[1] ?? process.execPath;
29
+ const base = {
30
+ packageName: pkg.name, version: pkg.version, packageRoot: realpathSync(packageRoot),
31
+ executable, nodeVersion: process.version,
32
+ };
33
+ try {
34
+ const installation = inspectInstallation({ actualRoot: packageRoot, createIfMissing: false });
35
+ return SessionRuntimeIdentitySchema.parse({
36
+ ...base,
37
+ installationMethod: installation.actualMethod,
38
+ installationState: installation.state,
39
+ canonicalRoot: installation.identity?.root ?? null,
40
+ diagnostics: [
41
+ ...installation.drift,
42
+ ...(['mismatch', 'stale'].includes(installation.state)
43
+ ? ['Deliberately select a compatible runtime, inspect `aiwg installation show`, and rediscover. No automatic upgrade or installation switch is performed.'] : []),
44
+ ],
45
+ });
46
+ }
47
+ catch (error) {
48
+ return SessionRuntimeIdentitySchema.parse({
49
+ ...base, installationMethod: 'unknown', installationState: 'unknown', canonicalRoot: null,
50
+ diagnostics: [
51
+ error instanceof Error ? error.message : String(error),
52
+ 'Inspect `aiwg installation show` and deliberately select a compatible runtime before claiming complete coverage.',
53
+ ],
54
+ });
55
+ }
56
+ }
57
+ export function coveragePreflight(options = {}) {
58
+ const expectedProviders = expectedSessionProviders(options.expectedProviders ?? SESSION_PROVIDER_IDS);
59
+ const adapters = (options.registry ?? createSessionAdapterRegistry()).list();
60
+ const runtime = options.runtime ?? sessionRuntimeIdentity();
61
+ const ledger = expectedProviders.map((provider) => {
62
+ const adapter = adapters.find((item) => item.provider === provider);
63
+ const report = options.reports?.find((item) => item.provider === provider);
64
+ const entry = {
65
+ provider, disposition: 'not-checked', adapterVersion: adapter?.adapterVersion ?? null,
66
+ supportedOperations: [...(adapter?.supportedOperations ?? [])],
67
+ acquisitionModes: [...(adapter?.acquisitionModes ?? [])],
68
+ sourceCount: report?.sourceCount ?? 0, boundaries: [],
69
+ remediation: report?.remediation ?? 'Run authorized workspace discovery or select a supported export.',
70
+ };
71
+ if (!adapter) {
72
+ entry.disposition = 'missing-adapter';
73
+ entry.remediation = `Running ${runtime.packageName} ${runtime.version} at ${runtime.packageRoot} has no ${provider} adapter. Deliberately select a compatible runtime or use an explicitly authorized supported export; no installation is switched automatically.`;
74
+ }
75
+ else if (adapter.disposition === 'unsupported' || !adapter.supportedOperations.includes('stream')) {
76
+ entry.disposition = 'unsupported';
77
+ }
78
+ else if (report?.reasonCode === 'SHARED_ROOT_AUTHORIZATION_REQUIRED') {
79
+ entry.disposition = 'authorization-required';
80
+ }
81
+ else if (report?.status === 'export-required' || !adapter.supportedOperations.includes('discover')) {
82
+ entry.disposition = 'export-required';
83
+ }
84
+ else if (report?.status === 'unavailable') {
85
+ entry.disposition = 'unavailable';
86
+ }
87
+ else if (report?.reasonCode === 'MUSE_SOURCE_INSPECTION_INCOMPLETE') {
88
+ entry.disposition = report.sourceCount > 0 ? 'pending-import' : 'not-checked';
89
+ entry.boundaries.push('Some Muse sources could not be fully inspected; see museSourceInspections in the discovery manifest.');
90
+ entry.remediation = report.remediation;
91
+ }
92
+ else if (report?.status === 'checked') {
93
+ entry.disposition = report.sourceCount > 0 ? 'pending-import' : 'no-sources';
94
+ entry.remediation = report.sourceCount > 0
95
+ ? 'Import the exact authorized manifest and inspect source dispositions.'
96
+ : 'Zero matching sources does not establish no activity; verify scope, authorization and export availability.';
97
+ }
98
+ if (provider === 'muse') {
99
+ entry.boundaries.push('Native discovery includes parent session.jsonl logs only; nested subagent logs and approval-review scope are not established.');
100
+ }
101
+ return entry;
102
+ });
103
+ return SessionCoveragePreflightSchema.parse({
104
+ expectedProviders,
105
+ expectedProviderBasis: options.expectedProviderBasis ?? (options.expectedProviders ? 'explicit' : 'declared-default'),
106
+ supportedProviders: adapters.map((adapter) => adapter.provider), runtime,
107
+ status: 'partial', unresolvedProviders: expectedProviders, ledger,
108
+ });
109
+ }
110
+ export function reconcileCoveragePreflight(preflight, sources) {
111
+ const accepted = new Set(['committed', 'duplicate', 'previously-committed']);
112
+ const ledger = preflight.ledger.map((entry) => {
113
+ if (!['pending-import', 'import-incomplete', 'scope-incomplete', 'acquired'].includes(entry.disposition))
114
+ return entry;
115
+ const selected = sources.filter((source) => source.provider === entry.provider);
116
+ const imported = selected.length === entry.sourceCount && selected.length > 0
117
+ && selected.every((source) => source.status === 'excluded' || (accepted.has(source.status) && source.eventsAccepted > 0));
118
+ return {
119
+ ...entry,
120
+ disposition: !imported ? 'import-incomplete'
121
+ : entry.boundaries.length > 0 ? 'scope-incomplete' : 'acquired',
122
+ remediation: !imported ? 'Resolve pending, rejected, skipped or empty imports before claiming acquisition coverage.'
123
+ : entry.boundaries.length > 0 ? 'Declare the parent-only boundary and separately authorize supported exports for omitted scope.' : null,
124
+ };
125
+ });
126
+ const unresolvedProviders = ledger.filter((entry) => entry.disposition !== 'acquired').map((entry) => entry.provider);
127
+ const runtimeGap = ['mismatch', 'stale', 'unknown'].includes(preflight.runtime.installationState);
128
+ return {
129
+ ...preflight, ledger, unresolvedProviders,
130
+ status: unresolvedProviders.length > 0 || runtimeGap || preflight.expectedProviderBasis !== 'explicit'
131
+ ? 'partial' : 'complete',
132
+ };
133
+ }
134
+ //# sourceMappingURL=coverage-preflight.js.map
@@ -1,6 +1,9 @@
1
1
  import { SessionContractError, assertSessionProviderId, } from './contracts.js';
2
2
  export class SessionSourceAdapterRegistry {
3
3
  adapters = new Map();
4
+ list() {
5
+ return [...this.adapters.values()].sort((a, b) => a.provider.localeCompare(b.provider));
6
+ }
4
7
  register(adapter) {
5
8
  const provider = assertSessionProviderId(adapter.provider);
6
9
  if (this.adapters.has(provider))
@@ -13,6 +13,7 @@ import { SessionContractError } from './contracts.js';
13
13
  import { buildSessionAiwgFortemiIndexExport, SESSION_EXPORT_INDEX_SCHEMA_VERSION, } from './fortemi-export-mapping.js';
14
14
  import { discoverSessionOutputCandidates } from './output-lineage.js';
15
15
  import { FilesystemDerivedOutputIndex } from './output-registration.js';
16
+ import { redactSessionValue } from './policy.js';
16
17
  export const SESSION_EXPORT_PLAN_SCHEMA_VERSION = '1.1.0';
17
18
  function eventDigestSummary(events) {
18
19
  const hash = createHash('sha256');
@@ -43,7 +44,7 @@ function localEventAttachment(event, projectRoot) {
43
44
  && value.dataBytes.every((item) => Number.isInteger(item) && Number(item) >= 0 && Number(item) <= 255)) {
44
45
  return { filename, mediaType, bytes: Uint8Array.from(value.dataBytes) };
45
46
  }
46
- if (typeof value.dataUrl === 'string') {
47
+ if (typeof value.dataUrl === 'string' && !value.dataUrl.startsWith('[REDACTED:')) {
47
48
  const match = /^data:([^;,]*)(;base64)?,(.*)$/s.exec(value.dataUrl);
48
49
  if (!match)
49
50
  throw new SessionContractError('MALFORMED_SOURCE', `invalid data URL attachment: ${event.eventId}`);
@@ -52,7 +53,7 @@ function localEventAttachment(event, projectRoot) {
52
53
  : Buffer.from(decodeURIComponent(match[3]), 'utf8');
53
54
  return { filename, mediaType: match[1] || mediaType, bytes };
54
55
  }
55
- if (typeof value.fileUrl === 'string') {
56
+ if (typeof value.fileUrl === 'string' && !value.fileUrl.startsWith('[REDACTED:')) {
56
57
  if (!projectRoot)
57
58
  throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'project root is required for file attachments');
58
59
  const root = realpathSync(projectRoot);
@@ -157,7 +158,7 @@ export function buildSessionExportPlan(repository, options) {
157
158
  sampleRecordIds: index.items.slice(0, sampleSize).map((item) => item.id),
158
159
  },
159
160
  };
160
- return { plan, sessions, eventsBySessionId };
161
+ return { plan: redactSessionValue(plan).value, sessions, eventsBySessionId };
161
162
  }
162
163
  /**
163
164
  * Re-selects the plan's sessions from the repository and compares digests
@@ -1,7 +1,7 @@
1
1
  import { execFile as execFileCallback } from 'node:child_process';
2
2
  import { constants as fsConstants } from 'node:fs';
3
- import { lstat, open, realpath, writeFile } from 'node:fs/promises';
4
- import { dirname, isAbsolute, join, parse, resolve } from 'node:path';
3
+ import { access, lstat, open, realpath, stat, writeFile } from 'node:fs/promises';
4
+ import { delimiter, dirname, isAbsolute, join, parse, resolve } from 'node:path';
5
5
  import { promisify } from 'node:util';
6
6
  import { resolveGrokHomeResult } from '../providers/grok-build-paths.js';
7
7
  import { SessionContractError } from './contracts.js';
@@ -115,10 +115,10 @@ async function runGrok(options, args) {
115
115
  if (!home.ok)
116
116
  throw new SessionContractError('SOURCE_NOT_AUTHORIZED', home.message);
117
117
  await rejectSymlinkComponents(home.path);
118
- const binary = options.binary ?? 'grok';
119
- if (binary !== 'grok' && !isAbsolute(binary)) {
118
+ if (options.binary !== undefined && !isAbsolute(options.binary)) {
120
119
  throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'Grok Build binary override must be absolute');
121
120
  }
121
+ const binary = options.binary ?? await defaultGrokBinary(env, home.path);
122
122
  const runner = options.runner ?? execFile;
123
123
  try {
124
124
  const result = await runner(binary, ['--no-auto-update', ...args], {
@@ -136,7 +136,69 @@ async function runGrok(options, args) {
136
136
  if (error.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') {
137
137
  throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Grok Build CLI output exceeds 2 MB');
138
138
  }
139
- throw new SessionContractError('UNSUPPORTED_OPERATION', 'Grok Build CLI failed or timed out; check the local `grok` installation, authentication, and selected workspace.');
139
+ throw grokFailure(error, binary);
140
+ }
141
+ }
142
+ /**
143
+ * Map a failed `grok` launch to an actionable error (#2968). stderr is never
144
+ * echoed: Grok Build diagnostics can carry session content.
145
+ */
146
+ function grokFailure(error, binary) {
147
+ const name = binary === 'grok' ? '`grok`' : `\`${binary}\``;
148
+ if (error.code === 'ENOENT') {
149
+ return new SessionContractError('UNSUPPORTED_OPERATION', `Grok Build CLI not found: ${name} is not on PATH and no $GROK_HOME/bin/grok was found; `
150
+ + 'pass --grok-bin <absolute path> or add the Grok Build bin directory to PATH.');
151
+ }
152
+ if (error.code === 'EACCES') {
153
+ return new SessionContractError('UNSUPPORTED_OPERATION', `Grok Build CLI ${name} is not executable; check its permissions or pass --grok-bin <absolute path>.`);
154
+ }
155
+ if (error.killed || error.signal) {
156
+ return new SessionContractError('UNSUPPORTED_OPERATION', `Grok Build CLI ${name} timed out after ${TIMEOUT_MS / 1000}s; check that it is authenticated `
157
+ + 'and does not prompt for input.');
158
+ }
159
+ if (typeof error.code === 'number') {
160
+ return new SessionContractError('UNSUPPORTED_OPERATION', `Grok Build CLI ${name} exited with code ${error.code}; run \`grok sessions list\` in the selected `
161
+ + 'workspace to check authentication and installation.');
162
+ }
163
+ return new SessionContractError('UNSUPPORTED_OPERATION', 'Grok Build CLI failed; check the local `grok` installation, authentication, and selected workspace.');
164
+ }
165
+ /**
166
+ * Resolve `grok` from PATH, else the installer's `$GROK_HOME/bin/grok` (#2968).
167
+ * The installer links `bin/grok` to a versioned binary beside it, so that one
168
+ * link is followed only when it resolves to a regular file inside `bin`.
169
+ */
170
+ async function defaultGrokBinary(env, grokHome) {
171
+ for (const directory of (env.PATH ?? '').split(delimiter)) {
172
+ if (!directory || !isAbsolute(directory))
173
+ continue;
174
+ if (await isExecutableFile(join(directory, 'grok')))
175
+ return 'grok';
176
+ }
177
+ const binDirectory = join(grokHome, 'bin');
178
+ try {
179
+ await rejectSymlinkComponents(binDirectory);
180
+ const canonicalBin = await realpath(binDirectory);
181
+ const target = await realpath(join(binDirectory, 'grok'));
182
+ if (dirname(target) !== canonicalBin || !(await isExecutableFile(target)))
183
+ return 'grok';
184
+ return target;
185
+ }
186
+ catch (error) {
187
+ if (error instanceof SessionContractError)
188
+ throw error;
189
+ return 'grok';
190
+ }
191
+ }
192
+ async function isExecutableFile(path) {
193
+ try {
194
+ const item = await stat(path);
195
+ if (!item.isFile())
196
+ return false;
197
+ await access(path, fsConstants.X_OK);
198
+ return true;
199
+ }
200
+ catch {
201
+ return false;
140
202
  }
141
203
  }
142
204
  function parseSessionIds(stdout, mode) {
@@ -0,0 +1,72 @@
1
+ import { homedir } from 'node:os';
2
+ import { basename, dirname, extname, isAbsolute } from 'node:path';
3
+ import { SessionContractError } from './contracts.js';
4
+ import { grokbotConversationIdFromLocator } from './adapters/grokbot-locator.js';
5
+ export function validateImportExclusions(value) {
6
+ if (!Array.isArray(value) || !value.every(entry => typeof entry === 'string' && entry.trim().length > 0)) {
7
+ throw new SessionContractError('INVALID_ARGUMENT', 'sessions.import.exclude must be an array of non-empty strings');
8
+ }
9
+ for (const entry of value) {
10
+ if (!isAbsolute(entry) && entry !== '~' && !entry.startsWith('~/') && /[/*?\\~]/.test(entry)) {
11
+ throw new SessionContractError('INVALID_ARGUMENT', 'sessions.import.exclude path globs must be absolute or ~/ prefixed');
12
+ }
13
+ }
14
+ }
15
+ export function resolveImportExclusions(config, flags = [], env = process.env) {
16
+ const configured = config?.exclude === undefined ? [] : config.exclude;
17
+ validateImportExclusions(configured);
18
+ const entries = [...configured, ...(env.AIWG_SESSIONS_IMPORT_EXCLUDE === undefined
19
+ ? [] : env.AIWG_SESSIONS_IMPORT_EXCLUDE.split(',').map(entry => entry.trim())), ...flags];
20
+ validateImportExclusions(entries);
21
+ return [...new Set(entries)];
22
+ }
23
+ /** Use only discovery metadata and locator names; never inspect source content. */
24
+ export function matchImportExclusion(source, entries) {
25
+ const ids = [source.nativeSessionId, nativeSessionIdFromLocator(source)];
26
+ for (const entry of entries) {
27
+ if (isAbsolute(entry) || entry === '~' || entry.startsWith('~/')) {
28
+ const pattern = entry.startsWith('~') ? homedir() + entry.slice(1) : entry;
29
+ if (globExpression(pattern).test(source.locator))
30
+ return { entry, kind: 'path-glob' };
31
+ }
32
+ else if (ids.includes(entry))
33
+ return { entry, kind: 'session-id' };
34
+ }
35
+ return undefined;
36
+ }
37
+ export function nativeSessionIdFromLocator(source) {
38
+ if (source.provider === 'grokbot')
39
+ return grokbotConversationIdFromLocator(source.locator) ?? undefined;
40
+ if (source.provider === 'muse')
41
+ return basename(dirname(source.locator));
42
+ const name = basename(source.locator, extname(source.locator));
43
+ if (source.provider === 'codex' || source.provider === 'pi') {
44
+ return /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i.exec(name)?.[1] ?? name;
45
+ }
46
+ return name;
47
+ }
48
+ function globExpression(pattern) {
49
+ let expression = '^';
50
+ for (let index = 0; index < pattern.length; index++) {
51
+ const character = pattern[index];
52
+ if (character === '*') {
53
+ if (pattern[index + 1] === '*') {
54
+ index++;
55
+ if (pattern[index + 1] === '/') {
56
+ expression += '(?:.*/)?';
57
+ index++;
58
+ }
59
+ else
60
+ expression += '.*';
61
+ }
62
+ else
63
+ expression += '[^/]*';
64
+ }
65
+ else if (character === '?')
66
+ expression += '[^/]';
67
+ else
68
+ expression += character.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
69
+ }
70
+ return new RegExp(expression + '$');
71
+ }
72
+ //# sourceMappingURL=import-exclusions.js.map
@@ -1,11 +1,10 @@
1
- import { mkdir, readFile, rename, rm, stat, writeFile, } from 'node:fs/promises';
1
+ import { mkdir, readFile, rename, rm, writeFile, } from 'node:fs/promises';
2
2
  import { hostname } from 'node:os';
3
3
  import { dirname } from 'node:path';
4
4
  const DEFAULTS = {
5
5
  waitMs: 5_000,
6
6
  pollMs: 50,
7
7
  heartbeatMs: 1_000,
8
- staleMs: 30_000,
9
8
  };
10
9
  export class ImportLeaseContentionError extends Error {
11
10
  owner;
@@ -29,12 +28,13 @@ export async function acquireImportLease(databasePath, runId, options = {}) {
29
28
  const waitMs = options.waitMs ?? DEFAULTS.waitMs;
30
29
  const pollMs = options.pollMs ?? DEFAULTS.pollMs;
31
30
  const heartbeatMs = options.heartbeatMs ?? DEFAULTS.heartbeatMs;
32
- const staleMs = options.staleMs ?? DEFAULTS.staleMs;
33
31
  const now = options.now ?? (() => new Date());
34
32
  const processAlive = options.processAlive ?? defaultProcessAlive;
33
+ const processStartId = options.processStartId ?? defaultProcessStartId;
35
34
  const lockPath = importLeasePath(databasePath);
36
35
  const ownerPath = `${lockPath}/owner.json`;
37
36
  const deadline = Date.now() + waitMs;
37
+ const startId = await processStartId(process.pid);
38
38
  await mkdir(dirname(databasePath), { recursive: true, mode: 0o700 });
39
39
  while (true) {
40
40
  try {
@@ -47,6 +47,7 @@ export async function acquireImportLease(databasePath, runId, options = {}) {
47
47
  host: hostname(),
48
48
  startedAt: observed,
49
49
  heartbeatAt: observed,
50
+ ...(startId === null ? {} : { processStartId: startId }),
50
51
  };
51
52
  await writeOwner(ownerPath, owner);
52
53
  let heartbeatWrite = Promise.resolve();
@@ -78,10 +79,10 @@ export async function acquireImportLease(databasePath, runId, options = {}) {
78
79
  if (!isNodeError(error) || error.code !== 'EEXIST')
79
80
  throw error;
80
81
  const existing = await readOwner(ownerPath);
81
- if (await staleLease(lockPath, existing, staleMs, processAlive)) {
82
+ if (await staleLease(existing, processAlive, processStartId)) {
82
83
  const confirmed = await readOwner(ownerPath);
83
84
  if (sameLease(existing, confirmed)
84
- && await staleLease(lockPath, confirmed, staleMs, processAlive)) {
85
+ && await staleLease(confirmed, processAlive, processStartId)) {
85
86
  await rm(lockPath, { recursive: true, force: true });
86
87
  continue;
87
88
  }
@@ -103,8 +104,9 @@ async function readOwner(path) {
103
104
  const value = JSON.parse(await readFile(path, 'utf8'));
104
105
  if (value.contractVersion !== '1.0.0'
105
106
  || typeof value.runId !== 'string'
106
- || typeof value.pid !== 'number'
107
+ || !Number.isSafeInteger(value.pid) || (value.pid ?? 0) <= 0
107
108
  || typeof value.host !== 'string'
109
+ || (value.processStartId !== undefined && typeof value.processStartId !== 'string')
108
110
  || typeof value.startedAt !== 'string'
109
111
  || typeof value.heartbeatAt !== 'string')
110
112
  return null;
@@ -114,20 +116,15 @@ async function readOwner(path) {
114
116
  return null;
115
117
  }
116
118
  }
117
- async function staleLease(lockPath, owner, staleMs, processAlive) {
119
+ async function staleLease(owner, processAlive, processStartId) {
118
120
  if (!owner || owner.host !== hostname())
119
121
  return false;
120
- if (processAlive(owner.pid))
121
- return false;
122
- const heartbeat = owner ? Date.parse(owner.heartbeatAt) : Number.NaN;
123
- if (Number.isFinite(heartbeat))
124
- return Date.now() - heartbeat > staleMs;
125
- try {
126
- return Date.now() - (await stat(lockPath)).mtimeMs > staleMs;
127
- }
128
- catch {
122
+ if (!processAlive(owner.pid))
123
+ return true;
124
+ if (!owner.processStartId)
129
125
  return false;
130
- }
126
+ const current = await processStartId(owner.pid);
127
+ return current !== null && current !== owner.processStartId;
131
128
  }
132
129
  function sameLease(first, second) {
133
130
  if (!first || !second)
@@ -136,6 +133,7 @@ function sameLease(first, second) {
136
133
  && first.pid === second.pid
137
134
  && first.host === second.host
138
135
  && first.startedAt === second.startedAt
136
+ && first.processStartId === second.processStartId
139
137
  && first.heartbeatAt === second.heartbeatAt;
140
138
  }
141
139
  function defaultProcessAlive(pid) {
@@ -144,7 +142,25 @@ function defaultProcessAlive(pid) {
144
142
  return true;
145
143
  }
146
144
  catch (error) {
147
- return isNodeError(error) && error.code === 'EPERM';
145
+ return !isNodeError(error) || error.code !== 'ESRCH';
146
+ }
147
+ }
148
+ async function defaultProcessStartId(pid) {
149
+ if (process.platform !== 'linux')
150
+ return null;
151
+ try {
152
+ const [details, bootId] = await Promise.all([
153
+ readFile(`/proc/${pid}/stat`, 'utf8'),
154
+ readFile('/proc/sys/kernel/random/boot_id', 'utf8'),
155
+ ]);
156
+ // The command name may contain spaces and parentheses; field 22 is starttime.
157
+ const startTicks = details.slice(details.lastIndexOf(')') + 2).split(/\s+/)[19];
158
+ return startTicks && /^\d+$/.test(startTicks) && bootId.trim()
159
+ ? `${bootId.trim()}:${startTicks}`
160
+ : null;
161
+ }
162
+ catch {
163
+ return null;
148
164
  }
149
165
  }
150
166
  function isNodeError(error) {
@@ -0,0 +1,37 @@
1
+ import { SessionContractError } from './contracts.js';
2
+ export const DEFAULT_IMPORT_BYTE_LIMITS = Object.freeze({
3
+ maxRecordBytes: 64 * 1024 * 1024,
4
+ maxTotalBytes: 1024 * 1024 * 1024,
5
+ });
6
+ export function resolveImportLimits(config, flags, env = process.env) {
7
+ const resolve = (setting, flag, fallback) => {
8
+ const environmentValue = env[`AIWG_SESSIONS_IMPORT_${setting.toUpperCase()}`];
9
+ const origin = flag !== undefined ? 'flag' : environmentValue !== undefined ? 'env'
10
+ : config?.[setting] !== undefined ? 'config' : 'default';
11
+ const input = flag ?? environmentValue ?? config?.[setting] ?? fallback;
12
+ const value = typeof input === 'string' && /^\d+$/.test(input) ? Number(input) : input;
13
+ if (typeof value !== 'number' || !Number.isSafeInteger(value)
14
+ || value < (setting === 'max_source_bytes' ? 0 : 1)) {
15
+ throw new SessionContractError('INVALID_ARGUMENT', `sessions.import.${setting} (${origin}) must be ${setting === 'max_source_bytes' ? 'a non-negative' : 'a positive'} safe integer in bytes`);
16
+ }
17
+ return { value, origin };
18
+ };
19
+ const record = resolve('max_record_bytes', flags?.maxRecordBytes, DEFAULT_IMPORT_BYTE_LIMITS.maxRecordBytes);
20
+ const source = resolve('max_source_bytes', flags?.maxSourceBytes, DEFAULT_IMPORT_BYTE_LIMITS.maxTotalBytes);
21
+ return {
22
+ maxRecordBytes: record.value,
23
+ maxTotalBytes: source.value,
24
+ limitOrigins: { maxRecordBytes: record.origin, maxTotalBytes: source.origin },
25
+ };
26
+ }
27
+ export function assertImportByteLimit(limit, limits, observed) {
28
+ const configured = limits[limit];
29
+ if (limit === 'maxTotalBytes' && configured === 0)
30
+ return;
31
+ if (observed > configured) {
32
+ const setting = limit === 'maxRecordBytes' ? 'sessions.import.max_record_bytes' : 'sessions.import.max_source_bytes';
33
+ const origin = limits.limitOrigins?.[limit] ?? 'default';
34
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', `${setting} exceeded (configured=${configured}, observed=${observed}, origin=${origin})`, { limit, setting, configured, observed, origin });
35
+ }
36
+ }
37
+ //# sourceMappingURL=import-limits.js.map