@aiwg/cli 2026.10.3 → 2026.10.5

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 +69 -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 +286 -131
  21. package/dist/src/artifacts/index-files.js +132 -18
  22. package/dist/src/artifacts/index-preparation.js +130 -0
  23. package/dist/src/artifacts/index-refresh.js +591 -0
  24. package/dist/src/artifacts/index-worker.mjs +11 -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 +137 -43
  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 +95 -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 +252 -12
  207. package/dist/src/sessions/contracts.js +50 -3
  208. package/dist/src/sessions/coverage-preflight.js +27 -2
  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 +145 -26
  216. package/dist/src/sessions/readers.js +106 -53
  217. package/dist/src/sessions/refresh.js +105 -0
  218. package/dist/src/sessions/repository.js +151 -54
  219. package/dist/src/sessions/workspace-discovery.js +292 -60
  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
@@ -10,12 +10,15 @@
10
10
  * node tools/plugin/package-plugins.mjs --plugin aiwg-sdlc # Package specific plugin
11
11
  * node tools/plugin/package-plugins.mjs --clean # Clean agentic/code/plugins directory
12
12
  * node tools/plugin/package-plugins.mjs --dry-run # Show what would be copied
13
+ * node tools/plugin/package-plugins.mjs --all --check # Verify tracked Claude copies
13
14
  */
14
15
 
15
16
  import fs from 'fs';
16
17
  import path from 'path';
17
- import { fileURLToPath } from 'url';
18
+ import os from 'os';
19
+ import { fileURLToPath, pathToFileURL } from 'url';
18
20
  import { importImpl } from '../_resolve-impl.mjs';
21
+ import { rewritePublishedMarkdown, reportPluginLinks } from './plugin-links.mjs';
19
22
 
20
23
  const __filename = fileURLToPath(import.meta.url);
21
24
  const __dirname = path.dirname(__filename);
@@ -38,7 +41,9 @@ const PLUGIN_CONFIGS = {
38
41
  skills: 'agentic/code/frameworks/sdlc-complete/skills'
39
42
  },
40
43
  extraCopy: [
41
- { from: 'tools/security/threat-assessment.mjs', to: 'tools/security/threat-assessment.mjs' }
44
+ { from: 'tools/security/threat-assessment.mjs', to: 'tools/security/threat-assessment.mjs' },
45
+ { from: 'agentic/code/frameworks/sdlc-complete/flows/flow-architecture-evolution.playbook.yaml', to: 'flows/flow-architecture-evolution.playbook.yaml' },
46
+ { from: 'agentic/code/frameworks/sdlc-complete/flows/flow-release.playbook.yaml', to: 'flows/flow-release.playbook.yaml' }
42
47
  ],
