@aiwg/cli 2026.10.3 → 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 (279) hide show
  1. package/README.md +2 -2
  2. package/agentic/code/providers/model-capabilities.v1.json +96 -4
  3. package/bin/aiwg.mjs +50 -27
  4. package/dist/src/agents/grounding/knowledge-base.js +54 -6
  5. package/dist/src/artifacts/browser-export.js +6 -0
  6. package/dist/src/artifacts/checksum-manifest.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +173 -92
  8. package/dist/src/artifacts/citation-table-schema.js +59 -0
  9. package/dist/src/artifacts/cli.js +57 -18
  10. package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
  11. package/dist/src/artifacts/corpus-tools/vision-extract.js +2 -0
  12. package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
  13. package/dist/src/artifacts/corpus-views/renderers.js +3 -3
  14. package/dist/src/artifacts/discovery-eval.js +6 -4
  15. package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
  16. package/dist/src/artifacts/fortemi-core-sync.js +166 -40
  17. package/dist/src/artifacts/framework-capabilities.js +171 -0
  18. package/dist/src/artifacts/framework-index-paths.js +73 -0
  19. package/dist/src/artifacts/framework-source-digest.js +75 -0
  20. package/dist/src/artifacts/index-builder.js +285 -131
  21. package/dist/src/artifacts/index-files.js +132 -18
  22. package/dist/src/artifacts/index-preparation.js +65 -0
  23. package/dist/src/artifacts/index-refresh.js +576 -0
  24. package/dist/src/artifacts/index-worker.mjs +9 -0
  25. package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
  26. package/dist/src/artifacts/prebuilt-deployment.js +46 -0
  27. package/dist/src/artifacts/prebuilt-relations.js +80 -0
  28. package/dist/src/artifacts/query-engine.js +410 -88
  29. package/dist/src/artifacts/relations-builder.js +168 -0
  30. package/dist/src/artifacts/relations.js +148 -0
  31. package/dist/src/artifacts/stats.js +5 -2
  32. package/dist/src/artifacts/types.js +30 -10
  33. package/dist/src/artifacts/watcher.js +1 -1
  34. package/dist/src/auth/credential-store.js +2 -1
  35. package/dist/src/catalog/cli.d.mts +5 -0
  36. package/dist/src/channel/manager.d.mts +20 -0
  37. package/dist/src/channel/manager.mjs +19 -2
  38. package/dist/src/cli/command-log.js +2 -3
  39. package/dist/src/cli/handlers/artifacts.js +3 -0
  40. package/dist/src/cli/handlers/auth.js +3 -0
  41. package/dist/src/cli/handlers/decision.js +19 -12
  42. package/dist/src/cli/handlers/diagnose.js +4 -3
  43. package/dist/src/cli/handlers/effect.js +4 -2
  44. package/dist/src/cli/handlers/evidence.js +3 -0
  45. package/dist/src/cli/handlers/help.js +1 -0
  46. package/dist/src/cli/handlers/index.js +3 -1
  47. package/dist/src/cli/handlers/init.js +4 -1
  48. package/dist/src/cli/handlers/lint.js +5 -0
  49. package/dist/src/cli/handlers/models.js +104 -8
  50. package/dist/src/cli/handlers/ralph-launcher.js +2 -0
  51. package/dist/src/cli/handlers/refresh.js +12 -0
  52. package/dist/src/cli/handlers/resource-versions.js +3 -0
  53. package/dist/src/cli/handlers/rules.js +195 -0
  54. package/dist/src/cli/handlers/run.js +4 -0
  55. package/dist/src/cli/handlers/runtime-info.js +1 -2
  56. package/dist/src/cli/handlers/script-runner.js +3 -2
  57. package/dist/src/cli/handlers/session.js +19 -9
  58. package/dist/src/cli/handlers/sessions.js +98 -37
  59. package/dist/src/cli/handlers/setup-manifest.js +39 -44
  60. package/dist/src/cli/handlers/setup.js +41 -0
  61. package/dist/src/cli/handlers/steward.js +11 -0
  62. package/dist/src/cli/handlers/subcommands.js +57 -2
  63. package/dist/src/cli/handlers/uhp.js +3 -0
  64. package/dist/src/cli/handlers/use.js +294 -55
  65. package/dist/src/cli/handlers/utilities.js +26 -10
  66. package/dist/src/cli/handlers/version.js +8 -0
  67. package/dist/src/cli/router.js +15 -1
  68. package/dist/src/cli/services/deployment-verification.js +19 -9
  69. package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
  70. package/dist/src/cli/skill-usage.js +2 -3
  71. package/dist/src/config/aiwg-config.js +87 -37
  72. package/dist/src/config/cli.js +111 -5
  73. package/dist/src/config/decision-config.js +106 -0
  74. package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
  75. package/dist/src/config/gitignore.js +50 -0
  76. package/dist/src/config/index-graph-overrides.js +36 -0
  77. package/dist/src/config/project-artifacts-health.d.mts +37 -0
  78. package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
  79. package/dist/src/config/user-config-dir.d.mts +9 -0
  80. package/dist/src/config/user-config.js +2 -1
  81. package/dist/src/config/user-registry.js +23 -15
  82. package/dist/src/config/user-state.js +7 -0
  83. package/dist/src/decision/ask.js +203 -43
  84. package/dist/src/decision/context-live-qualification.js +2 -2
  85. package/dist/src/decision/driver.js +13 -8
  86. package/dist/src/decision/ensemble/aggregate.js +23 -10
  87. package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
  88. package/dist/src/decision/entry.js +2 -15
  89. package/dist/src/decision/graph-live-qualification.js +1 -1
  90. package/dist/src/decision/graph-run.js +9 -0
  91. package/dist/src/decision/heldout/collector.js +5 -13
  92. package/dist/src/decision/heldout/contract.js +30 -7
  93. package/dist/src/decision/jev-credentials.js +15 -1
  94. package/dist/src/decision/ledger.js +131 -28
  95. package/dist/src/decision/offload-activation.js +137 -0
  96. package/dist/src/decision/offload.js +550 -0
  97. package/dist/src/decision/qualification/load.js +4 -6
  98. package/dist/src/decision/savings.js +28 -0
  99. package/dist/src/effects/types.js +5 -1
  100. package/dist/src/effects/verifiers/git.js +2 -1
  101. package/dist/src/effects/verifiers/tracker.js +26 -14
  102. package/dist/src/extensions/commands/definitions.js +19 -0
  103. package/dist/src/extensions/project-local-remove.js +36 -1
  104. package/dist/src/gates/providers/loader.js +61 -17
  105. package/dist/src/installation/manager-command.d.mts +18 -0
  106. package/dist/src/installation/manager-command.mjs +14 -2
  107. package/dist/src/installation/manager.d.mts +49 -0
  108. package/dist/src/installation/manager.mjs +78 -3
  109. package/dist/src/issues/cli.js +4 -4
  110. package/dist/src/issues/local.js +24 -5
  111. package/dist/src/jobs/runner.js +1 -1
  112. package/dist/src/lint/cli.js +27 -1
  113. package/dist/src/lint/loader.js +2 -1
  114. package/dist/src/lint/reporters.js +25 -1
  115. package/dist/src/lint/rule-activation.js +43 -0
  116. package/dist/src/lint/runner.js +137 -62
  117. package/dist/src/mcp/adapters/codex-runtime.js +7 -1
  118. package/dist/src/mcp/claude-install.d.mts +4 -0
  119. package/dist/src/mcp/claude-install.mjs +41 -0
  120. package/dist/src/mcp/cli.d.mts +1 -0
  121. package/dist/src/mcp/cli.mjs +36 -11
  122. package/dist/src/mcp/config-file.d.mts +28 -0
  123. package/dist/src/mcp/config-layers.d.mts +36 -0
  124. package/dist/src/mcp/credentials.d.mts +51 -0
  125. package/dist/src/mcp/grok-build-config.d.mts +6 -0
  126. package/dist/src/mcp/grok-build-config.mjs +1 -1
  127. package/dist/src/mcp/helpers.mjs +3 -2
  128. package/dist/src/mcp/muse-native-config.d.mts +13 -0
  129. package/dist/src/mcp/muse-native-config.mjs +1 -0
  130. package/dist/src/mcp/omp-config.d.mts +4 -0
  131. package/dist/src/mcp/registry.js +3 -93
  132. package/dist/src/mcp/registry.mjs +3 -87
  133. package/dist/src/mcp/server-config.d.mts +3 -0
  134. package/dist/src/mcp/server-config.mjs +89 -0
  135. package/dist/src/mcp/server.mjs +37 -375
  136. package/dist/src/mcp/test-simple.mjs +2 -1
  137. package/dist/src/mcp/toml-editor.d.mts +4 -0
  138. package/dist/src/mcp/toml-string.d.mts +1 -0
  139. package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
  140. package/dist/src/mcp/tool-filters.d.mts +46 -0
  141. package/dist/src/mcp/tools/decision.mjs +12 -11
  142. package/dist/src/mcp/tools/discovery.mjs +62 -55
  143. package/dist/src/mcp/tools/orchestration.mjs +12 -2
  144. package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
  145. package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
  146. package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
  147. package/dist/src/mission-protocol/codecs.js +8 -0
  148. package/dist/src/models/config-loader.js +7 -2
  149. package/dist/src/models/model-capabilities.v1.json +96 -4
  150. package/dist/src/models/model-discovery.js +76 -11
  151. package/dist/src/models/provider-policy.js +101 -7
  152. package/dist/src/models/qualification-digest.d.mts +2 -0
  153. package/dist/src/models/resolver.js +12 -10
  154. package/dist/src/models/worker-direct-readiness.js +65 -44
  155. package/dist/src/models/worker-dispatch-offer.js +3 -3
  156. package/dist/src/models/worker-health-readiness.js +16 -3
  157. package/dist/src/models/worker-installation.d.mts +39 -0
  158. package/dist/src/models/worker-installation.mjs +135 -28
  159. package/dist/src/process/bounded-child-process.d.mts +84 -0
  160. package/dist/src/process/bounded-child-process.mjs +43 -0
  161. package/dist/src/process/cli-command.d.mts +16 -0
  162. package/dist/src/process/signal-child.d.mts +6 -0
  163. package/dist/src/process/signal-child.mjs +7 -0
  164. package/dist/src/providers/deployed-skill-roots.js +20 -0
  165. package/dist/src/providers/grok-build-acp.js +3 -2
  166. package/dist/src/providers/grok-build-headless.js +12 -4
  167. package/dist/src/providers/grok-build-inspect.js +1 -0
  168. package/dist/src/providers/omp-agent.d.mts +8 -0
  169. package/dist/src/providers/omp-diagnostics.d.mts +1 -0
  170. package/dist/src/providers/omp-paths.d.mts +13 -0
  171. package/dist/src/providers/skill-ownership.d.mts +9 -0
  172. package/dist/src/providers/skill-ownership.mjs +88 -0
  173. package/dist/src/rules/activation.d.mts +21 -0
  174. package/dist/src/rules/activation.mjs +62 -0
  175. package/dist/src/rules/inline-budget.d.mts +26 -0
  176. package/dist/src/rules/inline-budget.mjs +66 -0
  177. package/dist/src/rules/inventory.js +129 -0
  178. package/dist/src/rules/pin-state.js +73 -0
  179. package/dist/src/rules/pins.d.mts +14 -0
  180. package/dist/src/rules/pins.mjs +112 -0
  181. package/dist/src/rules/rule-frontmatter.schema.json +197 -0
  182. package/dist/src/serve/mission-conductor.js +38 -12
  183. package/dist/src/serve/worker-invocation.js +30 -10
  184. package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
  185. package/dist/src/sessions/adapter-registry.js +23 -19
  186. package/dist/src/sessions/adapters/claude.js +39 -54
  187. package/dist/src/sessions/adapters/codex.js +82 -67
  188. package/dist/src/sessions/adapters/copilot.js +4 -4
  189. package/dist/src/sessions/adapters/cursor.js +40 -57
  190. package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
  191. package/dist/src/sessions/adapters/factory.js +31 -27
  192. package/dist/src/sessions/adapters/generic.js +10 -10
  193. package/dist/src/sessions/adapters/grok-build.js +11 -11
  194. package/dist/src/sessions/adapters/grokbot.js +24 -13
  195. package/dist/src/sessions/adapters/hermes.js +27 -29
  196. package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
  197. package/dist/src/sessions/adapters/muse.js +150 -93
  198. package/dist/src/sessions/adapters/omp.js +28 -14
  199. package/dist/src/sessions/adapters/openclaw.js +89 -79
  200. package/dist/src/sessions/adapters/opencode.js +27 -24
  201. package/dist/src/sessions/adapters/openhuman.js +18 -60
  202. package/dist/src/sessions/adapters/pi.js +29 -14
  203. package/dist/src/sessions/adapters/warp.js +3 -3
  204. package/dist/src/sessions/adapters/windsurf.js +19 -48
  205. package/dist/src/sessions/batch-contracts.js +16 -8
  206. package/dist/src/sessions/batch-import.js +51 -11
  207. package/dist/src/sessions/contracts.js +40 -2
  208. package/dist/src/sessions/coverage-preflight.js +1 -1
  209. package/dist/src/sessions/export-plan.js +4 -3
  210. package/dist/src/sessions/import-exclusions.js +72 -0
  211. package/dist/src/sessions/import-lease.js +34 -18
  212. package/dist/src/sessions/import-limits.js +37 -0
  213. package/dist/src/sessions/importer.js +60 -38
  214. package/dist/src/sessions/lifecycle.js +45 -0
  215. package/dist/src/sessions/policy.js +133 -25
  216. package/dist/src/sessions/readers.js +106 -53
  217. package/dist/src/sessions/refresh.js +106 -0
  218. package/dist/src/sessions/repository.js +147 -52
  219. package/dist/src/sessions/workspace-discovery.js +221 -56
  220. package/dist/src/sessions/workspace-matching.js +107 -0
  221. package/dist/src/skills/importer.js +1 -0
  222. package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
  223. package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
  224. package/dist/src/smiths/context-pipeline/finalization.js +6 -5
  225. package/dist/src/smiths/context-pipeline/generator.js +21 -4
  226. package/dist/src/smiths/context-pipeline/parallelism-section.js +7 -15
  227. package/dist/src/smiths/mcpsmith/generator.js +1 -1
  228. package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
  229. package/dist/src/smiths/toolsmith/runtime-discovery.mjs +76 -18
  230. package/dist/src/storage/backends/fs.js +18 -76
  231. package/dist/src/storage/backends/obsidian.js +1 -0
  232. package/dist/src/tracker/forge-http.js +2 -1
  233. package/dist/src/update/checker.d.mts +2 -0
  234. package/dist/src/update/service.d.mts +22 -0
  235. package/dist/src/utils/contained-filesystem.d.mts +37 -0
  236. package/dist/src/utils/contained-filesystem.mjs +683 -0
  237. package/dist/src/utils/temporary-directory.js +36 -0
  238. package/dist/src/writing/example-generator.js +1 -1
  239. package/package.json +15 -2
  240. package/schemas/models/model-catalog.v1.schema.json +1 -1
  241. package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
  242. package/tools/_resolve-impl.mjs +13 -15
  243. package/tools/agents/deploy-agents.mjs +49 -21
  244. package/tools/agents/providers/base.mjs +104 -134
  245. package/tools/agents/providers/claude.mjs +8 -24
  246. package/tools/agents/providers/codex.mjs +18 -11
  247. package/tools/agents/providers/cursor.mjs +19 -18
  248. package/tools/agents/providers/grok-build.mjs +3 -1
  249. package/tools/agents/providers/hermes.mjs +57 -47
  250. package/tools/agents/providers/openclaw.mjs +9 -4
  251. package/tools/agents/providers/pi.mjs +5 -0
  252. package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
  253. package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
  254. package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
  255. package/tools/agents/providers/rule-delivery.mjs +1270 -0
  256. package/tools/agents/providers/warp.mjs +20 -26
  257. package/tools/cli/decision-offload-report.mjs +40 -0
  258. package/tools/cli/workspace-status.mjs +862 -0
  259. package/tools/plugin/package-plugins.mjs +186 -8
  260. package/tools/plugin/plugin-links.mjs +114 -0
  261. package/tools/providers/antigravity-transport.mjs +3 -1
  262. package/tools/providers/deepseek-harness-transport.mjs +6 -4
  263. package/tools/providers/omp-transport.mjs +4 -2
  264. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
  265. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
  266. package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
  267. package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
  268. package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
  269. package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
  270. package/tools/ralph-external/lib/session-environment.mjs +28 -0
  271. package/tools/ralph-external/lib/systemd-client.mjs +49 -0
  272. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  273. package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
  274. package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
  275. package/tools/ralph-external/process-monitor.mjs +1017 -0
  276. package/tools/ralph-external/session-launcher.mjs +5057 -0
  277. package/tools/scripts/resource-preflight.mjs +541 -0
  278. package/tools/skills/deploy-skills-codex.mjs +2 -1
  279. package/vscode-extension/schemas/aiwg.config.v1.json +1194 -231
