@aiwg/cli 2026.10.4 → 2026.10.6

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 (220) hide show
  1. package/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
  2. package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
  3. package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
  4. package/agentic/code/providers/model-capabilities.v1.json +74 -50
  5. package/bin/aiwg.mjs +3 -1
  6. package/dist/src/artifacts/browser-export.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +8 -1
  8. package/dist/src/artifacts/cli.js +72 -9
  9. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  10. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  11. package/dist/src/artifacts/graph-query.js +18 -8
  12. package/dist/src/artifacts/index-adapters.js +339 -0
  13. package/dist/src/artifacts/index-builder.js +146 -16
  14. package/dist/src/artifacts/index-files.js +15 -4
  15. package/dist/src/artifacts/index-preparation.js +91 -26
  16. package/dist/src/artifacts/index-reader.js +44 -0
  17. package/dist/src/artifacts/index-refresh.js +130 -56
  18. package/dist/src/artifacts/index-status.js +20 -5
  19. package/dist/src/artifacts/index-worker.mjs +9 -7
  20. package/dist/src/artifacts/memory-maintenance.js +503 -0
  21. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  22. package/dist/src/artifacts/query-engine.js +263 -108
  23. package/dist/src/artifacts/relations-builder.js +2 -2
  24. package/dist/src/artifacts/source-graph.js +2 -2
  25. package/dist/src/artifacts/types.js +9 -1
  26. package/dist/src/cli/handlers/decision.js +19 -1
  27. package/dist/src/cli/handlers/guided-setup.js +470 -0
  28. package/dist/src/cli/handlers/help.js +2 -2
  29. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  30. package/dist/src/cli/handlers/index.js +4 -2
  31. package/dist/src/cli/handlers/init.js +41 -6
  32. package/dist/src/cli/handlers/local-executor.js +5 -3
  33. package/dist/src/cli/handlers/mc.js +509 -53
  34. package/dist/src/cli/handlers/models.js +32 -2
  35. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  36. package/dist/src/cli/handlers/rules.js +1 -1
  37. package/dist/src/cli/handlers/script-runner.js +73 -2
  38. package/dist/src/cli/handlers/serve.js +5 -3
  39. package/dist/src/cli/handlers/sessions.js +40 -6
  40. package/dist/src/cli/handlers/setup.js +428 -1
  41. package/dist/src/cli/handlers/skill-lint.js +1 -1
  42. package/dist/src/cli/handlers/subcommands.js +118 -8
  43. package/dist/src/cli/handlers/use.js +279 -93
  44. package/dist/src/cli/handlers/workspace.js +3 -1
  45. package/dist/src/cli/prompt-utils.js +8 -0
  46. package/dist/src/cli/router.js +16 -1
  47. package/dist/src/config/aiwg-config.js +42 -0
  48. package/dist/src/config/cli.js +7 -3
  49. package/dist/src/config/decision-config.js +14 -1
  50. package/dist/src/config/native-sandbox-warnings.js +25 -0
  51. package/dist/src/contributors/validation.js +6 -5
  52. package/dist/src/decision/admission.js +7 -3
  53. package/dist/src/decision/benchmark.js +469 -0
  54. package/dist/src/decision/ledger.js +22 -3
  55. package/dist/src/decision/pricing.js +147 -0
  56. package/dist/src/decision/qualification/gate-evidence.js +18 -15
  57. package/dist/src/decision/qualification/load-staged.js +539 -0
  58. package/dist/src/decision/qualification/load.js +109 -33
  59. package/dist/src/decision/qualification/runner.js +5 -2
  60. package/dist/src/decision/review/service.js +6 -4
  61. package/dist/src/decision/review/validate.js +23 -2
  62. package/dist/src/decision/savings.js +8 -3
  63. package/dist/src/discovery/index.js +492 -0
  64. package/dist/src/discovery/interview.js +233 -0
  65. package/dist/src/discovery/plan-apply.js +571 -0
  66. package/dist/src/discovery/plan-store.js +171 -0
  67. package/dist/src/discovery/plan-types.js +2 -0
  68. package/dist/src/discovery/plan-validation.js +139 -0
  69. package/dist/src/discovery/types.js +2 -0
  70. package/dist/src/extensions/commands/definitions.js +49 -9
  71. package/dist/src/extensions/manifest.js +71 -44
  72. package/dist/src/extensions/project-local-discovery.js +1 -1
  73. package/dist/src/extensions/project-quickref.js +18 -17
  74. package/dist/src/extensions/validation.js +32 -29
  75. package/dist/src/housekeeper/daemon-config.js +148 -0
  76. package/dist/src/housekeeper/ipc.js +84 -0
  77. package/dist/src/housekeeper/lifecycle.js +148 -0
  78. package/dist/src/housekeeper/platform.js +35 -0
  79. package/dist/src/housekeeper/status.js +70 -0
  80. package/dist/src/housekeeper/units.js +114 -0
  81. package/dist/src/jobs/flow.js +22 -21
  82. package/dist/src/lint/rule-activation.js +20 -5
  83. package/dist/src/lint/runner.js +1 -1
  84. package/dist/src/mcp/cli.mjs +5 -6
  85. package/dist/src/mcp/config-file.mjs +6 -2
  86. package/dist/src/mcp/config-layers.mjs +23 -7
  87. package/dist/src/mcp/profiles.js +18 -31
  88. package/dist/src/mcp/profiles.mjs +18 -32
  89. package/dist/src/mcp/registry.js +7 -27
  90. package/dist/src/mcp/registry.mjs +7 -28
  91. package/dist/src/mcp/server.mjs +34 -1
  92. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  93. package/dist/src/mcp/tools/command-run.mjs +3 -2
  94. package/dist/src/mcp/tools/decision.mjs +49 -48
  95. package/dist/src/mcp/tools/discovery.mjs +46 -21
  96. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  97. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  98. package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
  99. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  100. package/dist/src/memory/audit.js +719 -0
  101. package/dist/src/memory/canonical-context.js +392 -13
  102. package/dist/src/memory/canonical-maintenance.js +95 -0
  103. package/dist/src/memory/cli-result.js +22 -0
  104. package/dist/src/memory/cli.js +176 -0
  105. package/dist/src/memory/context-pack.js +57 -6
  106. package/dist/src/memory/cost.js +512 -0
  107. package/dist/src/memory/firewall-classification.d.mts +7 -0
  108. package/dist/src/memory/firewall-classification.mjs +32 -0
  109. package/dist/src/memory/index.js +8 -0
  110. package/dist/src/memory/line-maintenance.js +68 -0
  111. package/dist/src/memory/maintenance-cli.js +286 -0
  112. package/dist/src/memory/maintenance-contract.js +136 -0
  113. package/dist/src/memory/maintenance-index.js +18 -0
  114. package/dist/src/memory/maintenance-owner.js +2 -0
  115. package/dist/src/memory/maintenance-record.js +138 -0
  116. package/dist/src/memory/maintenance.js +254 -0
  117. package/dist/src/memory/provider-memory-adapter.js +154 -0
  118. package/dist/src/memory/recommend-cli.js +83 -0
  119. package/dist/src/memory/recommend.js +269 -0
  120. package/dist/src/memory/scheduled.js +81 -0
  121. package/dist/src/memory/taxonomy.js +44 -0
  122. package/dist/src/mission-protocol/codecs.js +19 -9
  123. package/dist/src/models/config-loader.js +11 -1
  124. package/dist/src/models/model-capabilities.v1.json +74 -50
  125. package/dist/src/models/provider-policy.js +125 -62
  126. package/dist/src/models/resolver.js +45 -8
  127. package/dist/src/models/worker-installation.d.mts +7 -0
  128. package/dist/src/models/worker-installation.mjs +169 -37
  129. package/dist/src/models/wrapper-route.js +1 -1
  130. package/dist/src/output-modes/registry.js +8 -7
  131. package/dist/src/plugin/metadata-validator.js +1 -1
  132. package/dist/src/providers/deploy-version.d.mts +1 -0
  133. package/dist/src/providers/deploy-version.mjs +17 -0
  134. package/dist/src/providers/provider-definitions.js +19 -16
  135. package/dist/src/providers/skill-ownership.d.mts +11 -2
  136. package/dist/src/providers/skill-ownership.mjs +35 -17
  137. package/dist/src/rules/activation.d.mts +11 -2
  138. package/dist/src/rules/activation.mjs +82 -6
  139. package/dist/src/rules/inventory.js +1 -1
  140. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  141. package/dist/src/schema/zod-validation.d.mts +6 -0
  142. package/dist/src/schema/zod-validation.mjs +50 -0
  143. package/dist/src/serve/executor-registry.js +297 -20
  144. package/dist/src/serve/executor-token.d.mts +1 -0
  145. package/dist/src/serve/executor-token.mjs +8 -0
  146. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  147. package/dist/src/serve/worker-invocation.js +114 -15
  148. package/dist/src/sessions/adapters/claude.js +19 -18
  149. package/dist/src/sessions/adapters/codex.js +33 -19
  150. package/dist/src/sessions/adapters/copilot.js +14 -13
  151. package/dist/src/sessions/adapters/cursor.js +19 -18
  152. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  153. package/dist/src/sessions/adapters/factory.js +11 -10
  154. package/dist/src/sessions/adapters/generic.js +32 -23
  155. package/dist/src/sessions/adapters/grokbot.js +35 -35
  156. package/dist/src/sessions/adapters/hermes.js +20 -19
  157. package/dist/src/sessions/adapters/muse.js +50 -49
  158. package/dist/src/sessions/adapters/omp.js +5 -4
  159. package/dist/src/sessions/adapters/openclaw.js +30 -29
  160. package/dist/src/sessions/adapters/opencode.js +26 -26
  161. package/dist/src/sessions/adapters/openhuman.js +24 -23
  162. package/dist/src/sessions/adapters/pi.js +5 -4
  163. package/dist/src/sessions/adapters/windsurf.js +8 -8
  164. package/dist/src/sessions/analytics.js +10 -9
  165. package/dist/src/sessions/batch-contracts.js +1 -1
  166. package/dist/src/sessions/batch-import.js +202 -2
  167. package/dist/src/sessions/candidates.js +7 -6
  168. package/dist/src/sessions/contracts.js +73 -54
  169. package/dist/src/sessions/coverage-preflight.js +26 -1
  170. package/dist/src/sessions/output-registration.js +11 -10
  171. package/dist/src/sessions/policy.js +18 -7
  172. package/dist/src/sessions/refresh.js +2 -3
  173. package/dist/src/sessions/repository.js +4 -2
  174. package/dist/src/sessions/workspace-discovery.js +92 -26
  175. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  176. package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
  177. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  178. package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
  179. package/dist/src/update/checker.d.mts +4 -0
  180. package/dist/src/update/checker.mjs +14 -0
  181. package/dist/src/writing/exemplar-selection.js +6 -6
  182. package/dist/src/writing/voice-evaluation.js +24 -23
  183. package/dist/src/writing/writer-migration.js +14 -13
  184. package/dist/src/writing/writer-profile.js +19 -18
  185. package/dist/src/writing/writing-brief.js +18 -17
  186. package/dist/src/writing/writing-receipt.js +47 -46
  187. package/package.json +5 -2
  188. package/schemas/decision/DecisionReview.schema.json +78 -1
  189. package/schemas/mission-v1.schema.json +3 -0
  190. package/tools/agents/deploy-agents.mjs +67 -39
  191. package/tools/agents/providers/antigravity.mjs +6 -1
  192. package/tools/agents/providers/base.mjs +19 -13
  193. package/tools/agents/providers/claude.mjs +1 -1
  194. package/tools/agents/providers/codex.mjs +50 -56
  195. package/tools/agents/providers/copilot.mjs +8 -2
  196. package/tools/agents/providers/cursor.mjs +1 -1
  197. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  198. package/tools/agents/providers/factory.mjs +7 -1
  199. package/tools/agents/providers/grok-build.mjs +18 -2
  200. package/tools/agents/providers/grokbot.mjs +1 -1
  201. package/tools/agents/providers/hermes.mjs +7 -13
  202. package/tools/agents/providers/muse-hooks.mjs +21 -14
  203. package/tools/agents/providers/muse.mjs +7 -2
  204. package/tools/agents/providers/omp.mjs +28 -4
  205. package/tools/agents/providers/opencode.mjs +14 -5
  206. package/tools/agents/providers/openhuman.mjs +1 -1
  207. package/tools/agents/providers/pi.mjs +1 -1
  208. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  209. package/tools/agents/providers/rule-delivery.mjs +263 -71
  210. package/tools/agents/providers/windsurf.mjs +7 -0
  211. package/tools/cli/workspace-status.mjs +5 -0
  212. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  213. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  214. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  215. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  216. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  217. package/tools/ralph-external/process-monitor.mjs +7 -4
  218. package/tools/ralph-external/session-launcher.mjs +280 -32
  219. package/tools/skills/deploy-skills-codex.mjs +11 -7
  220. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -20,6 +20,7 @@ import path from 'node:path';