43
48
  rewrites: [
44
49
  {
@@ -136,7 +141,12 @@ Marketing automation framework with 37 specialized agents.
136
141
  skills: 'agentic/code/addons/voice-framework/skills'
137
142
  },
138
143
  extraCopy: [
139
- { from: 'agentic/code/addons/voice-framework/voices', to: 'voices' }
144
+ { from: 'agentic/code/addons/voice-framework/voices', to: 'voices' },
145
+ { from: 'agentic/code/addons/voice-framework/docs/writing-workflows.md', to: 'docs/writing-workflows.md' },
146
+ { from: 'agentic/code/addons/voice-framework/docs/voice-output-impact.md', to: 'docs/voice-output-impact.md' },
147
+ { from: 'agentic/code/addons/voice-framework/docs/natural-voice/ADR-001-evidence-and-ownership.md', to: 'docs/natural-voice/ADR-001-evidence-and-ownership.md' },
148
+ { from: 'agentic/code/addons/voice-framework/docs/natural-voice/evidence-ledger.v1.json', to: 'docs/natural-voice/evidence-ledger.v1.json' },
149
+ { from: 'agentic/code/addons/voice-framework/flows/voice-critique-correction.flow.yaml', to: 'flows/voice-critique-correction.flow.yaml' }
140
150
  ],
141
151
  readme: `# AIWG Voice Framework
142
152
 
@@ -227,6 +237,11 @@ Writing quality validation and AI pattern detection.
227
237
  agents: 'agentic/code/addons/aiwg-utils/agents',
228
238
  skills: 'agentic/code/addons/aiwg-utils/skills'
229
239
  },
240
+ extraCopy: [
241
+ { from: 'agentic/code/addons/aiwg-utils/rules/skill-discovery.md', to: 'rules/skill-discovery.md' },
242
+ { from: 'agentic/code/addons/aiwg-utils/rules/skill-discovery-guidance.md', to: 'rules/skill-discovery-guidance.md' },
243
+ { from: 'agentic/code/addons/aiwg-utils/rules/cli-secondary.md', to: 'rules/cli-secondary.md' }
244
+ ],
230
245
  readme: `# AIWG Utilities
231
246
 
232
247
  Core AIWG utilities for context regeneration and workspace management.
@@ -269,10 +284,19 @@ Core AIWG utilities for context regeneration and workspace management.
269
284
  name: 'codex-sdlc',
270
285
  displayName: 'AIWG SDLC for Codex',
271
286
  pluginType: 'codex',
287
+ scriptWrappers: [{
288
+ file: 'skills/address-issues-threat-assess/scripts/assess.mjs',
289
+ source: 'agentic/code/frameworks/sdlc-complete/skills/address-issues-threat-assess/scripts/assess.mjs',
290
+ exports: ['assessIssue', 'assessText', 'runCli'],
291
+ }],
272
292
  description: 'Complete SDLC framework packaged as a Codex plugin with skills, agents, and marketplace entry.',
273
293
  sources: {
274
294
  skills: 'agentic/code/frameworks/sdlc-complete/skills'
275
295
  },
296
+ extraCopy: [
297
+ { from: 'agentic/code/frameworks/sdlc-complete/flows/flow-architecture-evolution.playbook.yaml', to: 'flows/flow-architecture-evolution.playbook.yaml' },
298
+ { from: 'agentic/code/frameworks/sdlc-complete/flows/flow-release.playbook.yaml', to: 'flows/flow-release.playbook.yaml' }
299
+ ],
276
300
  readme: `# AIWG SDLC for Codex
277
301
 
278
302
  AIWG SDLC framework packaged as a Codex plugin.
@@ -348,6 +372,9 @@ Digital forensics and incident response framework with 14 specialized agents.
348
372
  agents: 'agentic/code/frameworks/security-engineering/agents',
349
373
  skills: 'agentic/code/frameworks/security-engineering/skills'
350
374
  },
375
+ extraCopy: [
376
+ { from: 'agentic/code/frameworks/security-engineering/rules/ci-action-pinning.md', to: 'rules/ci-action-pinning.md' }
377
+ ],
351
378
  readme: `# AIWG Security Engineering
352
379
 
353
380
  Applied security engineering framework for cryptographic primitive selection, chain-of-trust integrity, and physical-threat modeling.
@@ -394,6 +421,10 @@ Applied security engineering framework for cryptographic primitive selection, ch
394
421
  agents: 'agentic/code/frameworks/research-complete/agents',
395
422
  skills: 'agentic/code/frameworks/research-complete/skills'
396
423
  },
424
+ extraCopy: [
425
+ { from: 'agentic/code/frameworks/research-complete/docs/bibliographic-services.md', to: 'docs/bibliographic-services.md' },
426
+ { from: 'agentic/code/frameworks/research-complete/docs/corpus-data-model.md', to: 'docs/corpus-data-model.md' }
427
+ ],
397
428
  readme: `# AIWG Research Complete
398
429
 
399
430
  Research workflow framework with 9 specialized agents for academic and technical research.
@@ -679,6 +710,9 @@ function parseArgs() {
679
710
 
680
711
  for (let i = 0; i < args.length; i++) {
681
712
  switch (args[i]) {
713
+ case '--check-links':
714
+ options.checkLinks = true;
715
+ break;
682
716
  case '--all':
683
717
  case '-a':
684
718
  options.all = true;
@@ -704,6 +738,9 @@ function parseArgs() {
704
738
  case '-n':
705
739
  options.dryRun = true;
706
740
  break;
741
+ case '--check':
742
+ options.check = true;
743
+ break;
707
744
  case '--help':
708
745
  case '-h':
709
746
  console.log(`
@@ -713,6 +750,7 @@ Usage:
713
750
  node tools/plugin/package-plugins.mjs [options]
714
751
 
715
752
  Options:
753
+ --check-links Report payload links without writing; exit 1 on offenders
716
754
  --all, -a Package all plugins
