@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,6 +10,7 @@ import fs from 'fs';
10
10
  import path from 'path';
11
11
  import { DEFAULT_INDEX_EXTENSIONS, GRAPH_CONFIGS, resolveGraphScanDir, } from './types.js';
12
12
  import { DEFAULT_PROJECT_AIWG_DIR, resolveProjectAiwgDir, } from '../config/project-artifacts.js';
13
+ import { dropGitignored } from '../config/gitignore.js';
13
14
  import { workspaceLinkedFiles } from '../smiths/context-pipeline/workspace-context.js';
14
15
  import { discoverProjectLocalBundles } from '../extensions/project-local-discovery.js';
15
16
  function pathContains(parent, child) {
@@ -32,16 +33,18 @@ export function indexPathFor(cwd, fullPath, graph) {
32
33
  return toPosixPath(relative);
33
34
  return fullPath;
34
35
  }
35
- export function findArtifactFiles(dir, extensions = DEFAULT_INDEX_EXTENSIONS) {
36
- return walkArtifactFiles(dir, extensions, new Set());
36
+ export function findArtifactFiles(dir, extensions = DEFAULT_INDEX_EXTENSIONS, acceptPath = () => true) {
37
+ return walkArtifactFiles(dir, extensions, new Set(), acceptPath);
37
38
  }
38
39
  /** Recursively find indexable files, excluding hidden directories such as .index. */
39
- function walkArtifactFiles(dir, extensions, seenRealDirs, boundary) {
40
+ function walkArtifactFiles(dir, extensions, seenRealDirs, acceptPath, knownStat) {
40
41
  const results = [];
41
- if (!fs.existsSync(dir))
42
+ if (!fs.existsSync(dir) || !acceptPath(dir, knownStat))
42
43
  return results;
43
44
  let realDir;
44
45
  try {
46
+ if ((knownStat ?? fs.lstatSync(dir)).isSymbolicLink())
47
+ return results;
45
48
  realDir = fs.realpathSync(dir);
46
49
  }
47
50
  catch {
@@ -55,8 +58,8 @@ function walkArtifactFiles(dir, extensions, seenRealDirs, boundary) {
55
58
  const fullPath = path.join(dir, entry.name);
56
59
  let stat;
57
60
  try {
58
- stat = fs.statSync(fullPath);
59
- if (boundary && !pathContains(boundary, fs.realpathSync(fullPath)))
61
+ stat = fs.lstatSync(fullPath);
62
+ if (stat.isSymbolicLink() || !acceptPath(fullPath, stat, dir))
60
63
  continue;
61
64
  }
62
65
  catch {
@@ -65,7 +68,7 @@ function walkArtifactFiles(dir, extensions, seenRealDirs, boundary) {
65
68
  if (stat.isDirectory()) {
66
69
  if (entry.name.startsWith('.'))
67
70
  continue;
68
- results.push(...walkArtifactFiles(fullPath, extensions, seenRealDirs, boundary));
71
+ results.push(...walkArtifactFiles(fullPath, extensions, seenRealDirs, acceptPath, stat));
69
72
  }
70
73
  else if (stat.isFile() && extensions.some(extension => entry.name.endsWith(extension))) {
71
74
  results.push(fullPath);
@@ -73,22 +76,96 @@ function walkArtifactFiles(dir, extensions, seenRealDirs, boundary) {
73
76
  }
74
77
  return results;
75
78
  }
79
+ /** Runtime and acquisition scratch beneath either the local or relocated artifact root. */
80
+ export const INDEX_SCRATCH_DIRS = [
81
+ 'working', 'sessions', 'scratch', 'tmp', 'temp', 'cache', '.index', '.cache', '.storage-cache',
82
+ ];
76
83
  /** Return the exact current source-file set used by a standard graph build. */
77
- export async function collectGraphIndexFiles(cwd, graph) {
84
+ export async function collectGraphIndexFiles(cwd, graph, options = {}) {
78
85
  const config = graph ? GRAPH_CONFIGS[graph] : undefined;
79
86
  if (graph && !config) {
80
87
  throw new Error(`Unknown graph: ${graph}`);
81
88
  }
82
- const scanDirs = config
83
- ? config.scanDirs.map(directory => resolveGraphScanDir(cwd, directory))
84
- : [resolveProjectAiwgDir(cwd)];
85
- const extensions = config?.extensions ?? [...DEFAULT_INDEX_EXTENSIONS];
89
+ const artifactRoot = resolveProjectAiwgDir(cwd);
90
+ const excludedDirs = [path.join(cwd, DEFAULT_PROJECT_AIWG_DIR), artifactRoot]
91
+ .flatMap(root => INDEX_SCRATCH_DIRS.map(name => path.resolve(root, name)));
92
+ const excludedPaths = new Set(excludedDirs);
93
+ // A directory's ancestors are shared by thousands of sibling artifacts.
94
+ // Cache only within this scan so the next build still notices new symlinks.
95
+ const safePaths = new Map();
96
+ const roots = [artifactRoot, cwd].map(root => path.resolve(root));
97
+ const artifactPrefix = roots[0].endsWith(path.sep) ? roots[0] : roots[0] + path.sep;
98
+ const acceptPath = (file, knownStat, parent) => {
99
+ // The walker already checked this parent and rejected symlink entries.
100
+ // A regular file cannot introduce an excluded ancestor; only an exact
101
+ // excluded path remains to check. Avoid normalizing and memoizing every
102
+ // leaf merely to repeat its parent's proof thousands of times.
103
+ if (parent && knownStat?.isFile() && safePaths.get(parent) === true) {
104
+ if (process.platform === 'win32'
105
+ ? excludedDirs.some(dir => pathContains(dir, file)) : excludedPaths.has(file))
106
+ return false;
107
+ options.fileStats?.set(file, knownStat);
108
+ return true;
109
+ }
110
+ const inputPath = file;
111
+ file = path.resolve(file);
112
+ if (excludedDirs.some(dir => process.platform === 'win32'
113
+ ? pathContains(dir, file) : file === dir || file.startsWith(dir + path.sep)))
114
+ return false;
115
+ if (knownStat && !knownStat.isSymbolicLink() && safePaths.get(path.dirname(file)) === true) {
116
+ if (knownStat.isFile())
117
+ options.fileStats?.set(inputPath, knownStat);
118
+ safePaths.set(file, true);
119
+ return true;
120
+ }
121
+ // Explicit scopes and workspace links can start below a symlink. Check
122
+ // their ancestors too, stopping at the authorized root (which may be external).
123
+ const inArtifactRoot = process.platform === 'win32'
124
+ ? pathContains(roots[0], file) : file === roots[0] || file.startsWith(artifactPrefix);
125
+ const root = inArtifactRoot ? roots[0] : roots[1];
126
+ let current = file;
127
+ const checked = [];
128
+ let safe = true;
129
+ while (pathContains(root, current)) {
130
+ if (safePaths.has(current)) {
131
+ safe = safePaths.get(current);
132
+ break;
133
+ }
134
+ checked.push(current);
135
+ try {
136
+ const stat = current === file && knownStat ? knownStat : fs.lstatSync(current);
137
+ if (stat.isSymbolicLink()) {
138
+ safe = false;
139
+ break;
140
+ }
141
+ if (current === file && stat.isFile())
142
+ options.fileStats?.set(inputPath, stat);
143
+ }
144
+ catch {
145
+ safe = false;
146
+ break;
147
+ }
148
+ if (current === root)
149
+ break;
150
+ current = path.dirname(current);
151
+ }
152
+ for (const candidate of checked)
153
+ safePaths.set(candidate, safe);
154
+ return safe;
155
+ };
156
+ const scanDirs = options.scope
157
+ ? [path.resolve(cwd, options.scope)]
158
+ : config
159
+ ? config.scanDirs.map(directory => resolveGraphScanDir(cwd, directory))
160
+ : [artifactRoot];
161
+ const extensions = options.scope ? DEFAULT_INDEX_EXTENSIONS : config?.extensions ?? DEFAULT_INDEX_EXTENSIONS;
86
162
  const files = new Set();
163
+ const ignoreRoots = new Set([cwd, ...scanDirs.filter(dir => !pathContains(cwd, dir))]);
87
164
  for (const scanDir of scanDirs) {
88
- for (const file of findArtifactFiles(scanDir, extensions))
165
+ for (const file of findArtifactFiles(scanDir, extensions, acceptPath))
89
166
  files.add(file);
90
167
  }
91
- if (!graph || graph === 'project') {
168
+ if (!options.scope && (!graph || graph === 'project')) {
92
169
  // Additional search roots authorize bundle payloads, not the surrounding
93
170
  // external corpus. Reuse deployment's validated source resolution, including
94
171
  // plugin payloads, and prevent payload symlinks from escaping that boundary.
@@ -96,8 +173,9 @@ export async function collectGraphIndexFiles(cwd, graph) {
96
173
  for (const bundle of bundles) {
97
174
  if (scanDirs.some(scanDir => pathContains(scanDir, bundle.artifactPath)))
98
175
  continue;
99
- const boundary = fs.realpathSync(bundle.artifactPath);
100
- for (const file of walkArtifactFiles(bundle.artifactPath, extensions, new Set(), boundary)) {
176
+ if (!pathContains(cwd, bundle.artifactPath))
177
+ ignoreRoots.add(bundle.artifactPath);
178
+ for (const file of findArtifactFiles(bundle.artifactPath, extensions, acceptPath)) {
101
179
  files.add(file);
102
180
  }
103
181
  }
@@ -107,10 +185,46 @@ export async function collectGraphIndexFiles(cwd, graph) {
107
185
  ...await workspaceLinkedFiles(cwd),
108
186
  ];
109
187
  for (const contextFile of contextFiles) {
110
- if (extensions.some(extension => contextFile.endsWith(extension)))
188
+ if (acceptPath(contextFile) && extensions.some(extension => contextFile.endsWith(extension)))
111
189
  files.add(contextFile);
112
190
  }
113
191
  }
114
- return [...files];
192
+ let sources = [...files];
193
+ if (!options.includeIgnored) {
194
+ // Many projects ignore the whole artifact root (`.aiwg/`). Honoring that
195
+ // would empty the index, so ignore rules apply only beneath a scan root
196
+ // that is not itself ignored; runtime directories are excluded regardless.
197
+ const exemptRoots = [];
198
+ if (!options.scope) {
199
+ // Sibling roots use the same Git context. Probe them together without
200
+ // merging external roots or changing which ignored roots are exempt.
201
+ const byParent = new Map();
202
+ for (const dir of scanDirs.filter(dir => fs.existsSync(dir))) {
203
+ const parent = path.dirname(dir);
204
+ const siblings = byParent.get(parent) ?? [];
205
+ siblings.push(dir);
206
+ byParent.set(parent, siblings);
207
+ }
208
+ for (const [parent, siblings] of byParent) {
209
+ const kept = new Set(dropGitignored(parent, siblings));
210
+ exemptRoots.push(...siblings.filter(dir => !kept.has(dir)));
211
+ }
212
+ }
213
+ const isExempt = (file) => exemptRoots.some(dir => pathContains(dir, file));
214
+ // Git rejects paths outside its worktree. Filter authorized external roots
215
+ // separately so they cannot disable ignore filtering for local sources.
216
+ for (const root of ignoreRoots) {
217
+ const candidates = sources.filter(file => pathContains(root, file) && !isExempt(file));
218
+ const kept = new Set(dropGitignored(root, candidates));
219
+ sources = sources.filter(file => !pathContains(root, file) || isExempt(file) || kept.has(file));
220
+ }
221
+ }
222
+ if (options.fileStats) {
223
+ const selected = new Set(sources);
224
+ for (const file of options.fileStats.keys())
225
+ if (!selected.has(file))
226
+ options.fileStats.delete(file);
227
+ }
228
+ return sources;
115
229
  }
116
230
  //# sourceMappingURL=index-files.js.map
@@ -0,0 +1,130 @@
1
+ /** Bounded artifact-local preparation; ordered graph reduction stays in index-builder. */
2
+ import os from 'node:os';
3
+ import { fork } from 'node:child_process';
4
+ import { signalChild } from '../process/signal-child.mjs';
5
+ const MIB = 1024 ** 2;
6
+ const WORKER_HEAP_MB = 256;
7
+ // Leave room for V8's young generation, executable code, IPC and native allocations.
8
+ const WORKER_BUDGET_BYTES = 512 * MIB;
9
+ // Parsing and metadata extraction amplify input size; do large files only after the pool exits.
10
+ const MAX_WORKER_ARTIFACT_BYTES = MIB;
11
+ export function resolveIndexWorkers(requested, env = process.env) {
12
+ const value = requested ?? env.AIWG_INDEX_WORKERS;
13
+ if (requested === undefined && (value === undefined || value === ''))
14
+ return undefined;
15
+ if ((typeof value === 'string' && !/^\d+$/.test(value))
16
+ || !Number.isSafeInteger(Number(value)) || Number(value) < 0) {
17
+ throw new Error(`${requested === undefined ? 'AIWG_INDEX_WORKERS' : '--index-workers'} must be a nonnegative safe integer (0 = serial)`);
18
+ }
19
+ return Number(value);
20
+ }
21
+ export function indexPreparationWorkers(jobs, requested, cores = os.availableParallelism(), memory = Math.min(os.freemem(), process.availableMemory?.() ?? Infinity), totalBytes = 0) {
22
+ requested = resolveIndexWorkers(requested);
23
+ if (jobs < 64 || cores < 3 || requested === 0 || requested === 1)
24
+ return 0;
25
+ // Process startup costs dominate lightweight scans even at thousands of files.
26
+ // Explicit requests bypass only this conservative automatic workload gate.
27
+ if (requested === undefined && (jobs < 1000 || !Number.isFinite(totalBytes) || totalBytes < 16 * MIB))
28
+ return 0;
29
+ const byMemory = Math.floor((memory - 512 * MIB) / WORKER_BUDGET_BYTES);
30
+ const bounded = Math.max(0, Math.min(requested ?? 4, 4, cores - 1, byMemory, jobs));
31
+ return bounded >= 2 ? bounded : 0;
32
+ }
33
+ export async function runIndexPreparation(jobs, serial, moduleUrl, requested, onDiagnostic) {
34
+ const diagnostics = [];
35
+ const diagnose = (message) => { diagnostics.push(message); onDiagnostic?.(message); };
36
+ const eligible = jobs.map((job, index) => ({ job, index })).filter(({ job }) => Number.isFinite(job.sizeBytes) && job.sizeBytes >= 0 && job.sizeBytes <= MAX_WORKER_ARTIFACT_BYTES);
37
+ const workerCount = indexPreparationWorkers(eligible.length, requested, undefined, undefined, eligible.reduce((total, { job }) => total + job.sizeBytes, 0));
38
+ if (!workerCount)
39
+ return { results: jobs.map(serial), workerCount: 0, diagnostics };
40
+ const results = new Array(jobs.length), workers = [];
41
+ const closed = [];
42
+ let next = 0, completed = 0, stopped = false;
43
+ try {
44
+ await new Promise((resolve, reject) => {
45
+ // Stop dispatch on a process failure. Reap the entire pool before retrying
46
+ // unfinished work in the main isolate, avoiding overlapping memory peaks.
47
+ const recover = (message) => {
48
+ if (stopped)
49
+ return;
50
+ stopped = true;
51
+ diagnose(`${message}; retrying unfinished preparation serially`);
52
+ resolve();
53
+ };
54
+ const dispatch = (worker) => {
55
+ if (stopped || next >= eligible.length)
56
+ return;
57
+ const { index, job } = eligible[next++];
58
+ try {
59
+ worker.send({ index, job }, error => { if (error)
60
+ recover(`Index preparation IPC failed for ${job.relativePath}: ${error.message}`); });
61
+ }
62
+ catch (error) {
63
+ recover(`Index preparation IPC failed for ${job.relativePath}: ${error instanceof Error ? error.message : String(error)}`);
64
+ }
65
+ };
66
+ for (let index = 0; index < workerCount && !stopped; index++) {
67
+ // A worker_threads resourceLimit is not a process boundary: V8 can abort
68
+ // Node during allocation before its isolate-limit error is delivered.
69
+ // A child heap fatal/SIGABRT is instead an ordinary, recoverable exit.
70
+ const worker = fork(new URL('./index-worker.mjs', import.meta.url), [moduleUrl], {
71
+ execArgv: [`--max-old-space-size=${WORKER_HEAP_MB}`, '--max-semi-space-size=16'],
72
+ stdio: ['ignore', 'ignore', 'pipe', 'ipc'], serialization: 'advanced',
73
+ });
74
+ workers.push(worker);
75
+ closed.push(new Promise(done => worker.once('close', () => done())));
76
+ let stderr = '';
77
+ let activePath = '<startup>';
78
+ worker.stderr?.on('data', chunk => { stderr = (stderr + String(chunk)).slice(-8192); });
79
+ worker.on('error', error => recover(`Index preparation worker failed for ${activePath}: ${error.message}`));
80
+ worker.on('exit', (code, signal) => {
81
+ const oom = /heap out of memory|ERR_WORKER_OUT_OF_MEMORY/i.test(stderr) ? ' (heap out of memory)' : '';
82
+ recover(`Index preparation worker exited early for ${activePath} (${signal ?? code})${oom}`);
83
+ });
84
+ worker.on('message', (message) => {
85
+ if (stopped)
86
+ return;
87
+ if (message.error) {
88
+ stopped = true;
89
+ reject(new Error(message.error));
90
+ return;
91
+ }
92
+ results[message.index] = message.result;
93
+ completed++;
94
+ if (completed === eligible.length) {
95
+ stopped = true;
96
+ resolve();
97
+ }
98
+ else {
99
+ activePath = eligible[next]?.job.relativePath ?? '<idle>';
100
+ dispatch(worker);
101
+ }
102
+ });
103
+ activePath = eligible[next]?.job.relativePath ?? '<idle>';
104
+ dispatch(worker);
105
+ }
106
+ });
107
+ }
108
+ finally {
109
+ stopped = true;
110
+ for (const worker of workers)
111
+ if (worker.exitCode === null && worker.signalCode === null)
112
+ signalChild(worker, 'SIGKILL');
113
+ await Promise.all(closed);
114
+ }
115
+ const largeCount = jobs.length - eligible.length;
116
+ if (largeCount)
117
+ diagnose(`${largeCount} artifact(s) above the worker size threshold prepared serially`);
118
+ for (let index = 0; index < jobs.length; index++) {
119
+ if (!results[index]) {
120
+ try {
121
+ results[index] = serial(jobs[index]);
122
+ }
123
+ catch (error) {
124
+ throw new Error(`${jobs[index].relativePath}: ${error instanceof Error ? error.message : String(error)}`);
125
+ }
126
+ }
127
+ }
128
+ return { results, workerCount, diagnostics };
129
+ }
130
+ //# sourceMappingURL=index-preparation.js.map