@@ -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
@@ -1,18 +1,20 @@
1
- import { SESSION_CONTRACT_VERSION, SessionEventSchema, SessionSchema, assertSupportedSchemaMajor, sha256, stableEventId, stableSessionId, SessionContractError, } from './contracts.js';
2
- import { redactSessionText, sanitizeNativeExtensions } from './policy.js';
1
+ import { SESSION_CONTRACT_VERSION, SessionEventSchema, SessionSchema, assertSupportedSchemaMajor, sha256, stableEventId, stableSessionId, SessionContractError, schemaIssueDetail, assertSessionResourceLimit, } from './contracts.js';
2
+ import { assertImportByteLimit, DEFAULT_IMPORT_BYTE_LIMITS, resolveImportLimits } from './import-limits.js';
3
+ import { redactSessionValue, sanitizeSessionEvent, sanitizeNativeExtensions } from './policy.js';
3
4
  import { fingerprintSourcePrefix } from './readers.js';
5
+ import { DEFAULT_INACTIVITY_THRESHOLD_MS } from './lifecycle.js';
4
6
  import { classifySessionEventOrigin, deriveSessionIntent, } from './origin.js';
5
- const DEFAULT_LIMITS = {
7
+ export const DEFAULT_IMPORT_LIMITS = {
6
8
  maxRecords: 1_000_000,
7
- maxRecordBytes: 8 * 1024 * 1024,
8
- maxTotalBytes: 1024 * 1024 * 1024,
9
+ ...DEFAULT_IMPORT_BYTE_LIMITS,
9
10
  batchSize: 1_000,
10
11
  };
11
12
  export class SessionImportFailure extends SessionContractError {
12
13
  failureReceipt;
13
14
  constructor(failureReceipt, cause) {
14
- super(cause instanceof SessionContractError ? cause.code : 'IMPORT_INTERRUPTED', cause instanceof Error ? cause.message : 'session import failed');
15
+ super(cause instanceof SessionContractError ? cause.code : 'IMPORT_INTERRUPTED', cause instanceof Error ? cause.message : 'session import failed', cause instanceof SessionContractError ? cause.detail : undefined);
15
16
  this.failureReceipt = failureReceipt;
17
+ this.failureReceipt = redactSessionValue(failureReceipt).value;
16
18
  this.name = 'SessionImportFailure';
17
19
  }
18
20
  }
@@ -30,7 +32,9 @@ export class IncrementalSessionImporter {
30
32
  if (request.workspaceId !== request.selectedSource.authorizedScope.workspaceId) {
31
33
  throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'session import workspace is outside the authorized source scope');
32
34
  }
33
- const limits = { ...DEFAULT_LIMITS, ...request.limits };
35
+ const limits = { ...DEFAULT_IMPORT_LIMITS, ...resolveImportLimits(undefined, {
36
+ maxRecordBytes: request.limits?.maxRecordBytes, maxSourceBytes: request.limits?.maxTotalBytes,
37
+ }), ...request.limits };
34
38
  const previous = request.batchRunId
35
39
  ? this.repository.getBatchCheckpoint(request.source.sourceId, request.adapter.adapterVersion, request.batchRunId) ?? this.repository.getCheckpoint(request.source.sourceId, request.adapter.adapterVersion)
36
40
  : this.repository.getCheckpoint(request.source.sourceId, request.adapter.adapterVersion);
@@ -40,17 +44,17 @@ export class IncrementalSessionImporter {
40
44
  : undefined;
41
45
  const sourceGeneration = continuity?.sourceGeneration ?? sourceGenerationDigest(request);
42
46
  if (previous?.sourceGeneration && previous.sourceGeneration !== sourceGeneration) {
43
- throw new SessionContractError('SCHEMA_DRIFT', 'session source generation changed; explicit restart or migration is required');
47
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source generation changed; explicit restart or migration is required', schemaIssueDetail('sourceGeneration'));
44
48
  }
45
49
  if (previous?.adapterVersion && previous.adapterVersion !== request.adapter.adapterVersion) {
46
- throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint adapter version changed; checkpoint migration is required');
50
+ throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint adapter version changed; checkpoint migration is required', schemaIssueDetail('adapterVersion'));
47
51
  }
48
52
  if (previous?.sourceSchemaVersion
49
53
  && previous.sourceSchemaVersion !== request.source.sourceSchemaVersion) {
50
- throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint source schema changed; checkpoint migration is required');
54
+ throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint source schema changed; checkpoint migration is required', schemaIssueDetail('sourceSchemaVersion'));
51
55
  }
52
56
  if (previous?.policyVersion && previous.policyVersion !== request.policyVersion) {
53
- throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint policy version changed; checkpoint migration is required');
57
+ throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint policy version changed; checkpoint migration is required', schemaIssueDetail('policyVersion'));
54
58
  }
55
59
  const checkpoint = {
56
60
  cursor: previous?.cursor ?? '',
@@ -76,6 +80,7 @@ export class IncrementalSessionImporter {
76
80
  };
77
81
  const receipts = [];
78
82
  let batch = [];
83
+ let batchBytes = 0;
79
84
  let batchStart = checkpoint.recordsRead;
80
85
  let durableCheckpoint = { ...checkpoint };
81
86
  const importStarted = performance.now();
@@ -87,12 +92,14 @@ export class IncrementalSessionImporter {
87
92
  if (request.signal?.aborted) {
88
93
  throw new SessionContractError('IMPORT_INTERRUPTED', 'session import was cancelled at a durable batch boundary');
89
94
  }
95
+ const identities = batch.map(recordIdentity);
96
+ const batchDigests = identities.map(identity => identity.digest);
90
97
  const runId = sha256([
91
98
  request.source.sourceId, request.adapter.adapterVersion,
92
99
  batchStart, checkpoint.recordsRead,
93
- ...batch.map((record) => sha256(JSON.stringify(record))),
100
+ ...batchDigests,
94
101
  ].join('\0'));
95
- const normalized = normalizeBatch(request, batch, runId, sourceObservedAt);
102
+ const normalized = normalizeBatch(request, batch, batchDigests, runId, sourceObservedAt);
96
103
  const run = {
97
104
  contractVersion: SESSION_CONTRACT_VERSION,
98
105
  importRunId: runId,
@@ -123,7 +130,7 @@ export class IncrementalSessionImporter {
123
130
  receipt.metrics = {
124
131
  records: batch.length,
125
132
  normalizedEvents: normalized.events.length,
126
- normalizedBytes: batch.reduce((total, record) => total + Buffer.byteLength(JSON.stringify(record)), 0),
133
+ normalizedBytes: identities.reduce((bytes, identity) => bytes + identity.bytes, 0),
127
134
  durationMs: performance.now() - importStarted,
128
135
  batchLatencyMs: performance.now() - flushStarted,
129
136
  heapUsedBytes: peakHeap,
@@ -133,20 +140,26 @@ export class IncrementalSessionImporter {
133
140
  receipts.push(receipt);
134
141
  durableCheckpoint = { ...checkpoint };
135
142
  batch = [];
143
+ batchBytes = 0;
136
144
  batchStart = checkpoint.recordsRead;
137
145
  };
138
146
  try {
147
+ if (continuity)
148
+ assertImportByteLimit('maxTotalBytes', limits, continuity.size);
139
149
  for await (const record of request.adapter.stream(request.selectedSource, previous ? { value: previous.cursor } : undefined)) {
140
150
  if (request.signal?.aborted) {
141
151
  throw new SessionContractError('IMPORT_INTERRUPTED', 'session import was cancelled and can resume from its durable checkpoint');
142
152
  }
143
- const bytes = Buffer.byteLength(JSON.stringify(record));
144
- if (bytes > limits.maxRecordBytes
145
- || checkpoint.bytesRead + bytes > limits.maxTotalBytes
146
- || checkpoint.recordsRead + 1 > limits.maxRecords) {
147
- throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'session import exceeded an authorized resource limit');
148
- }
153
+ const bytes = recordBytes(record);
154
+ assertImportByteLimit('maxRecordBytes', limits, bytes);
155
+ if (!continuity)
156
+ assertImportByteLimit('maxTotalBytes', limits, checkpoint.bytesRead + bytes);
157
+ assertSessionResourceLimit('maxRecords', limits.maxRecords, checkpoint.recordsRead + 1);
158
+ // Bound batches by bytes as well as record count for large records.
159
+ if (batchBytes + bytes > 4 * 1024 * 1024)
160
+ flush();
149
161
  batch.push(record);
162
+ batchBytes += bytes;
150
163
  checkpoint.recordsRead += 1;
151
164
  if (record.sourceCursor?.startsWith('byte:')) {
152
165
  checkpoint.positionKind = 'byte-offset';
@@ -195,6 +208,7 @@ export class IncrementalSessionImporter {
195
208
  : durableCheckpoint,
196
209
  errorCode: error instanceof SessionContractError
197
210
  ? error.code : 'IMPORT_INTERRUPTED',
211
+ detail: error instanceof SessionContractError ? error.detail : undefined,
198
212
  }, error);
199
213
  }
200
214
  if (request.publish !== false && request.source.consistency === 'complete') {
@@ -207,20 +221,30 @@ export class IncrementalSessionImporter {
207
221
  return receipts;
208
222
  }
209
223
  }
210
- function normalizeBatch(request, records, importRunId, sourceObservedAt) {
224
+ /** Keep large temporary JSON strings out of the asynchronous import frame. */
225
+ function recordBytes(record) {
226
+ return Buffer.byteLength(JSON.stringify(record));
227
+ }
228
+ /** Compute flush-time identity once, preserving adapters that mutate yielded objects. */
229
+ function recordIdentity(record) {
230
+ const serialized = JSON.stringify(record);
231
+ return { bytes: Buffer.byteLength(serialized), digest: sha256(serialized) };
232
+ }
233
+ function normalizeBatch(request, records, digests, importRunId, sourceObservedAt) {
211
234
  const sessions = new Map();
212
- const events = records.map((record) => {
235
+ const events = records.map((record, index) => {
213
236
  const sessionId = stableSessionId(request.source.provider, request.source.sourceId, record.nativeSessionId);
214
- const redacted = redactSessionText(record.text);
215
237
  const native = sanitizeNativeExtensions(record.extensions ?? {});
216
- const digest = sha256(JSON.stringify(record));
238
+ const lineage = request.source.provider === 'codex' && native.value.lineage
239
+ ? { lineage: native.value.lineage } : {};
240
+ const digest = digests[index];
217
241
  const origin = classifySessionEventOrigin(request.source.provider, record);
218
242
  const lifecycle = sessionLifecycle(request, record, sourceObservedAt);
219
243
  const lifecycleEvidence = sessionLifecycleEvidence(request, record, sourceObservedAt);
220
244
  const extensions = {
221
- [`native.${request.source.provider}`]: native.value,
245
+ [`native.${request.source.provider}`]: record.extensions ?? {},
222
246
  };
223
- const event = SessionEventSchema.parse({
247
+ const event = sanitizeSessionEvent(SessionEventSchema.parse({
224
248
  contractVersion: SESSION_CONTRACT_VERSION,
225
249
  eventId: stableEventId(request.source.provider, request.source.sourceId, record, digest),
226
250
  sessionId, sourceId: request.source.sourceId, importRunId,
@@ -238,17 +262,13 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
238
262
  model: record.model ?? null,
239
263
  entities: record.entities ?? [],
240
264
  extractionState: record.extractionState ?? null,
241
- searchableText: redacted.text, digest, rawReference: record.rawReference,
265
+ searchableText: record.text, digest, rawReference: record.rawReference,
242
266
  adapterVersion: request.adapter.adapterVersion,
243
267
  consistency: request.source.consistency,
244
- sensitivity: {
245
- classification: redacted.sensitivity === 'sensitive' || native.sensitivity === 'sensitive'
246
- ? 'sensitive' : 'none',
247
- classes: [...new Set([...redacted.classes, ...native.classes])].sort(),
248
- },
268
+ sensitivity: { classification: 'none', classes: [] },
249
269
  opaque: !isKnownEventKind(record.kind),
250
270
  extensions,
251
- });
271
+ }));
252
272
  if (!sessions.has(sessionId)) {
253
273
  sessions.set(sessionId, SessionSchema.parse({
254
274
  contractVersion: SESSION_CONTRACT_VERSION,
@@ -260,6 +280,7 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
260
280
  sourceDigest: sha256(`${sourceGenerationDigest(request)}\0${record.nativeSessionId}`),
261
281
  extensions: {
262
282
  [`native.${request.source.provider}`]: {
283
+ ...lineage,
263
284
  lifecycleEvidence,
264
285
  },
265
286
  },
@@ -279,6 +300,7 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
279
300
  session.lifecycle = selected.lifecycle;
280
301
  session.extensions[nativeKey] = {
281
302
  ...nativeRecord,
303
+ ...lineage,
282
304
  lifecycleEvidence: selected.evidence,
283
305
  };
284
306
  }
@@ -287,7 +309,7 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
287
309
  for (const session of sessions.values()) {
288
310
  session.intent = deriveSessionIntent(events.filter((event) => event.sessionId === session.sessionId));
289
311
  }
290
- return { sessions: [...sessions.values()], events };
312
+ return { sessions: redactSessionValue([...sessions.values()]).value, events };
291
313
  }
292
314
  const KNOWN_EVENT_KINDS = new Set(['message', 'tool-call', 'tool-result', 'artifact', 'attachment', 'summary']);
293
315
  function isKnownEventKind(kind) {
@@ -363,6 +385,7 @@ function sessionLifecycleEvidence(request, record, sourceObservedAt) {
363
385
  state: 'active',
364
386
  observedAt: observedAt ?? request.source.authorizedAt,
365
387
  confidence: 'provisional',
388
+ thresholdMs,
366
389
  };
367
390
  }
368
391
  function nativeLifecycle(extensions) {
@@ -416,7 +439,6 @@ function evidenceTimestamp(value) {
416
439
  const parsed = Date.parse(String(value.observedAt ?? ''));
417
440
  return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
418
441
  }
419
- const DEFAULT_INACTIVITY_THRESHOLD_MS = 24 * 60 * 60 * 1000;
420
442
  function inactivityThresholdMs(request) {
421
443
  return request.inactivityThresholdMs ?? DEFAULT_INACTIVITY_THRESHOLD_MS;
422
444
  }
@@ -454,15 +476,15 @@ async function sourceContinuity(request, previous) {
454
476
  const metadata = await fingerprintSourcePrefix(authorization, 0);
455
477
  if (!isSnapshot && previous?.sourceSize !== undefined) {
456
478
  if (metadata.size < previous.sourceSize) {
457
- throw new SessionContractError('SCHEMA_DRIFT', 'session source was truncated before its durable checkpoint');
479
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source was truncated before its durable checkpoint', schemaIssueDetail('sourceSize'));
458
480
  }
459
481
  if (previous.sourceFileIdentity
460
482
  && previous.sourceFileIdentity !== metadata.fileIdentity) {
461
- throw new SessionContractError('SCHEMA_DRIFT', 'session source file generation was replaced or rotated');
483
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source file generation was replaced or rotated', schemaIssueDetail('sourceFileIdentity'));
462
484
  }
463
485
  const priorPrefix = await fingerprintSourcePrefix(authorization, previous.sourceSize, skipPrefixBytes);
464
486
  if (previous.prefixDigest && priorPrefix.digest !== previous.prefixDigest) {
465
- throw new SessionContractError('SCHEMA_DRIFT', 'session source prefix was rewritten before its durable checkpoint');
487
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source prefix was rewritten before its durable checkpoint', schemaIssueDetail('prefixDigest'));
466
488
  }
467
489
  }
468
490
  const current = await fingerprintSourcePrefix(authorization, metadata.size, skipPrefixBytes);
@@ -0,0 +1,45 @@
1
+ export const DEFAULT_INACTIVITY_THRESHOLD_MS = 24 * 60 * 60 * 1000;
2
+ export function effectiveSessionLifecycle(session) {
3
+ if (session.lifecycle !== 'active' && session.lifecycle !== 'inactive')
4
+ return session;
5
+ const nativeKey = `native.${session.provider}`;
6
+ const native = objectRecord(session.extensions[nativeKey]);
7
+ const evidence = objectRecord(native.lifecycleEvidence);
8
+ if (evidence.basis !== 'open-provisional-source'
9
+ && evidence.basis !== 'inactivity-threshold')
10
+ return session;
11
+ const observedAt = session.updatedAt ?? evidence.observedAt;
12
+ const timestamp = typeof observedAt === 'string' ? Date.parse(observedAt) : NaN;
13
+ if (!Number.isFinite(timestamp))
14
+ return session;
15
+ const thresholdMs = typeof evidence.thresholdMs === 'number'
16
+ && Number.isFinite(evidence.thresholdMs)
17
+ && evidence.thresholdMs >= 0
18
+ ? evidence.thresholdMs : DEFAULT_INACTIVITY_THRESHOLD_MS;
19
+ const inactive = Date.now() - timestamp > thresholdMs;
20
+ const lifecycle = inactive ? 'inactive' : 'active';
21
+ return {
22
+ ...session,
23
+ lifecycle,
24
+ extensions: {
25
+ ...session.extensions,
26
+ [nativeKey]: {
27
+ ...native,
28
+ lifecycleEvidence: {
29
+ ...evidence,
30
+ basis: inactive ? 'inactivity-threshold' : 'open-provisional-source',
31
+ state: lifecycle,
32
+ observedAt,
33
+ confidence: inactive ? 'medium' : 'provisional',
34
+ thresholdMs,
35
+ },
36
+ },
37
+ },
38
+ };
39
+ }
40
+ function objectRecord(value) {
41
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
42
+ ? value
43
+ : {};
44
+ }
45
+ //# sourceMappingURL=lifecycle.js.map