717
755
  --plugin, -p NAME Package specific plugin
718
756
  --provider NAME Package for a specific provider
@@ -722,6 +760,7 @@ Options:
722
760
  --output PATH Standalone archive output (default: dist/plugins)
723
761
  --clean, -c Clean plugins directory before packaging
724
762
  --dry-run, -n Show what would be done without writing
763
+ --check Verify all default Claude outputs without writing to the checkout
725
764
  --help, -h Show this help message
726
765
 
727
766
  Examples:
@@ -823,6 +862,19 @@ function pruneUndeclaredPackagedSkills(pluginDir, declaredSkills) {
823
862
  }
824
863
  }
825
864
 
865
+
866
+ export function rewritePublishedLinks(pluginDir, payloadRoot = pluginDir) {
867
+ for (const entry of fs.readdirSync(pluginDir, { withFileTypes: true })) {
868
+ const target = path.join(pluginDir, entry.name);
869
+ if (entry.isDirectory()) rewritePublishedLinks(target, payloadRoot);
870
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
871
+ const body = fs.readFileSync(target, 'utf8');
872
+ const rewritten = rewritePublishedMarkdown(body, target, payloadRoot, ROOT_DIR);
873
+ if (rewritten !== body) fs.writeFileSync(target, rewritten);
874
+ }
875
+ }
876
+ }
877
+
826
878
  // Clean plugin directory (except .claude-plugin)