20
20
  import { readFileSync } from 'node:fs';
21
21
  import { fileURLToPath } from 'node:url';
22
22
  import { GRAPH_CONFIGS, OPERATIONAL_DISCOVERY_TYPES, OPERATIONAL_SHOW_TYPES, isOperationalShowType, loadUserGraphConfigs, loadGlobalGraphConfigs, orderedGraphEntries, } from './types.js';
23
+ import { resolveIndexWorkers } from './index-preparation.js';
23
24
  import { SUPPORTED_VIEWS } from './corpus-views/renderers.js';
24
25
  import { parseResourceSelector, readVerifiedRegularFile, } from '../resources/web-release.js';
25
26
  import { findPackageRoot } from '../cli/find-package-root.js';
@@ -328,10 +329,12 @@ export function printIndexUsage() {
328
329
  console.log(' build [--force] [--verbose] [--all] [--scope <dir>] [--graph <name>]');
329
330
  console.log(' refresh [--full] [--workspace <path>]... [--root <dir>]...');
330
331
  console.log(' [--only graphs|sessions|caches|runtime|models|issues] [--dry-run] [--json] [--lock-wait-ms <n>]');
332
+ console.log(' --only also accepts a registered index name (for example project) or all.');
331
333
  console.log(' [--max-record-bytes <n>] [--max-source-bytes <n>]');
332
334
  console.log(' Session import defaults: 67108864 bytes per record, 1073741824 bytes (1 GiB) per source; source 0 is unlimited.');
333
335
  console.log(' --exclude <id-or-glob> (repeatable): skip session IDs or absolute path globs; adds to sessions.import.exclude and AIWG_SESSIONS_IMPORT_EXCLUDE (comma-separated).');
334
336
  console.log(' Import limits: CLI flag > AIWG_SESSIONS_IMPORT_MAX_RECORD_BYTES / AIWG_SESSIONS_IMPORT_MAX_SOURCE_BYTES > workspace config > default.');
337
+ console.log(' build/refresh --index-workers <n>: preparation processes (0 = serial); flag > AIWG_INDEX_WORKERS > automatic CPU/memory limits.');
335
338
  console.log(' sync [--backend fortemi-core] [--graph <name> | --all] [--repo <name>]');
336
339
  console.log(' [--privacy private|sanitized|public] [--generated-at <iso>] [--json]');
337
340
  console.log(' --graph <name> Target a specific graph (framework, project, codebase, source, user, or user-defined)');
@@ -503,6 +506,7 @@ async function handleBuild(args) {
503
506
  console.log('Usage: aiwg index build [options]');
504
507
  console.log('');
505
508
  console.log('Options:');
509
+ console.log(' --index-workers <n> Preparation processes (0 = serial); overrides AIWG_INDEX_WORKERS');
506
510
  console.log(' --force Full rebuild (ignore checksums, re-index everything)');
507
511
  console.log(' --verbose Show detailed progress during indexing');
508
512
  console.log(' --all Build all known graphs (including user-defined)');
@@ -530,6 +534,15 @@ async function handleBuild(args) {
530
534
  console.log(' aiwg index sync --all');
531
535
  return;
532
536
  }
537
+ let workers;
538
+ try {
539
+ workers = resolveIndexWorkers(parseFlagValue(args, '--index-workers', 'Error: --index-workers requires a value'));
540
+ }
541
+ catch (error) {
542
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
543
+ process.exitCode = 1;
544
+ return;
545
+ }
533
546
  // Dynamic import to keep the CLI router lightweight
534
547
  const { buildIndex } = await import('./index-builder.js');
535
548
  const cwd = process.cwd();
@@ -554,7 +567,7 @@ async function handleBuild(args) {
554
567
  // --graph X: build the JSON graph if X is one; otherwise X may be a
555
568
  // research-corpus markdown view, rendered below.
556
569
  if (graph in GRAPH_CONFIGS) {
557
- await buildIndex(cwd, { force, verbose, scope, includeIgnored, graph, explicit: true });
570
+ await buildIndex(cwd, { force, verbose, scope, includeIgnored, workers, graph, explicit: true });
558
571
  jsonBuilt = true;
559
572
  builtGraphs.add(graph);
560
573
  }
@@ -562,7 +575,7 @@ async function handleBuild(args) {
562
575
  else if (all) {
563
576
  // Build all known graphs — user asked for everything, but don't hard-error on missing dirs
564
577
  for (const [name] of orderedGraphEntries(Object.entries(GRAPH_CONFIGS))) {
565
- await buildIndex(cwd, { force, verbose, includeIgnored, graph: name, explicit: false });
578
+ await buildIndex(cwd, { force, verbose, includeIgnored, workers, graph: name, explicit: false });
566
579
  builtGraphs.add(name);
567
580
  }
568
581
  jsonBuilt = true;
@@ -571,7 +584,7 @@ async function handleBuild(args) {
571
584
  // Default: build graphs with defaultBuild=true; skip gracefully if their dirs don't exist
572
585
  for (const [name, config] of orderedGraphEntries(Object.entries(GRAPH_CONFIGS))) {
573
586
  if (config.defaultBuild) {
574
- await buildIndex(cwd, { force, verbose, includeIgnored, scope: name === Object.keys(GRAPH_CONFIGS)[0] ? scope : undefined, graph: name, explicit: false });
587
+ await buildIndex(cwd, { force, verbose, includeIgnored, workers, scope: name === Object.keys(GRAPH_CONFIGS)[0] ? scope : undefined, graph: name, explicit: false });
575
588
  builtGraphs.add(name);
576
589
  }
577
590
  }
@@ -1073,6 +1086,21 @@ async function handleExport(args) {
1073
1086
  process.exit(1);
1074
1087
  }
1075
1088
  }
1089
+ function warnSyncTextQuality(manifest) {
1090
+ const quality = manifest.text_quality;
1091
+ if (!quality?.degenerate)
1092
+ return;
1093
+ const config = GRAPH_CONFIGS[manifest.graph];
1094
+ const source = config
1095
+ ? ` Source: ${config.scanDirs.join(', ')} (nodeStrategy: ${config.nodeStrategy ?? 'default'}).`
1096
+ : '';
1097
+ if (manifest.item_count === 0) {
1098
+ console.warn(`Warning: graph '${manifest.graph}' contains no indexed items; this graph cannot return results.${source}`);
1099
+ return;
1100
+ }
1101
+ const percent = Math.round(quality.short_text_count / manifest.item_count * 100);
1102
+ console.warn(`Warning: graph '${manifest.graph}': ${quality.short_text_count}/${manifest.item_count} items (${percent}%) have <${quality.short_text_threshold_chars} chars of indexed text; ${quality.filename_title_count} have a filename as title. This graph may return poor results. Check source content and extracted text sidecars.${source}`);
1103
+ }
1076
1104
  /**
1077
1105
  * Handle 'index sync' command
1078
1106
  */
@@ -1142,6 +1170,7 @@ async function handleSync(args) {
1142
1170
  console.log(`Fortemi Core sync: ${manifests.length} graph(s) succeeded, ${failures.length} failed`);
1143
1171
  for (const manifest of manifests) {
1144
1172
  console.log(` ${manifest.graph}: ${manifest.status}, ${manifest.item_count} item(s) → ${manifest.export_path}`);
1173
+ warnSyncTextQuality(manifest);
1145
1174
  }
1146
1175
  for (const failure of failures) {
1147
1176
  console.error(` ${failure.graph}: failed — ${failure.error}`);
@@ -1157,6 +1186,7 @@ async function handleSync(args) {
1157
1186
  return;
1158
1187
  }
1159
1188
  console.log(`Fortemi Core ${manifest.status}: ${manifest.item_count} item(s) → ${manifest.export_path}`);
1189
+ warnSyncTextQuality(manifest);
1160
1190
  }
1161
1191
  catch (err) {
1162
1192
  console.error('Error: ' + (err instanceof Error ? err.message : String(err)));
@@ -1288,7 +1318,7 @@ async function handleStats(args) {
1288
1318
  */
1289
1319
  async function handleStatus(args) {
1290
1320
  if (args.includes('--help') || args.includes('-h')) {
1291
- console.log('Usage: aiwg index status [--json]');
1321
+ console.log('Usage: aiwg index status [--only <name|all>] [--json]');
1292
1322
  console.log(' aiwg index list [--json] (alias)');
1293
1323
  console.log('');
1294
1324
  console.log('Enumerate every registered index graph (built-in + module + operator)');
@@ -1302,7 +1332,10 @@ async function handleStatus(args) {
1302
1332
  return;
1303
1333
  }
1304
1334
  const { showIndexStatus } = await import('./index-status.js');
1305
- await showIndexStatus(process.cwd(), { json: args.includes('--json') });
1335
+ const onlyAt = args.indexOf('--only');
1336
+ if (onlyAt >= 0 && (!args[onlyAt + 1] || args[onlyAt + 1].startsWith('--')))
1337
+ throw new Error('--only requires an index name');
1338
+ await showIndexStatus(process.cwd(), { json: args.includes('--json'), only: onlyAt >= 0 ? args[onlyAt + 1] : undefined });
1306
1339
  }
1307
1340
  /**
1308
1341
  * Handle 'index neighbors' command
@@ -1510,7 +1543,7 @@ async function handleDiscover(args) {
1510
1543
  });
1511
1544
  }
1512
1545
  /**
1513
- * Handle 'index show' command — print the full text of a specific
1546
+ * Handle 'index show' command — show the metadata card of a specific
1514
1547
  * artifact by type and name.
1515
1548
  *
1516
1549
  * Shape (#1218):
@@ -1519,9 +1552,31 @@ async function handleDiscover(args) {
1519
1552
  * Type is positional (not a flag) so the verb reads as
1520
1553
  * "show <kind> <name>". `<type>` is one of the operational show types.
1521
1554
  *
1522
- * Companion to `discover`: where discover ranks candidates, show fetches
1523
- * the artifact body so consumers don't need to navigate the filesystem.
1555
+ * Companion to `discover`: where discover ranks candidates, show returns
1556
+ * a metadata card with section/body drill-ins so consumers don't need to navigate the filesystem.
1524
1557
  */
1558
+ const SHOW_FLAGS = new Set(['--json', '--first', '--bound-rule-bodies', '--graph', '--backend', '--resource-source',
1559
+ '--aiwg-version', '--offline', '--body', '--section', '--rules', '--with-rule-bodies', '--resources', '--resource',
1560
+ '--help']);
1561
+ // Section headings can themselves start with `--` (e.g. "--max-iterations (default: 10)"), and the card
1562
+ // tells agents to pass them verbatim. Only a missing value or another show flag counts as "no value".
1563
+ function showFlagValue(flags, index) {
1564
+ const value = flags[index + 1];
1565
+ if (!value || SHOW_FLAGS.has(value.split('=')[0]))
1566
+ throw new Error(`${flags[index]} requires a value`);
1567
+ return value;
1568
+ }
1569
+ /** Values for a repeatable value flag, accepting both `--flag value` and `--flag=value`. */
1570
+ function showFlagValues(flags, name) {
1571
+ const values = [];
1572
+ for (let i = 0; i < flags.length; i++) {
1573
+ if (flags[i] === name)
1574
+ values.push(showFlagValue(flags, i));
1575
+ else if (flags[i].startsWith(`${name}=`))
1576
+ values.push(flags[i].slice(name.length + 1));
1577
+ }
1578
+ return values;
1579
+ }
1525
1580
  async function handleShow(args) {
1526
1581
  const { showArtifact, showMetadata } = await import('./query-engine.js');
1527
1582
  const cwd = process.cwd();
@@ -1555,9 +1610,11 @@ async function handleShow(args) {
1555
1610
  ' aiwg show command discover',
1556
1611
  ' aiwg show skill intake-wizard --resource-source web --aiwg-version stable',
1557
1612
  '',
1613
+ 'Default: metadata card. --body restores full output; --section <heading> is repeatable.',
1614
+ '--rules [--with-rule-bodies] | --resources | --resource <path>',
1558
1615
  'Bound rules: summaries and show pointers are appended for bound skills, agents, and flows.',
1559
1616
  'Fetch and follow every required_rule_checks entry before starting governed work; summaries do not replace full rules.',
1560
- 'Use --bound-rule-bodies to include their full text (JSON: bound_rules[].content).',
1617
+ 'Use --rules --with-rule-bodies to include their full text (legacy alias: --bound-rule-bodies).',
1561
1618
  '',
1562
1619
  'Tip: use `aiwg discover "<phrase>" --json` first to find the stable id.',
1563
1620
  ].join('\n');
@@ -1623,6 +1680,12 @@ async function handleShow(args) {
1623
1680
  const params = {
1624
1681
  name,
1625
1682
  boundRuleBodies: flags.includes('--bound-rule-bodies'),
1683
+ body: flags.includes('--body'),
1684
+ sections: showFlagValues(flags, '--section'),
1685
+ rules: flags.includes('--rules'),
1686
+ withRuleBodies: flags.includes('--with-rule-bodies'),
1687
+ resources: flags.includes('--resources'),
1688
+ resource: showFlagValues(flags, '--resource')[0],
1626
1689
  typeFilter: type ? [type] : undefined,
1627
1690
  json,
1628
1691
  first,
@@ -244,6 +244,8 @@ function entryFromRecord(record) {
244
244
  const indexedScript = indexedFrontmatter.aiwg_script;
245
245
  return {
246
246
  path: record.source.path,
247
+ ...(indexedFrontmatter.aiwg_memory_record && typeof indexedFrontmatter.aiwg_memory_record === 'object'
248
+ ? { memoryRecord: indexedFrontmatter.aiwg_memory_record } : {}),
247
249
  type: artifactTypeFromRecord(record),
248
250
  kind: typeof indexedFrontmatter.aiwg_kind === "string"
249
251
  ? indexedFrontmatter.aiwg_kind
@@ -5,9 +5,9 @@ import { fileURLToPath } from "node:url";
5
5
  import { parse as parseYaml } from "yaml";
6
6
  import { GRAPH_CONFIGS, getProjectIndexRoot, loadGlobalGraphConfigs } from "./types.js";
7
7
  import { buildAiwgFortemiIndexExport, } from "./browser-export.js";
8
- import { loadGraphIndexFile } from "./index-reader.js";
8
+ import { loadGraphIndexFile, publishIndexFiles } from "./index-reader.js";
9
9
  import { getFrameworkIndexBaseDir } from './framework-index-paths.js';
10
- function syncDir(cwd, graph) {
10
+ export function getFortemiCoreIndexDir(cwd, graph) {
11
11
  loadGlobalGraphConfigs();
12
12
  if (graph === 'framework')
13
13
  return path.join(getFrameworkIndexBaseDir(cwd), 'fortemi-core', graph);
@@ -180,14 +180,15 @@ function writeExport(file, exported, maxChars) {
180
180
  }
181
181
  export function syncFortemiCoreIndex(cwd, options = {}) {
182
182
  const graph = options.graph ?? "project";
183
- const dir = syncDir(cwd, graph);
183
+ const dir = getFortemiCoreIndexDir(cwd, graph);
184
184
  const exportPath = path.join(dir, "aiwg-fortemi-index-v2.json");
185
185
  const manifestPath = path.join(dir, "manifest.json");
186
186
  const maxChars = options.maxChunkChars ?? 64 * 1024;
187
187
  if (!Number.isSafeInteger(maxChars) || maxChars < 64)
188
188
  throw new Error("maxChunkChars must be an integer of at least 64");
189
189
  fs.mkdirSync(dir, { recursive: true });
190
- const temporaryPath = path.join(dir, `.export-${randomUUID()}.tmp`);
190
+ const staging = fs.mkdtempSync(path.join(dir, ".sync-"));
191
+ const temporaryPath = path.join(staging, `.export-${randomUUID()}.tmp`);
191
192
  const previous = readManifest(manifestPath);
192
193
  const sourceBuiltAt = sourceIndexBuiltAt(cwd, graph);
193
194
  const buildExport = (generatedAt) => {
@@ -200,10 +201,25 @@ export function syncFortemiCoreIndex(cwd, options = {}) {
200
201
  });
201
202
  const checksum = writeExport(temporaryPath, exported, maxChars);
202
203
  const recordsWithConcepts = exported.items.filter((item) => (item.skos_concepts?.length ?? 0) > 0).length;
204
+ const shortTextThreshold = 200;
205
+ let shortTextCount = 0;
206
+ let filenameTitleCount = 0;
207
+ for (const item of exported.items) {
208
+ if (item.text.trim().length < shortTextThreshold)
209
+ shortTextCount++;
210
+ if (item.title.trim() === path.posix.basename(item.source.path))
211
+ filenameTitleCount++;
212
+ }
203
213
  return {
204
214
  generatedAt,
205
215
  checksum,
206
216
  itemCount: exported.items.length,
217
+ textQuality: {
218
+ short_text_threshold_chars: shortTextThreshold,
219
+ short_text_count: shortTextCount,
220
+ filename_title_count: filenameTitleCount,
221
+ degenerate: exported.items.length === 0 || shortTextCount / exported.items.length >= 0.8,
222
+ },
207
223
  skosCoverage: {
208
224
  records_with_concepts: recordsWithConcepts,
209
225
  total_records: exported.items.length,
@@ -228,7 +244,7 @@ export function syncFortemiCoreIndex(cwd, options = {}) {
228
244
  }
229
245
  }
230
246
  }
231
- fs.renameSync(temporaryPath, exportPath);
247
+ fs.renameSync(temporaryPath, path.join(staging, path.basename(exportPath)));
232
248
  const manifest = {
233
249
  schema_version: "aiwg.fortemi.core-sync.v1",
234
250
  backend: "fortemi-core",
@@ -238,19 +254,21 @@ export function syncFortemiCoreIndex(cwd, options = {}) {
238
254
  export_schema_version: "aiwg.fortemi.index.export.v2",
239
255
  export_checksum: built.checksum,
240
256
  item_count: built.itemCount,
257
+ text_quality: built.textQuality,
241
258
  skos_coverage: built.skosCoverage,
242
259
  status,
243
260
  source_index_built_at: sourceBuiltAt,
244
261
  };
245
- fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
262
+ fs.writeFileSync(path.join(staging, path.basename(manifestPath)), JSON.stringify(manifest, null, 2) + "\n", "utf-8");
263
+ publishIndexFiles(staging, dir);
246
264
  return manifest;
247
265
  }
248
266
  finally {
249
- fs.rmSync(temporaryPath, { force: true });
267
+ fs.rmSync(staging, { recursive: true, force: true });
250
268
  }
251
269
  }
252
270
  export function getFortemiCoreSyncStatus(cwd, graph = "project") {
253
- const dir = syncDir(cwd, graph);
271
+ const dir = getFortemiCoreIndexDir(cwd, graph);
254
272
  const manifestPath = path.join(dir, "manifest.json");
255
273
  const exportPath = path.join(dir, "aiwg-fortemi-index-v2.json");
256
274
  const { manifest, reason: manifestReadReason } = readManifestResult(manifestPath);
@@ -9,8 +9,17 @@
9
9
  * @tests @test/unit/artifacts/graph-query.test.ts
10
10
  */
11
11
  import { normalizeEdges } from './types.js';
12
- import { buildFortemiCoreDependencyGraph } from './fortemi-core-query-adapter.js';
12
+ import { buildFortemiCoreDependencyGraph, loadFortemiCoreMetadataEntries } from './fortemi-core-query-adapter.js';
13
13
  import { closeGraphBackend, openGraphBackend } from './backend-runtime.js';
14
+ import { loadGraphIndexFile } from './index-reader.js';
15
+ import { isOrdinaryMemoryEntry } from './query-engine.js';
16
+ function graphMemoryMetadata(cwd, graph, backend) {
17
+ const local = loadGraphIndexFile(cwd, 'metadata.json', graph)?.entries ?? {};
18
+ if (backend === 'fortemi-core') {
19
+ return { ...Object.fromEntries(loadFortemiCoreMetadataEntries(cwd, graph).entries.map(entry => [entry.path, entry])), ...local };
20
+ }
21
+ return local;
22
+ }
14
23
  /**
15
24
  * Get neighbors of a node in a dependency graph.
16
25
  *
@@ -20,15 +29,15 @@ import { closeGraphBackend, openGraphBackend } from './backend-runtime.js';
20
29
  * @param edgeType - Optional filter by edge type
21
30
  * @returns Array of neighbor paths
22
31
  */
23
- export function getNeighbors(graph, node, direction = 'both', edgeType) {
32
+ export function getNeighbors(graph, node, direction = 'both', edgeType, metadata = {}) {
24
33
  const entry = graph[node];
25
- if (!entry)
34
+ if (!entry || (metadata[node] && !isOrdinaryMemoryEntry(metadata[node])))
26
35
  return [];
27
36
  const results = new Set();
28
37
  if (direction === 'in' || direction === 'both') {
29
38
  const edges = normalizeEdges(entry.upstream);
30
39
  for (const edge of edges) {
31
- if (!edgeType || edge.type === edgeType) {
40
+ if ((!edgeType || edge.type === edgeType) && (!metadata[edge.path] || isOrdinaryMemoryEntry(metadata[edge.path]))) {
32
41
  results.add(edge.path);
33
42
  }
34
43
  }
@@ -36,7 +45,7 @@ export function getNeighbors(graph, node, direction = 'both', edgeType) {
36
45
  if (direction === 'out' || direction === 'both') {
37
46
  const edges = normalizeEdges(entry.downstream);
38
47
  for (const edge of edges) {
39
- if (!edgeType || edge.type === edgeType) {
48
+ if ((!edgeType || edge.type === edgeType) && (!metadata[edge.path] || isOrdinaryMemoryEntry(metadata[edge.path]))) {
40
49
  results.add(edge.path);
41
50
  }
42
51
  }
@@ -134,7 +143,7 @@ export async function showNeighbors(cwd, options) {
134
143
  }
135
144
  process.exit(1);
136
145
  }
137
- const neighbors = getNeighbors(graph, resolved, direction, edgeType);
146
+ const neighbors = getNeighbors(graph, resolved, direction, edgeType, graphMemoryMetadata(cwd, graphType, backend));
138
147
  if (json) {
139
148
  console.log(JSON.stringify({
140
149
  graph: graphType,
@@ -208,8 +217,9 @@ export async function executeSetQuery(cwd, options) {
208
217
  console.error(`Error: Node '${nodeB}' not found in graph '${graphType}'.`);
209
218
  process.exit(1);
210
219
  }
211
- const neighborsA = getNeighbors(graph, resolvedA, direction, edgeType);
212
- const neighborsB = getNeighbors(graph, resolvedB, direction, edgeType);
220
+ const metadata = graphMemoryMetadata(cwd, graphType, backend);
221
+ const neighborsA = getNeighbors(graph, resolvedA, direction, edgeType, metadata);
222
+ const neighborsB = getNeighbors(graph, resolvedB, direction, edgeType, metadata);
213
223
  let result;
214
224
  switch (op) {
215
225
  case 'intersection':