827
879
  function cleanPlugin(pluginDir) {
828
880
  if (!fs.existsSync(pluginDir)) return;
@@ -844,7 +896,7 @@ function cleanPlugin(pluginDir) {
844
896
  function packagePlugin(name, config, options) {
845
897
  console.log(`\n📦 Packaging ${config.displayName}...`);
846
898
 
847
- const pluginDir = path.join(PLUGINS_DIR, name);
899
+ const pluginDir = path.join(options.pluginsDir || PLUGINS_DIR, name);
848
900
 
849
901
  if (options.clean) {
850
902
  console.log(' 🧹 Cleaning existing files...');
@@ -930,6 +982,8 @@ function packagePlugin(name, config, options) {
930
982
  }, null, 2)}\n`);
931
983
  }
932
984
 
985
+ if (!options.dryRun) rewritePublishedLinks(pluginDir);
986
+
933
987
  console.log(` ✅ ${config.displayName} packaged successfully`);
934
988
  }
935
989
 
@@ -975,8 +1029,37 @@ function writeClaudeMarketplaceManifest(options) {
975
1029
  console.log(` ${manifest.plugins.length} plugins`);
976
1030
  return;
977
1031
  }
978
- fs.writeFileSync(existingPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
979
- console.log(`\n✓ Wrote Claude marketplace: ${existingPath} (${manifest.plugins.length} plugins)`);
1032
+ const outputPath = options.marketplacePath || existingPath;
1033
+ fs.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
1034
+ console.log(`\n✓ Wrote Claude marketplace: ${outputPath} (${manifest.plugins.length} plugins)`);
1035
+ }
1036
+
1037
+ // Runtime delegates are generated after copying sources, so regeneration cannot
1038
+ // replace canonical routing with a checkout-relative implementation copy.
1039
+ export function writeCanonicalScriptWrappers(pluginDir, wrappers, repoRoot = ROOT_DIR) {
1040
+ for (const wrapper of wrappers || []) {
1041
+ const target = path.join(pluginDir, wrapper.file);
1042
+ const relativeSource = path.relative(path.dirname(target), path.join(repoRoot, wrapper.source)).split(path.sep).join('/');
1043
+ const source = JSON.stringify(wrapper.source);
1044
+ fs.writeFileSync(target, `#!/usr/bin/env node
1045
+ import fs from 'node:fs';
1046
+ import path from 'node:path';
1047
+ import { pathToFileURL } from 'node:url';
1048
+
1049
+ const candidates = [
1050
+ new URL(${JSON.stringify(relativeSource)}, import.meta.url),
1051
+ pathToFileURL(path.resolve(process.cwd(), ${source})),
1052
+ pathToFileURL(path.resolve(process.cwd(), 'node_modules/aiwg', ${source})),
1053
+ ];
1054
+ const source = candidates.find(candidate => fs.existsSync(candidate));
1055
+ if (!source) throw new Error('Unable to locate the canonical AIWG threat-assessment wrapper');
1056
+ const canonical = await import(source.href);
1057
+
1058
+ ${wrapper.exports.map(name => `export const ${name} = canonical.${name};`).join('\n')}
1059
+
1060
+ if (import.meta.url === pathToFileURL(process.argv[1] || '').href) runCli();
1061
+ `);
1062
+ }
980
1063
  }
981
1064
 
982
1065
  // Package a Codex-format plugin (generates .codex-plugin/plugin.json + marketplace.json)
@@ -1105,10 +1188,80 @@ function writeCodexMarketplaceManifest(options) {
1105
1188
  console.log(`\n✓ Wrote Codex project marketplace: ${manifestPath} (${codexPlugins.length} plugins)`);
1106
1189
  }
1107
1190
 
1191
+ // Compare the same generation logic used by --all, including manifests,
1192
+ // rewrites and skill pruning. Only default Claude-owned paths are checked:
1193
+ // provider-native metadata and separately maintained templates are preserved.
1194
+ export function checkPackagedPlugins({ pluginsDir = PLUGINS_DIR,
1195
+ marketplacePath = path.join(ROOT_DIR, '.claude-plugin/marketplace.json') } = {}) {
1196
+ const temporary = fs.mkdtempSync(path.join(os.tmpdir(), 'aiwg-plugin-check-'));
1197
+ const differences = [];
1198
+ function files(root) {
1199
+ if (!fs.existsSync(root)) return [];
1200
+ if (!fs.statSync(root).isDirectory()) return [''];
1201
+ return fs.readdirSync(root, { withFileTypes: true }).flatMap(entry => (
1202
+ files(path.join(root, entry.name)).map(file => path.join(entry.name, file))
1203
+ ));
1204
+ }
1205
+ function compare(expected, actual, label) {
1206
+ const paths = new Set([...files(expected), ...files(actual)]);
1207
+ for (const file of [...paths].sort()) {
1208
+ const generated = path.join(expected, file);
1209
+ const checkedIn = path.join(actual, file);
1210
+ const name = file ? `${label}/${file}` : label;
1211
+ if (!fs.existsSync(generated)) differences.push(`Unexpected: ${name}`);
1212
+ else if (!fs.existsSync(checkedIn)) differences.push(`Missing: ${name}`);
1213
+ else if (fs.statSync(generated).isDirectory() !== fs.statSync(checkedIn).isDirectory()) differences.push(`Changed type: ${name}`);
1214
+ else if (!fs.readFileSync(generated).equals(fs.readFileSync(checkedIn))) differences.push(`Changed: ${name}`);
1215
+ }
1216
+ }
1217
+ try {
1218
+ const options = { pluginsDir: path.join(temporary, 'plugins'),
1219
+ marketplacePath: path.join(temporary, 'marketplace.json') };
1220
+ for (const [name, config] of Object.entries(PLUGIN_CONFIGS)) {
1221
+ if (config.pluginType && config.pluginType !== 'claude') continue;
1222
+ packagePlugin(name, config, options);
1223
+ const generated = path.join(options.pluginsDir, name);
1224
+ const actual = path.join(pluginsDir, name);
1225
+ const label = `agentic/code/plugins/${name}`;
1226
+ if (config.sourceRoot) {
1227
+ // Entire manifest-backed addon is generated, except other providers'
1228
+ // metadata retained by cleanPlugin().
1229
+ const roots = new Set([...fs.readdirSync(generated), ...files(actual).map(file => file.split(path.sep)[0])]);
1230
+ for (const root of [...roots].sort()) {
1231
+ if ((root.endsWith('-plugin') && root !== '.claude-plugin') || root === 'clawhub.json') continue;
1232
+ compare(path.join(generated, root), path.join(actual, root), `${label}/${root}`);
1233
+ }
1234
+ } else {
1235
+ const roots = [...Object.keys(config.sources || {}),
1236
+ ...(config.extraCopy || []).map(extra => extra.to), '.claude-plugin/plugin.json'];
1237
+ if (config.readme) roots.push('README.md');
1238
+ for (const root of roots) compare(path.join(generated, root), path.join(actual, root), `${label}/${root}`);
1239
+ }
1240
+ }
1241
+ writeClaudeMarketplaceManifest(options);
1242
+ compare(options.marketplacePath, marketplacePath, '.claude-plugin/marketplace.json');
1243
+ return differences;
1244
+ } finally {
1245
+ fs.rmSync(temporary, { recursive: true, force: true });
1246
+ }
1247
+ }
1248
+
1108
1249
  // Main function
1109
1250
  async function main() {
1110
1251
  const options = parseArgs();
1111
1252
 
1253
+ if (options.check) {
1254
+ if (!options.all || options.plugin || options.provider || options.source || options.output || options.clean || options.dryRun || options.checkLinks) {
1255
+ throw new Error('--check requires --all and cannot be combined with other packaging options');
1256
+ }
1257
+ const differences = checkPackagedPlugins();
1258
+ if (differences.length) {
1259
+ throw new Error(`Generated plugin copies are stale:\n${differences.join('\n')}\nRun npm run package-plugins and review the diff.`);
1260
+ }
1261
+ console.log('✓ All generated Claude plugin copies match canonical sources.');
1262
+ return;
1263
+ }
1264
+
1112
1265
  if (!options.all && !options.plugin) {
1113
1266
  console.log('Please specify --all or --plugin NAME');
1114
1267
  console.log('Use --help for more information');
@@ -1123,7 +1276,7 @@ async function main() {
1123
1276
  console.log(' Mode: DRY RUN (no files will be changed)');
1124
1277
  }
1125
1278
 
1126
- if (options.plugin && !options.all) {
1279
+ if (options.plugin && !options.all && !options.checkLinks) {
1127
1280
  const { packageStandalonePlugin } = await importImpl(import.meta.url, 'plugins/standalone-packager.js');
1128
1281
  const standalone = await packageStandalonePlugin({
1129
1282
  cwd: process.cwd(),
@@ -1175,6 +1328,15 @@ async function main() {
1175
1328
  process.exit(1);
1176
1329
  }
1177
1330
 
1331
+ if (options.checkLinks) {
1332
+ let count = 0;
1333
+ for (const [name] of pluginsToPackage) {
1334
+ count += reportPluginLinks(path.join(PLUGINS_DIR, name)).length;
1335
+ }
1336
+ if (count) process.exitCode = 1;
1337
+ return;
1338
+ }
1339
+
1178
1340
  // Package for each (provider, plugin) combination
1179
1341
  for (const provider of providersToRun) {
1180
1342
  for (const [name, config] of pluginsToPackage) {
@@ -1192,6 +1354,22 @@ async function main() {
1192
1354
  // cursor, factory, openclaw — generic provider plugin bundle
1193
1355
  await packageProviderPlugin(name, config, options, effectiveProvider);
1194
1356
  }
1357
+ if (!options.dryRun) {
1358
+ const pluginDir = path.join(PLUGINS_DIR, name);
1359
+ // Claude already copied extras; other providers need the same docs.
1360
+ if (provider !== 'claude') {
1361
+ for (const extra of config.extraCopy || []) {
1362
+ const destination = path.join(pluginDir, extra.to);
1363
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
1364
+ fs.cpSync(path.join(ROOT_DIR, extra.from), destination, { recursive: true });
1365
+ }
1366
+ }
1367
+ if (provider !== 'claude') {
1368
+ writeCanonicalScriptWrappers(pluginDir, config.scriptWrappers);
1369
+ rewritePublishedLinks(pluginDir);
1370
+ }
1371
+ reportPluginLinks(pluginDir);
1372
+ }
1195
1373
  }
1196
1374
 
1197
1375
  if (provider === 'claude') {
@@ -1215,7 +1393,7 @@ async function main() {
1215
1393
  console.log(' aiwg use sdlc --provider openclaw # OpenClaw (ClawHub publish pending)');
1216
1394
  }
1217
1395
 
1218
- main().catch((error) => {
1396
+ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) main().catch((error) => {
1219
1397
  console.error(error instanceof Error ? error.message : String(error));
1220
1398
  process.exitCode = 1;
1221
1399
  });
@@ -0,0 +1,114 @@
1
+ /** Markdown payload-link inventory. No checkout existence can satisfy a plugin link. */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ // Mask code/comments without changing offsets, so diagnostics retain source lines.
6
+ function prose(body) {
7
+ let fence;
8
+ return body.replace(/<!--[^]*?-->/g, text => text.replace(/[^\n]/g, ' '))
9
+ .split('\n').map(line => {
10
+ const marker = line.match(/^\s{0,3}(`{3,}|~{3,})/);
11
+ if (fence) {
12
+ if (marker && marker[1][0] === fence[0] && marker[1].length >= fence.length) fence = undefined;
13
+ return ' '.repeat(line.length);
14
+ }
15
+ if (marker) { fence = marker[1]; return ' '.repeat(line.length); }
16
+ return line.replace(/(`+)[^]*?\1/g, text => ' '.repeat(text.length));
17
+ }).join('\n');
18
+ }
19
+
20
+ export function markdownLinks(body) {
21
+ const content = prose(body);
22
+ // Inline links/images (including angle destinations and one nested pair of
23
+ // parentheses), plus reference definitions. Definitions are checked once.
24
+ const pattern = /!?\[[^\]]*\]\(\s*(?:<([^>\n]+)>|((?:[^\s()\\]|\\.|\([^()]*\))+))(?:\s+(?:"[^"\n]*"|'[^'\n]*'|\([^()\n]*\)))?\s*\)|^\s{0,3}\[[^\]\n]+\]:\s*(?:<([^>\n]+)>|(\S+))/gm;
25
+ return [...content.matchAll(pattern)].map(match => {
26
+ const target = match[1] ?? match[2] ?? match[3] ?? match[4];
27
+ return {
28
+ target,
29
+ start: match.index + match[0].indexOf(target, match[0].indexOf(']') + 2),
30
+ line: content.slice(0, match.index).split('\n').length,
31
+ };
32
+ });
33
+ }
34
+
35
+ function outside(root, target) {
36
+ const relative = path.relative(root, target);
37
+ return relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative);
38
+ }
39
+
40
+ /** Separate from generation/check mode so the copy-drift guard can reuse it. */
41
+ export function checkPluginLinks(pluginDir) {
42
+ const root = fs.realpathSync(pluginDir);
43
+ const offenders = [];
44
+ function visit(dir) {
45
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
46
+ const file = path.join(dir, entry.name);
47
+ if (entry.isDirectory()) visit(file);
48
+ else if (entry.isFile() && /\.md$/i.test(entry.name)) {
49
+ for (const { target, line } of markdownLinks(fs.readFileSync(file, 'utf8'))) {
50
+ if (/^(?:[a-z][\w+.-]*:|\/\/|#)/i.test(target)) continue;
51
+ let destination;
52
+ try { destination = decodeURIComponent(target.split(/[?#]/)[0]).replace(/\\([ ()])/g, '$1'); }
53
+ catch { destination = target.split(/[?#]/)[0]; }
54
+ if (!destination) continue;
55
+ const resolved = path.resolve(path.dirname(file), destination);
56
+ const exists = fs.existsSync(resolved);
57
+ const reason = outside(root, resolved) || (exists && outside(root, fs.realpathSync(resolved)))
58
+ ? 'outside-payload' : !exists ? 'missing-target' : null;
59
+ if (reason) offenders.push({ file: path.relative(root, file).split(path.sep).join('/'), line, target, reason });
60
+ }
61
+ }
62
+ }
63
+ }
64
+ visit(root);
65
+ return offenders;
66
+ }
67
+
68
+ export function reportPluginLinks(pluginDir, log = console.warn) {
69
+ const offenders = checkPluginLinks(pluginDir);
70
+ for (const item of offenders) {
71
+ log(`${path.basename(pluginDir)}/${item.file}:${item.line}: ${item.reason}: ${item.target}`);
72
+ }
73
+ log(`${path.basename(pluginDir)}: ${offenders.length} unresolved relative Markdown link(s)`);
74
+ return offenders;
75
+ }
76
+
77
+ // Published cross-component docs are available independently of plugin installs.
78
+ // These aliases also repair historical framework-relative paths in source skills.
79
+ const PUBLISHED_LINKS = {
80
+ '../../../addons/aiwg-utils/rules/skill-discovery.md': 'agentic/code/addons/aiwg-utils/rules/skill-discovery.md',
81
+ '../../../addons/aiwg-utils/rules/sdlc-right-sizing.md': 'agentic/code/addons/aiwg-utils/rules/sdlc-right-sizing.md',
82
+ '../../../addons/dataset-intelligence/docs/migration-guide.md': 'agentic/code/addons/dataset-intelligence/docs/migration-guide.md',
83
+ '../../../dataset-intelligence/docs/migration-guide.md': 'agentic/code/addons/dataset-intelligence/docs/migration-guide.md',
84
+ '../dataset-intelligence/migration-guide.md': 'agentic/code/addons/dataset-intelligence/docs/migration-guide.md',
85
+ '../../getting-started/install-connect-verify.md': 'docs/getting-started/install-connect-verify.md',
86
+ '../../docs/daemon-guide.md': 'docs/daemon-guide.md',
87
+ '../../../../../../docs/verification-contracts.md': 'docs/verification-contracts.md',
88
+ '.claude/rules/dev-idempotent-builds.md': 'agentic/code/extensions/dev/rules/dev-idempotent-builds.md',
89
+ '../../sdlc-complete/rules/token-security.md': 'agentic/code/frameworks/sdlc-complete/rules/token-security.md',
90
+ };
91
+
92
+ /** Apply the packaging rewrite to prose only; scripts and code examples retain their paths. */
93
+ export function rewritePublishedMarkdown(body, file, payloadRoot, repoRoot = path.resolve(import.meta.dirname, '../..')) {
94
+ let rewritten = body;
95
+ for (const link of markdownLinks(body).reverse()) {
96
+ let published = PUBLISHED_LINKS[link.target];
97
+ // Root docs appear at different depths in skills and copied docs.
98
+ // Never let a path into this checkout satisfy an installed plugin.
99
+ if (!published && /^(?:\.\.\/)+docs\//.test(link.target)) {
100
+ const document = link.target.replace(/^(?:\.\.\/)+/, '');
101
+ const local = path.resolve(path.dirname(file), link.target.split(/[?#]/)[0]);
102
+ const outside = path.relative(payloadRoot, local).startsWith(`..${path.sep}`);
103
+ if ((outside || !fs.existsSync(local))
104
+ && fs.existsSync(path.join(repoRoot, document.split(/[?#]/)[0]))) published = document;
105
+ }
106
+ if (!published) continue;
107
+ if (!fs.existsSync(path.join(repoRoot, published.split(/[?#]/)[0]))) {
108
+ throw new Error(`Published link source not found: ${published}`);
109
+ }
110
+ const url = `https://github.com/jmagly/aiwg/blob/main/${published}`;
111
+ rewritten = rewritten.slice(0, link.start) + url + rewritten.slice(link.start + link.target.length);
112
+ }
113
+ return rewritten;
114
+ }
@@ -1,4 +1,6 @@
1
+ import { importImpl } from '../_resolve-impl.mjs';
1
2
  import { spawn } from 'node:child_process';
3
+ const { signalChild } = await importImpl(import.meta.url, 'process/signal-child.mjs');
2
4
 
3
5
  export const ANTIGRAVITY_CONTRACT_VERSION = '1.0.0';
4
6
  export const ANTIGRAVITY_QUALIFIED_CLI_VERSION = '1.1.26';
@@ -92,7 +94,7 @@ export function runAntigravity(prompt, options = {}) {
92
94
  let settled = false;
93
95
  const timer = setTimeout(() => {
94
96
  settled = true;
95
- child.kill('SIGTERM');
97
+ signalChild(child, 'SIGTERM');
96
98
  reject(new Error(`Antigravity invocation timed out after ${timeoutMs}ms`));
97
99
  }, timeoutMs);
98
100
  child.stdout.on('data', chunk => { stdout += chunk; });
@@ -1,8 +1,10 @@
1
+ import { importImpl } from '../_resolve-impl.mjs';
1
2
  import { createHash } from 'node:crypto';
2
3
  import { mkdtemp, readFile, rm, writeFile, chmod } from 'node:fs/promises';
3
4
  import { tmpdir } from 'node:os';
4
5
  import { join, resolve } from 'node:path';
5
6
  import { spawn } from 'node:child_process';
7
+ const { signalChild } = await importImpl(import.meta.url, 'process/signal-child.mjs');
6
8
 
7
9
  export const DSH_SUPPORTED_VERSIONS = Object.freeze(['0.1.1-rc.2', '0.1.2-rc.1', '0.1.3-alpha.1']);
8
10
  export const DSH_MAX_FRAME_BYTES = 1024 * 1024;
@@ -240,9 +242,9 @@ export class DshJsonRpcClient {
240
242
  shutdown() { return this.request('shutdown', {}); }
241
243
  abort(error = new Error('DeepSeek Harness JSON-RPC client closed')) {
242
244
  if (this.child && !this.child.killed) {
243
- this.child.kill('SIGTERM');
245
+ signalChild(this.child, 'SIGTERM');
244
246
  const child = this.child;
245
- const escalation = setTimeout(() => { if (child.exitCode === null) child.kill('SIGKILL'); }, 1_000);
247
+ const escalation = setTimeout(() => { if (child.exitCode === null) signalChild(child, 'SIGKILL'); }, 1_000);
246
248
  child.once('exit', () => clearTimeout(escalation));
247
249
  }
248
250
  this.rejectAll(error);
@@ -327,10 +329,10 @@ function runBounded(binary, args, { cwd, env, timeoutMs, terminateGraceMs = 1_00
327
329
  finish(error);
328
330
  return;
329
331
  }
330
- child.kill('SIGTERM');
332
+ signalChild(child, 'SIGTERM');
331
333
  if (settled) return;
332
334
  escalation = setTimeout(() => {
333
- if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL');
335
+ if (child.exitCode === null && child.signalCode === null) signalChild(child, 'SIGKILL');
334
336
  }, terminateGraceMs);
335
337
  };
336
338
  const cancel = () => terminate(new Error('DeepSeek Harness run cancelled'));
@@ -1,11 +1,13 @@
1
1
  import { spawn, spawnSync } from 'node:child_process';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { importImpl } from '../_resolve-impl.mjs';
4
+ const { signalChild } = await importImpl(import.meta.url, 'process/signal-child.mjs');
4
5
 
5
6
  const { positiveTimeoutMs } = await importImpl(import.meta.url, 'process/bounded-child-process.mjs');
6
7
 
7
8
  /** Preserve process identity and state: zombies still fail the cleanup gate. */
8
9
  export async function inspectOmpProcess({ pid, startTime }) {
10
+ if (!Number.isSafeInteger(pid) || pid <= 0) return { pid, present: false };
9
11
  try {
10
12
  const stat = await readFile(`/proc/${pid}/stat`, 'utf8');
11
13
  const fields = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\s+/);
@@ -145,7 +147,7 @@ export class OmpRpcClient {
145
147
  } catch (error) { await this.close(); throw error; } finally { this.running = false; }
146
148
  }
147
149
  fail(error) { if (this.failure) return; this.failure = error; clearTimeout(this.readyTimer); this.readyReject(error); this.promptReject?.(error); for (const p of this.pending.values()) { clearTimeout(p.timer); p.reject(error); } this.pending.clear(); if (!this.isClosed) this.kill('SIGKILL'); }
148
- kill(signal) { try { if (process.platform !== 'win32' && this.child.pid) process.kill(-this.child.pid, signal); else this.child.kill(signal); } catch { /* already exited */ } }
150
+ kill(signal) { try { if (process.platform !== 'win32' && Number.isSafeInteger(this.child.pid) && this.child.pid > 0) process.kill(-this.child.pid, signal); else signalChild(this.child, signal); } catch { /* already exited */ } }
149
151
  async close() {
150
152
  if (this.isClosed) return this.closed;
151
153
  if (this.closing) return this.closing;
@@ -181,7 +183,7 @@ export async function warmAndConnectOmpRpcClient({ binary, cwd, env, warmArgs =
181
183
  const warmStarted = Date.now();
182
184
  // warmTimeoutMs is caller-controlled; clamp it so a caller passing 0 (or
183
185
  // anything else non-positive) can't disable the bound (#3062 B/C finding 8).
184
- const warmup = spawnSync(binary, warmArgs, { cwd, env, encoding: 'utf8', timeout: positiveTimeoutMs(warmTimeoutMs, 15000) });
186
+ const warmup = spawnSync(binary, warmArgs, { cwd, env, encoding: 'utf8', timeout: positiveTimeoutMs(warmTimeoutMs, 15000), killSignal: 'SIGKILL' });
185
187
  const warmedMs = Date.now() - warmStarted;
186
188
  const warmupResult = { status: warmup.status ?? null, signal: warmup.signal ?? null, error: warmup.error ? String(warmup.error.message ?? warmup.error) : null };
187
189
  const readyStarted = Date.now();