@aiwg/cli 2026.10.5 → 2026.10.7

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 (263) 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 +7 -3
  6. package/dist/src/a2a/agent-card.js +11 -0
  7. package/dist/src/api/index.d.ts +1 -0
  8. package/dist/src/api/index.js +1 -0
  9. package/dist/src/artifacts/browser-export.js +1 -0
  10. package/dist/src/artifacts/citation-parser.js +8 -1
  11. package/dist/src/artifacts/cli.js +57 -6
  12. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  13. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  14. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/contract.json +103 -0
  15. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-config.schema.json +212 -0
  16. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-set.schema.json +240 -0
  17. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-manifest.schema.json +451 -0
  18. package/dist/src/artifacts/fortemi-shard-export.js +284 -0
  19. package/dist/src/artifacts/graph-query.js +18 -8
  20. package/dist/src/artifacts/index-adapters.js +339 -0
  21. package/dist/src/artifacts/index-builder.js +143 -14
  22. package/dist/src/artifacts/index-files.js +15 -4
  23. package/dist/src/artifacts/index-preparation.js +2 -0
  24. package/dist/src/artifacts/index-reader.js +44 -0
  25. package/dist/src/artifacts/index-refresh.js +114 -55
  26. package/dist/src/artifacts/index-status.js +20 -5
  27. package/dist/src/artifacts/memory-maintenance.js +503 -0
  28. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  29. package/dist/src/artifacts/query-engine.js +263 -108
  30. package/dist/src/artifacts/relations-builder.js +2 -2
  31. package/dist/src/artifacts/source-graph.js +2 -2
  32. package/dist/src/artifacts/types.js +9 -1
  33. package/dist/src/auth/client.js +5 -1
  34. package/dist/src/auth/credential-store.js +5 -1
  35. package/dist/src/auth/sensitive-input.js +151 -0
  36. package/dist/src/channel/manager.mjs +3 -0
  37. package/dist/src/cli/handlers/agentcard.js +47 -25
  38. package/dist/src/cli/handlers/auth.js +22 -2
  39. package/dist/src/cli/handlers/decision.js +22 -3
  40. package/dist/src/cli/handlers/effect.js +4 -84
  41. package/dist/src/cli/handlers/guided-setup.js +470 -0
  42. package/dist/src/cli/handlers/help.js +2 -2
  43. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  44. package/dist/src/cli/handlers/index.js +4 -2
  45. package/dist/src/cli/handlers/init.js +41 -6
  46. package/dist/src/cli/handlers/install.js +6 -0
  47. package/dist/src/cli/handlers/local-executor.js +5 -3
  48. package/dist/src/cli/handlers/marketplace.js +15 -4
  49. package/dist/src/cli/handlers/mc.js +509 -53
  50. package/dist/src/cli/handlers/models.js +32 -2
  51. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  52. package/dist/src/cli/handlers/rules.js +1 -1
  53. package/dist/src/cli/handlers/script-runner.js +73 -2
  54. package/dist/src/cli/handlers/serve.js +5 -3
  55. package/dist/src/cli/handlers/sessions.js +1 -0
  56. package/dist/src/cli/handlers/setup.js +432 -1
  57. package/dist/src/cli/handlers/skill-lint.js +1 -1
  58. package/dist/src/cli/handlers/subcommands.js +118 -8
  59. package/dist/src/cli/handlers/use.js +335 -107
  60. package/dist/src/cli/handlers/workspace.js +3 -1
  61. package/dist/src/cli/prompt-utils.js +81 -0
  62. package/dist/src/cli/router.js +16 -1
  63. package/dist/src/config/aiwg-config.js +42 -0
  64. package/dist/src/config/cli.js +7 -3
  65. package/dist/src/config/decision-config.js +14 -1
  66. package/dist/src/config/gitignore.js +4 -0
  67. package/dist/src/config/native-sandbox-warnings.js +25 -0
  68. package/dist/src/config/workspace.js +2 -1
  69. package/dist/src/contributors/validation.js +6 -5
  70. package/dist/src/decision/adapters/jev.js +20 -31
  71. package/dist/src/decision/admission.js +7 -3
  72. package/dist/src/decision/ask.js +6 -1
  73. package/dist/src/decision/benchmark.js +482 -0
  74. package/dist/src/decision/ledger.js +22 -3
  75. package/dist/src/decision/pricing.js +147 -0
  76. package/dist/src/decision/qualification/gate-evidence.js +23 -18
  77. package/dist/src/decision/qualification/load-staged.js +576 -0
  78. package/dist/src/decision/qualification/load.js +109 -33
  79. package/dist/src/decision/qualification/runner.js +12 -5
  80. package/dist/src/decision/review/service.js +6 -4
  81. package/dist/src/decision/review/validate.js +23 -2
  82. package/dist/src/decision/savings.js +8 -3
  83. package/dist/src/discovery/index.js +492 -0
  84. package/dist/src/discovery/interview.js +238 -0
  85. package/dist/src/discovery/plan-apply.js +567 -0
  86. package/dist/src/discovery/plan-store.js +171 -0
  87. package/dist/src/discovery/plan-types.js +2 -0
  88. package/dist/src/discovery/plan-validation.js +139 -0
  89. package/dist/src/discovery/types.js +2 -0
  90. package/dist/src/effects/host.js +91 -0
  91. package/dist/src/extensions/commands/definitions.js +49 -9
  92. package/dist/src/extensions/manifest.js +71 -44
  93. package/dist/src/extensions/project-local-discovery.js +1 -1
  94. package/dist/src/extensions/project-local-gitignore.js +2 -0
  95. package/dist/src/extensions/project-quickref.js +18 -17
  96. package/dist/src/extensions/validation.js +32 -29
  97. package/dist/src/housekeeper/daemon-config.js +148 -0
  98. package/dist/src/housekeeper/ipc.js +84 -0
  99. package/dist/src/housekeeper/lifecycle.js +148 -0
  100. package/dist/src/housekeeper/platform.js +35 -0
  101. package/dist/src/housekeeper/status.js +70 -0
  102. package/dist/src/housekeeper/units.js +114 -0
  103. package/dist/src/issues/cli.js +16 -5
  104. package/dist/src/issues/live.js +44 -12
  105. package/dist/src/jobs/flow.js +22 -21
  106. package/dist/src/lint/rule-activation.js +20 -5
  107. package/dist/src/lint/runner.js +1 -1
  108. package/dist/src/marketplace/exchange.js +18 -6
  109. package/dist/src/marketplace/provenance.js +3 -2
  110. package/dist/src/mcp/adapters/codex-runtime.js +46 -76
  111. package/dist/src/mcp/cli.mjs +22 -96
  112. package/dist/src/mcp/config-file.mjs +6 -2
  113. package/dist/src/mcp/config-layers.mjs +23 -7
  114. package/dist/src/mcp/grok-build-config.mjs +2 -1
  115. package/dist/src/mcp/muse-native-config.mjs +2 -1
  116. package/dist/src/mcp/profiles.js +18 -31
  117. package/dist/src/mcp/profiles.mjs +18 -32
  118. package/dist/src/mcp/registry.js +7 -27
  119. package/dist/src/mcp/registry.mjs +7 -28
  120. package/dist/src/mcp/server.mjs +34 -1
  121. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  122. package/dist/src/mcp/tools/command-run.mjs +3 -2
  123. package/dist/src/mcp/tools/decision.mjs +49 -48
  124. package/dist/src/mcp/tools/discovery.mjs +46 -21
  125. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  126. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  127. package/dist/src/mcp/tools/worker-invoke.mjs +30 -6
  128. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  129. package/dist/src/memory/audit.js +719 -0
  130. package/dist/src/memory/canonical-context.js +392 -13
  131. package/dist/src/memory/canonical-maintenance.js +95 -0
  132. package/dist/src/memory/cli-result.js +22 -0
  133. package/dist/src/memory/cli.js +176 -0
  134. package/dist/src/memory/context-pack.js +57 -6
  135. package/dist/src/memory/cost.js +512 -0
  136. package/dist/src/memory/firewall-classification.d.mts +7 -0
  137. package/dist/src/memory/firewall-classification.mjs +32 -0
  138. package/dist/src/memory/index.js +8 -0
  139. package/dist/src/memory/line-maintenance.js +68 -0
  140. package/dist/src/memory/maintenance-cli.js +286 -0
  141. package/dist/src/memory/maintenance-contract.js +136 -0
  142. package/dist/src/memory/maintenance-index.js +18 -0
  143. package/dist/src/memory/maintenance-owner.js +2 -0
  144. package/dist/src/memory/maintenance-record.js +138 -0
  145. package/dist/src/memory/maintenance.js +254 -0
  146. package/dist/src/memory/project-registry.js +2 -1
  147. package/dist/src/memory/provider-memory-adapter.js +154 -0
  148. package/dist/src/memory/recommend-cli.js +83 -0
  149. package/dist/src/memory/recommend.js +269 -0
  150. package/dist/src/memory/scheduled.js +81 -0
  151. package/dist/src/memory/taxonomy.js +44 -0
  152. package/dist/src/mission-protocol/codecs.js +19 -9
  153. package/dist/src/mission-protocol/worker-status.js +91 -1
  154. package/dist/src/models/config-loader.js +11 -1
  155. package/dist/src/models/model-capabilities.v1.json +74 -50
  156. package/dist/src/models/provider-policy.js +125 -62
  157. package/dist/src/models/resolver.js +45 -8
  158. package/dist/src/models/worker-installation.d.mts +8 -1
  159. package/dist/src/models/worker-installation.mjs +231 -38
  160. package/dist/src/models/wrapper-route.js +1 -1
  161. package/dist/src/output-modes/registry.js +8 -7
  162. package/dist/src/packages/adapters/git.js +99 -23
  163. package/dist/src/packages/adapters/gitea.js +8 -27
  164. package/dist/src/packages/adapters/github.js +7 -25
  165. package/dist/src/packages/registry.js +4 -4
  166. package/dist/src/plugin/metadata-validator.js +1 -1
  167. package/dist/src/process/cli-command.d.mts +5 -0
  168. package/dist/src/process/cli-command.mjs +42 -0
  169. package/dist/src/providers/deploy-version.d.mts +1 -0
  170. package/dist/src/providers/deploy-version.mjs +17 -0
  171. package/dist/src/providers/provider-definitions.js +19 -16
  172. package/dist/src/providers/skill-ownership.d.mts +11 -2
  173. package/dist/src/providers/skill-ownership.mjs +35 -17
  174. package/dist/src/rules/activation.d.mts +11 -2
  175. package/dist/src/rules/activation.mjs +82 -6
  176. package/dist/src/rules/inventory.js +1 -1
  177. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  178. package/dist/src/schema/zod-validation.d.mts +6 -0
  179. package/dist/src/schema/zod-validation.mjs +50 -0
  180. package/dist/src/serve/executor-registry.js +297 -20
  181. package/dist/src/serve/executor-token.d.mts +1 -0
  182. package/dist/src/serve/executor-token.mjs +8 -0
  183. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  184. package/dist/src/serve/worker-invocation.js +124 -15
  185. package/dist/src/sessions/adapters/claude.js +19 -18
  186. package/dist/src/sessions/adapters/codex.js +10 -9
  187. package/dist/src/sessions/adapters/copilot.js +14 -13
  188. package/dist/src/sessions/adapters/cursor.js +19 -18
  189. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  190. package/dist/src/sessions/adapters/factory.js +11 -10
  191. package/dist/src/sessions/adapters/generic.js +32 -23
  192. package/dist/src/sessions/adapters/grokbot.js +35 -35
  193. package/dist/src/sessions/adapters/hermes.js +20 -19
  194. package/dist/src/sessions/adapters/muse.js +50 -49
  195. package/dist/src/sessions/adapters/omp.js +5 -4
  196. package/dist/src/sessions/adapters/openclaw.js +30 -29
  197. package/dist/src/sessions/adapters/opencode.js +26 -26
  198. package/dist/src/sessions/adapters/openhuman.js +24 -23
  199. package/dist/src/sessions/adapters/pi.js +5 -4
  200. package/dist/src/sessions/adapters/windsurf.js +8 -8
  201. package/dist/src/sessions/analytics.js +10 -9
  202. package/dist/src/sessions/candidates.js +7 -6
  203. package/dist/src/sessions/contracts.js +63 -53
  204. package/dist/src/sessions/output-registration.js +11 -10
  205. package/dist/src/sessions/workspace-discovery.js +3 -4
  206. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  207. package/dist/src/smiths/context-pipeline/claude-hook.js +46 -10
  208. package/dist/src/smiths/context-pipeline/context-file-safety.js +330 -9
  209. package/dist/src/smiths/context-pipeline/finalization.js +3 -2
  210. package/dist/src/smiths/context-pipeline/generator.js +7 -19
  211. package/dist/src/smiths/context-pipeline/legacy-inject.js +3 -10
  212. package/dist/src/smiths/context-pipeline/managed-hook.js +5 -5
  213. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  214. package/dist/src/smiths/context-pipeline/workspace-context.js +110 -22
  215. package/dist/src/tracker/project-inputs.js +2 -0
  216. package/dist/src/update/checker.d.mts +4 -0
  217. package/dist/src/update/checker.mjs +14 -0
  218. package/dist/src/update/notifier.mjs +2 -4
  219. package/dist/src/writing/exemplar-selection.js +6 -6
  220. package/dist/src/writing/voice-evaluation.js +24 -23
  221. package/dist/src/writing/writer-migration.js +14 -13
  222. package/dist/src/writing/writer-profile.js +19 -18
  223. package/dist/src/writing/writing-brief.js +18 -17
  224. package/dist/src/writing/writing-receipt.js +47 -46
  225. package/package.json +5 -2
  226. package/schemas/decision/DecisionReview.schema.json +78 -1
  227. package/schemas/mission-v1.schema.json +3 -0
  228. package/tools/agents/deploy-agents.mjs +67 -39
  229. package/tools/agents/providers/antigravity.mjs +6 -1
  230. package/tools/agents/providers/base.mjs +24 -14
  231. package/tools/agents/providers/claude.mjs +6 -3
  232. package/tools/agents/providers/codex.mjs +54 -57
  233. package/tools/agents/providers/context-write.mjs +28 -0
  234. package/tools/agents/providers/copilot.mjs +13 -4
  235. package/tools/agents/providers/cursor.mjs +1 -1
  236. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  237. package/tools/agents/providers/factory.mjs +7 -1
  238. package/tools/agents/providers/grok-build.mjs +18 -2
  239. package/tools/agents/providers/grokbot.mjs +1 -1
  240. package/tools/agents/providers/hermes.mjs +12 -15
  241. package/tools/agents/providers/muse-hooks.mjs +21 -14
  242. package/tools/agents/providers/muse.mjs +7 -2
  243. package/tools/agents/providers/omp.mjs +31 -5
  244. package/tools/agents/providers/opencode.mjs +14 -5
  245. package/tools/agents/providers/openhuman.mjs +1 -1
  246. package/tools/agents/providers/pi.mjs +1 -1
  247. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  248. package/tools/agents/providers/rule-delivery.mjs +289 -80
  249. package/tools/agents/providers/warp.mjs +4 -1
  250. package/tools/agents/providers/windsurf.mjs +13 -3
  251. package/tools/cli/workspace-status.mjs +5 -0
  252. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  253. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  254. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +26 -0
  255. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +7 -1
  256. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  257. package/tools/ralph-external/lib/recovery-probe.mjs +14 -4
  258. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  259. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  260. package/tools/ralph-external/process-monitor.mjs +49 -8
  261. package/tools/ralph-external/session-launcher.mjs +405 -35
  262. package/tools/skills/deploy-skills-codex.mjs +11 -7
  263. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -0,0 +1,286 @@
1
+ import { memoryUsage, MEMORY_EXIT_USAGE } from './cli-result.js';
2
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { createInterface } from 'node:readline/promises';
4
+ import { sha256 } from './context-pack.js';
5
+ import { MemoryRecommendationsSchema } from './recommend.js';
6
+ import { MaintenanceOpSchema, MaintenancePlanSchema } from './maintenance-contract.js';
7
+ import { MemoryPlacementSchema } from './taxonomy.js';
8
+ import { indexMemoryAliases } from './maintenance-record.js';
9
+ import { applyMaintenancePlan, maintenancePath, maintenancePlanDigest, previewMaintenancePlan, verifyMaintenancePlan } from './maintenance.js';
10
+ import { providerCopiesStatus } from '../smiths/context-pipeline/workspace-context.js';
11
+ export const MEMORY_MAINTENANCE_USAGE = `Usage:
12
+ aiwg memory plan --owner <owner> --target <handle> --op <operation> --rationale <text> --reviewer <name> --out <file>
13
+ [--placement resident|indexed|task-context|archived] [--category <category>]
14
+ [--replacements <json-file>] [--related <json-file>] [--link <indexed-path> ...]
15
+ [--retirement-basis age|review] [--json]
16
+ aiwg memory plan --recommendation <selected-candidate-file> --reviewer <name> --out <file> [--category <category>] [--replacements <json-file>] [--link <indexed-path> ...]
17
+ aiwg memory plan --input <exact-plan-file> [--out <file> | --preview] [--json]
18
+ aiwg memory apply --plan <file> [--confirm <plan-digest> | --yes] [--preview] [--json]
19
+ aiwg memory verify --plan <applied-plan-file> [--json]
20
+ aiwg memory restore --plan <restore-plan-file> [--confirm <plan-digest> | --yes] [--preview] [--json]
21
+ Operations: promote, demote, recategorize, merge, split, supersede, retire, restore.
22
+ Owners: line-memory, compound-memory, semantic-memory. Scope: this project (--scope project); global writes unsupported.
23
+ Verify checks recorded end states, receipts, history and indexed retrieval without writes.
24
+ Plan writes only the requested new plan file; preview writes nothing.
25
+ Noninteractive apply requires --yes or --confirm with the exact plan digest.
26
+ Changes affect the next session. Provider adapters must be regenerated by their existing owner.
27
+ ${MEMORY_EXIT_USAGE}`;
28
+ export function parseMemoryMaintenanceOptions(command, args) {
29
+ const opts = { values: {}, links: [], yes: false, json: false, preview: false, help: false };
30
+ const valueFlags = command === 'plan'
31
+ ? ['--owner', '--target', '--op', '--rationale', '--reviewer', '--out', '--input', '--recommendation', '--placement', '--category', '--replacements', '--related', '--link', '--retirement-basis']
32
+ : command === 'verify' ? ['--plan'] : ['--plan', '--confirm'];
33
+ valueFlags.push('--scope');
34
+ const booleanFlags = ['--json', '--help', '-h', ...(command === 'verify' ? [] : ['--preview']), ...(['apply', 'restore'].includes(command) ? ['--yes'] : [])];
35
+ const seen = new Set();
36
+ for (let index = 0; index < args.length; index++) {
37
+ const equal = args[index].indexOf('=');
38
+ const flag = equal < 0 ? args[index] : args[index].slice(0, equal);
39
+ const inline = equal < 0 ? undefined : args[index].slice(equal + 1);
40
+ if (!valueFlags.includes(flag) && !booleanFlags.includes(flag))
41
+ throw new Error(`Unknown memory ${command} argument: ${args[index]}`);
42
+ const key = flag === '-h' ? '--help' : flag;
43
+ if (seen.has(key) && flag !== '--link')
44
+ throw new Error(`Duplicate memory ${command} option: ${flag}`);
45
+ seen.add(key);
46
+ if (booleanFlags.includes(flag)) {
47
+ if (inline !== undefined)
48
+ throw new Error(`${flag} takes no value`);
49
+ if (key === '--help')
50
+ opts.help = true;
51
+ else if (flag === '--yes')
52
+ opts.yes = true;
53
+ else if (flag === '--json')
54
+ opts.json = true;
55
+ else
56
+ opts.preview = true;
57
+ }
58
+ else {
59
+ const value = inline ?? args[++index];
60
+ if (!value || value.startsWith('-'))
61
+ throw new Error(`${flag} requires a value`);
62
+ if (flag === '--link')
63
+ opts.links.push(value);
64
+ else
65
+ opts.values[flag.slice(2)] = value;
66
+ }
67
+ }
68
+ if (opts.help)
69
+ return opts;
70
+ if (opts.values.scope && opts.values.scope !== 'project')
71
+ throw new Error('Executable maintenance supports --scope project only; use audit --scope global for global inventory');
72
+ if (opts.yes && opts.values.confirm)
73
+ throw new Error('--yes and --confirm are mutually exclusive');
74
+ if (command === 'plan') {
75
+ if (opts.values.recommendation) {
76
+ if (!opts.values.reviewer)
77
+ throw new Error('--reviewer is required for recommendation review');
78
+ if (Object.keys(opts.values).some(key => !['recommendation', 'reviewer', 'out', 'category', 'replacements', 'scope'].includes(key)))
79
+ throw new Error('--recommendation cannot be combined with operation or exact-plan flags');
80
+ }
81
+ else if (opts.values.input) {
82
+ if (Object.keys(opts.values).some(key => !['input', 'out', 'scope'].includes(key)) || opts.links.length)
83
+ throw new Error('--input cannot be combined with operation flags');
84
+ }
85
+ else {
86
+ for (const required of ['owner', 'target', 'op', 'rationale', 'reviewer'])
87
+ if (!opts.values[required])
88
+ throw new Error(`--${required} is required`);
89
+ }
90
+ if (opts.preview && opts.values.out)
91
+ throw new Error('--preview and --out are mutually exclusive');
92
+ if (!opts.preview && !opts.values.out)
93
+ throw new Error('--out is required unless --preview is selected');
94
+ }
95
+ else {
96
+ if (!opts.values.plan)
97
+ throw new Error('--plan is required');
98
+ if (opts.preview && (opts.yes || opts.values.confirm))
99
+ throw new Error('--preview cannot be combined with confirmation');
100
+ }
101
+ return opts;
102
+ }
103
+ export async function createMaintenanceOwners(root) {
104
+ const [{ LineMaintenanceOwner }, { CanonicalMaintenanceOwner }, { ArtifactMaintenanceOwner }] = await Promise.all([
105
+ import('./line-maintenance.js'), import('./canonical-maintenance.js'), import('../artifacts/memory-maintenance.js'),
106
+ ]);
107
+ const artifact = new ArtifactMaintenanceOwner(root);
108
+ // These resident owners do not yet publish an owner-native indexed projection.
109
+ // Their default verifier explicitly refuses resident removal; an unrelated
110
+ // artifact copy must not turn that unsupported operation into a valid plan.
111
+ return [new LineMaintenanceOwner(root), new CanonicalMaintenanceOwner(root), artifact];
112
+ }
113
+ export async function runMemoryMaintenanceCli(command, args, dependencies = {}) {
114
+ const opts = memoryUsage(() => parseMemoryMaintenanceOptions(command, args));
115
+ if (opts.help) {
116
+ console.log(MEMORY_MAINTENANCE_USAGE);
117
+ return;
118
+ }
119
+ const root = dependencies.root ?? process.cwd();
120
+ const owners = dependencies.owners ?? await createMaintenanceOwners(root);
121
+ const readJson = (path) => memoryUsage(() => JSON.parse(readFileSync(maintenancePath(root, path), 'utf8')));
122
+ let recommendationRelated;
123
+ let recommendationUncertainty;
124
+ if (command === 'plan' && opts.values.recommendation) {
125
+ const report = memoryUsage(() => MemoryRecommendationsSchema.parse(readJson(opts.values.recommendation)));
126
+ if (report.workspace !== root || report.candidates.length !== 1)
127
+ throw new Error('Review input requires one candidate from this workspace');
128
+ const candidate = report.candidates[0];
129
+ if (candidate.status !== 'advisory' || candidate.blockedReasons.length)
130
+ throw new Error('Blocked, rejected or conflicting recommendations cannot become plans');
131
+ if (candidate.kind === 'conflict')
132
+ throw new Error('Conflicts require explicit source resolution');
133
+ if (['merge', 'supersede'].includes(candidate.kind) && !opts.values.replacements)
134
+ throw new Error('Lineage recommendations require explicit owner review with --replacements');
135
+ const target = candidate.target;
136
+ if (target.scope !== 'project')
137
+ throw new Error('Executable recommendation review requires a project-owned source');
138
+ const file = maintenancePath(root, target.sourcePath);
139
+ if (sha256(readFileSync(file, 'utf8')) !== candidate.sourceDigest)
140
+ throw new Error('Stale recommendation source digest; rerun recommend');
141
+ const owner = owners.find(value => value.name === target.authority.owner);
142
+ if (!owner)
143
+ throw new Error('Recommendation source has no executable maintenance owner');
144
+ // Audit fingerprints whole files. The owner binds its native body/revision and
145
+ // snapshot only after the reviewer selects this exact unchanged source.
146
+ const record = (await owner.records()).find(value => value.sourcePath === target.sourcePath);
147
+ if (!record)
148
+ throw new Error('Recommendation source is not an individual owner target; review an owner handle explicitly');
149
+ if (candidate.kind === 'merge') {
150
+ if (candidate.related.length !== candidate.relatedTargets.length)
151
+ throw new Error('Merge review requires every related source revision');
152
+ const records = await owner.records();
153
+ recommendationRelated = candidate.relatedTargets.map(binding => {
154
+ const related = binding.record;
155
+ if (related.scope !== target.scope || related.authority.owner !== owner.name)
156
+ throw new Error('Merge recommendation cannot cross scope or owners');
157
+ if (sha256(readFileSync(maintenancePath(root, related.sourcePath), 'utf8')) !== binding.sourceDigest)
158
+ throw new Error('Stale related recommendation source digest');
159
+ const input = records.find(value => value.sourcePath === related.sourcePath);
160
+ if (!input)
161
+ throw new Error('Related recommendation source is not an individual owner target');
162
+ return input.id;
163
+ });
164
+ }
165
+ recommendationUncertainty = candidate.uncertainty.join('; ');
166
+ opts.values.owner = owner.name;
167
+ opts.values.target = record.id;
168
+ opts.values.op = candidate.kind;
169
+ opts.values.rationale = candidate.rationale + (candidate.residentJustification ? `; Resident justification: ${JSON.stringify(candidate.residentJustification)}` : '');
170
+ if (candidate.retrievalImpact.proposedPlacement)
171
+ opts.values.placement = candidate.retrievalImpact.proposedPlacement;
172
+ opts.values.category ??= candidate.retrievalImpact.category ?? '';
173
+ opts.values['retirement-basis'] = 'review';
174
+ }
175
+ let plan;
176
+ if (command === 'plan' && !opts.values.input) {
177
+ const owner = owners.find(value => value.name === opts.values.owner);
178
+ if (!owner)
179
+ throw new Error(`Unavailable maintenance owner: ${opts.values.owner}`);
180
+ const records = await owner.records();
181
+ const aliases = indexMemoryAliases(records);
182
+ const record = aliases.get(opts.values.target);
183
+ if (!record)
184
+ throw new Error('Maintenance target is missing');
185
+ const op = memoryUsage(() => MaintenanceOpSchema.parse(opts.values.op));
186
+ const lifecycle = op === 'retire' ? 'retired' : ['merge', 'split', 'supersede'].includes(op) ? 'superseded' : op === 'restore' ? 'active' : record.lifecycle;
187
+ const placement = opts.values.placement ? memoryUsage(() => MemoryPlacementSchema.parse(opts.values.placement)) : record.placement;
188
+ const relatedInput = recommendationRelated ?? (opts.values.related ? readJson(opts.values.related) : []);
189
+ if (!Array.isArray(relatedInput) || relatedInput.some(value => typeof value !== 'string'))
190
+ throw new Error('--related requires a JSON array of existing owner handles');
191
+ const related = relatedInput.map(handle => {
192
+ const input = aliases.get(handle);
193
+ if (!input)
194
+ throw new Error(`Related target is missing: ${handle}`);
195
+ return { id: input.id, digest: input.digest, version: input.version };
196
+ });
197
+ plan = { schemaVersion: 'aiwg.maintenance-plan.v1', operations: [{
198
+ op, target: { id: record.id, digest: record.digest, version: record.version },
199
+ from: { placement: record.placement, lifecycle: record.lifecycle }, to: { placement, lifecycle },
200
+ scope: record.scope, rationale: opts.values.rationale, uncertainty: recommendationUncertainty ?? 'Static review; live session loading is unobserved',
201
+ impactedLinks: opts.links, sessionEffect: 'next-session', precondition: { digest: record.digest, version: record.version },
202
+ owner: { name: owner.name, handle: record.aliases[0] ?? record.id, snapshot: await owner.snapshot() },
203
+ review: { reviewer: opts.values.reviewer, retirementBasis: (opts.values['retirement-basis'] ?? 'age') },
204
+ ...(related.length ? { related } : {}), ...(opts.values.category ? { category: opts.values.category } : {}),
205
+ ...(opts.values.replacements ? { replacements: readJson(opts.values.replacements) } : {}),
206
+ }] };
207
+ }
208
+ else
209
+ plan = readJson(opts.values.input ?? opts.values.plan);
210
+ plan = memoryUsage(() => MaintenancePlanSchema.parse(plan));
211
+ if (command === 'verify') {
212
+ const report = await verifyMaintenancePlan(plan, owners);
213
+ const providerCopies = await providerCopiesStatus(root);
214
+ const review = maintenanceReview(plan, root);
215
+ console.log(opts.json ? JSON.stringify({ ...report, providerCopies, review }, null, 2) : `${report.planDigest}: ${report.findings.length ? report.findings.join('; ') : 'verified recorded owner end states, history and required retrieval'}\nProvider copies: ${providerCopies.status}; regenerate: ${providerCopies.regenerate}\n${formatMaintenanceReview(review)}`);
216
+ return report.findings.length ? 1 : 0;
217
+ }
218
+ if (command === 'restore' && plan.operations?.some(op => op.op !== 'restore'))
219
+ throw new Error('memory restore requires a plan containing only restore operations');
220
+ if (command === 'plan' || opts.preview) {
221
+ plan = await previewMaintenancePlan(plan, owners);
222
+ const digest = maintenancePlanDigest(plan);
223
+ const review = maintenanceReview(plan, root);
224
+ if (command === 'plan' && !opts.preview) {
225
+ const path = maintenancePath(root, opts.values.out);
226
+ if (existsSync(path))
227
+ throw new Error('Plan output exists; choose a new file to preserve the reviewed preview');
228
+ console.error(opts.json ? JSON.stringify({ event: 'maintenance-review', planDigest: digest, review }) : formatMaintenanceReview(review));
229
+ writeFileSync(path, `${JSON.stringify(plan, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
230
+ }
231
+ console.log(opts.json ? JSON.stringify({ planDigest: digest, plan, review }, null, 2) : `${digest}\n${formatMaintenanceReview(review)}`);
232
+ return;
233
+ }
234
+ const digest = maintenancePlanDigest(plan);
235
+ const review = maintenanceReview(plan, root);
236
+ console.error(opts.json ? JSON.stringify({ event: 'maintenance-review', planDigest: digest, review }) : formatMaintenanceReview(review));
237
+ let confirmed = opts.values.confirm;
238
+ if (opts.yes)
239
+ confirmed = digest;
240
+ if (!confirmed) {
241
+ if (!(dependencies.isTTY ?? (process.stdin.isTTY && process.stdout.isTTY)) || opts.json)
242
+ memoryUsage(() => { throw new Error('Noninteractive apply requires --yes or --confirm <exact-plan-digest>'); });
243
+ console.log(JSON.stringify(plan, null, 2));
244
+ if (dependencies.confirm)
245
+ confirmed = await dependencies.confirm(digest);
246
+ else {
247
+ const readline = createInterface({ input: process.stdin, output: process.stdout });
248
+ try {
249
+ confirmed = await readline.question(`Type the exact plan digest to apply ${digest}: `);
250
+ }
251
+ finally {
252
+ readline.close();
253
+ }
254
+ }
255
+ }
256
+ const receipt = await applyMaintenancePlan(plan, { root, owners, confirmedDigest: confirmed });
257
+ const providerCopies = await providerCopiesStatus(root);
258
+ console.log(opts.json ? JSON.stringify({ ...receipt, providerCopies }, null, 2) : `${receipt.planDigest}: ${receipt.ownerReceipts.length} owner operation(s) completed; next-session effect\nProvider copies: ${providerCopies.status}; regenerate: ${providerCopies.regenerate}`);
259
+ }
260
+ /** Review envelope shared by human output, JSON previews and pre-mutation events. */
261
+ export function maintenanceReview(plan, root) {
262
+ const scopes = [...new Set(plan.operations.map(operation => operation.scope))];
263
+ return {
264
+ targeting: { workspace: root, scope: scopes.join(', '), global: scopes.includes('global'), globalMutationSupported: false },
265
+ diff: plan.operations.map(operation => ({ ...operation })),
266
+ ownerReview: plan.operations.map(operation => ({ owner: operation.owner, review: operation.review,
267
+ requirement: 'Exact owner snapshot and reviewer required; confirmation never bypasses owner validation' })),
268
+ limitations: ['Static durable state only; live native/session loading is unobserved',
269
+ 'Changes take effect next-session; running sessions are unchanged',
270
+ 'Provider-native files require regeneration by their existing owner',
271
+ 'Line-memory and compound-memory resident removal requires an owner-native indexed projection and is currently unsupported'],
272
+ };
273
+ }
274
+ function formatMaintenanceReview(review) {
275
+ return [`Target: ${review.targeting.scope} ${review.targeting.workspace}; global mutation unsupported`,
276
+ ...review.diff.flatMap(operation => [
277
+ `${operation.op} ${operation.owner?.name}:${operation.owner?.handle}: ${operation.from.placement}/${operation.from.lifecycle} -> ${operation.to.placement}/${operation.to.lifecycle}${operation.category ? `; category -> ${operation.category}` : ''}; ${operation.scope}; ${operation.sessionEffect}; reviewer ${operation.review?.reviewer}; rationale: ${operation.rationale}`,
278
+ ` revision ${operation.target.version}; digest ${operation.target.digest}; owner snapshot ${operation.owner?.snapshot}; retirement basis ${operation.review?.retirementBasis}`,
279
+ ` uncertainty: ${operation.uncertainty}; links: ${JSON.stringify(operation.impactedLinks)}`,
280
+ ...(operation.related?.length ? [` related revisions: ${JSON.stringify(operation.related)}`] : []),
281
+ ...(operation.replacements?.length ? [` replacements: ${JSON.stringify(operation.replacements)}`] : []),
282
+ ]),
283
+ 'Owner review: exact snapshot, source revision and reviewer required.',
284
+ ...review.limitations].join('\n');
285
+ }
286
+ //# sourceMappingURL=maintenance-cli.js.map
@@ -0,0 +1,136 @@
1
+ import { z } from 'zod';
2
+ import { integer } from '../schema/zod-validation.mjs';
3
+ import { isDeepStrictEqual } from 'node:util';
4
+ import { indexMemoryAliases, MemoryDigestSchema } from './maintenance-record.js';
5
+ import { MemoryLifecycleSchema, MemoryPlacementSchema, MemoryScopeSchema } from './taxonomy.js';
6
+ export const MaintenanceOpSchema = z.enum([
7
+ 'promote', 'demote', 'recategorize', 'merge', 'split', 'supersede', 'retire', 'restore',
8
+ ]);
9
+ const VersionSchema = integer().min(1).max(Number.MAX_SAFE_INTEGER);
10
+ const TargetSchema = z.strictObject({ id: z.string().min(1), digest: MemoryDigestSchema, version: VersionSchema });
11
+ const StateSchema = z.strictObject({ placement: MemoryPlacementSchema, lifecycle: MemoryLifecycleSchema });
12
+ export const MaintenanceOperationSchema = z.strictObject({
13
+ op: MaintenanceOpSchema,
14
+ target: TargetSchema,
15
+ related: z.array(TargetSchema).optional(),
16
+ owner: z.strictObject({ name: z.string().min(1), handle: z.string().min(1), snapshot: MemoryDigestSchema }).optional(),
17
+ review: z.strictObject({ reviewer: z.string().min(1), retirementBasis: z.enum(['age', 'review']) }).optional(),
18
+ category: z.string().min(1).optional(),
19
+ replacements: z.array(z.strictObject({ key: z.string().min(1), value: z.string().min(1), sourcePath: z.string().min(1).optional(), category: z.string().min(1).optional() })).optional(),
20
+ from: StateSchema,
21
+ to: StateSchema,
22
+ scope: MemoryScopeSchema,
23
+ rationale: z.string().min(1),
24
+ uncertainty: z.string().min(1),
25
+ impactedLinks: z.array(z.string().min(1)),
26
+ sessionEffect: z.enum(['current', 'next-session']),
27
+ precondition: z.strictObject({ digest: MemoryDigestSchema, version: VersionSchema }),
28
+ }).superRefine((operation, context) => {
29
+ if (operation.from.placement !== operation.to.placement && operation.from.lifecycle !== operation.to.lifecycle) {
30
+ context.addIssue({ code: 'custom', message: 'An operation cannot implicitly change a second axis' });
31
+ }
32
+ if (operation.target.digest !== operation.precondition.digest || operation.target.version !== operation.precondition.version) {
33
+ context.addIssue({ code: 'custom', message: 'Target and precondition must identify the same revision' });
34
+ }
35
+ const lineage = ['merge', 'split', 'supersede'].includes(operation.op);
36
+ if (!lineage && (operation.related?.length || operation.replacements?.length)) {
37
+ context.addIssue({ code: 'custom', message: 'Only lineage operations accept replacements or related inputs' });
38
+ }
39
+ if (operation.replacements && ((['merge', 'supersede'].includes(operation.op) && operation.replacements.length !== 1)
40
+ || (operation.op === 'split' && operation.replacements.length < 2))) {
41
+ context.addIssue({ code: 'custom', message: 'Lineage operation requires the exact replacement count' });
42
+ }
43
+ if (operation.related?.length && operation.op !== 'merge')
44
+ context.addIssue({ code: 'custom', message: 'Only merge accepts related inputs' });
45
+ if (['promote', 'demote', 'recategorize'].includes(operation.op) && operation.from.lifecycle !== operation.to.lifecycle) {
46
+ context.addIssue({ code: 'custom', message: 'Placement and category operations cannot change lifecycle' });
47
+ }
48
+ if (!['promote', 'demote'].includes(operation.op) && operation.from.placement !== operation.to.placement) {
49
+ context.addIssue({ code: 'custom', message: 'Lifecycle and category operations cannot change placement' });
50
+ }
51
+ const rank = { archived: 0, indexed: 1, 'task-context': 2, resident: 3 };
52
+ if ((operation.op === 'promote' && rank[operation.to.placement] <= rank[operation.from.placement])
53
+ || (operation.op === 'demote' && rank[operation.to.placement] >= rank[operation.from.placement])) {
54
+ context.addIssue({ code: 'custom', message: 'Promotion or demotion must move in the requested placement direction' });
55
+ }
56
+ if (lineage && (operation.from.lifecycle !== 'active' || operation.to.lifecycle !== 'superseded')) {
57
+ context.addIssue({ code: 'custom', message: 'Lineage operations supersede active originals' });
58
+ }
59
+ if (operation.from.lifecycle === 'purged')
60
+ context.addIssue({ code: 'custom', message: 'Purged sources cannot be maintained' });
61
+ if (operation.to.lifecycle === 'purged') {
62
+ context.addIssue({ code: 'custom', message: 'Maintenance cannot purge sources' });
63
+ }
64
+ });
65
+ export const MaintenancePlanSchema = z.strictObject({
66
+ schemaVersion: z.literal('aiwg.maintenance-plan.v1'),
67
+ operations: z.array(MaintenanceOperationSchema),
68
+ });
69
+ export const ProviderCopiesSchema = z.strictObject({
70
+ status: z.enum(['current', 'stale', 'not-applicable']),
71
+ regenerate: z.literal('aiwg regenerate --workspace --provider generic'),
72
+ });
73
+ export const MaintenanceReceiptSchema = z.strictObject({
74
+ schemaVersion: z.literal('aiwg.maintenance-receipt.v1'),
75
+ planDigest: MemoryDigestSchema,
76
+ ownerReceipts: z.array(z.unknown()),
77
+ partial: z.strictObject({ completed: z.array(z.string().min(1)), pending: z.array(z.string().min(1)) }).optional(),
78
+ resumedFrom: z.string().min(1).optional(),
79
+ providerCopies: ProviderCopiesSchema.optional(),
80
+ });
81
+ /** Validate a preview against current owner metadata. Does not apply, retire or restore anything.
82
+ * Retirement defaults to age eligibility; explicit review policy is supplied by the caller.
83
+ */
84
+ export function validateMaintenancePlan(input, records, policy = { retirementBasis: 'age' }) {
85
+ const plan = MaintenancePlanSchema.parse(input);
86
+ const index = indexMemoryAliases(records);
87
+ const targets = new Set();
88
+ for (const operation of plan.operations) {
89
+ const record = index.get(operation.target.id);
90
+ if (!record)
91
+ throw new Error('Maintenance target is missing');
92
+ if (targets.has(record.id))
93
+ throw new Error('Multiple operations require separate revision previews for the same target');
94
+ targets.add(record.id);
95
+ if (operation.precondition.digest !== record.digest || operation.precondition.version !== record.version) {
96
+ throw new Error('Stale memory digest or version precondition');
97
+ }
98
+ if (record.version >= Number.MAX_SAFE_INTEGER)
99
+ throw new Error('Maintenance revision is exhausted');
100
+ if (operation.scope !== record.scope)
101
+ throw new Error('Maintenance cannot implicitly change scope');
102
+ if (operation.from.placement !== record.placement || operation.from.lifecycle !== record.lifecycle) {
103
+ throw new Error('Stale memory placement or lifecycle precondition');
104
+ }
105
+ if (policy.retirementBasis === 'age' && record.authority.protection === 'pinned'
106
+ && (operation.op === 'retire' || operation.to.lifecycle === 'retired')) {
107
+ throw new Error('Pinned rare obligations cannot be retired by age');
108
+ }
109
+ if (operation.op === 'retire' && operation.to.lifecycle !== 'retired')
110
+ throw new Error('Retire requires retired lifecycle');
111
+ if (operation.op === 'supersede' && operation.to.lifecycle !== 'superseded')
112
+ throw new Error('Supersede requires superseded lifecycle');
113
+ if (operation.op === 'restore' && operation.to.lifecycle !== 'active')
114
+ throw new Error('Restore requires active lifecycle');
115
+ }
116
+ for (const operation of plan.operations) {
117
+ for (const input of operation.related ?? []) {
118
+ const record = index.get(input.id);
119
+ const target = index.get(operation.target.id);
120
+ if (!record)
121
+ throw new Error('Related maintenance target is missing');
122
+ if (targets.has(record.id))
123
+ throw new Error('Multiple operations overlap a maintenance target');
124
+ targets.add(record.id);
125
+ if (input.digest !== record.digest || input.version !== record.version)
126
+ throw new Error('Stale related digest or version precondition');
127
+ if (record.scope !== target.scope || !isDeepStrictEqual(record.authority, target.authority)) {
128
+ throw new Error('Merge cannot implicitly change scope or authority');
129
+ }
130
+ if (record.lifecycle !== 'active')
131
+ throw new Error('Merge inputs must be active');
132
+ }
133
+ }
134
+ return plan;
135
+ }
136
+ //# sourceMappingURL=maintenance-contract.js.map
@@ -0,0 +1,18 @@
1
+ import { existsSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { getProjectIndexRoot } from '../artifacts/types.js';
4
+ /** Refresh every existing local retrieval graph after an owner commit or recovery. */
5
+ export async function refreshMaintenanceIndexes(root) {
6
+ const directory = getProjectIndexRoot(root);
7
+ const graphs = existsSync(directory)
8
+ ? readdirSync(directory, { withFileTypes: true })
9
+ .filter(entry => entry.isDirectory() && !entry.name.startsWith('.')
10
+ && existsSync(join(directory, entry.name, 'metadata.json')))
11
+ .map(entry => entry.name)
12
+ : [];
13
+ const { buildIndex } = await import('../artifacts/index-builder.js');
14
+ for (const graph of ['', ...graphs]) {
15
+ await buildIndex(root, { ...(graph ? { graph } : {}), force: true, quiet: true, workers: 0 });
16
+ }
17
+ }
18
+ //# sourceMappingURL=maintenance-index.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=maintenance-owner.js.map
@@ -0,0 +1,138 @@
1
+ import { z } from 'zod';
2
+ import { integer, dateTime } from '../schema/zod-validation.mjs';
3
+ import { load } from 'js-yaml';
4
+ import { sha256 } from './context-pack.js';
5
+ import { MemoryLifecycleSchema, MemoryTaxonomySchema } from './taxonomy.js';
6
+ export const MemoryDigestSchema = z.string().regex(/^sha256:[0-9a-f]{64}$/);
7
+ const HandleSchema = z.string().min(1);
8
+ const HandlesSchema = z.array(HandleSchema).refine(values => new Set(values).size === values.length, 'Duplicate handles');
9
+ export const MemoryTombstoneSchema = z.strictObject({
10
+ id: HandleSchema,
11
+ digest: MemoryDigestSchema,
12
+ disposition: MemoryLifecycleSchema.exclude(['active']),
13
+ reason: z.string().min(1),
14
+ reviewer: z.string().min(1),
15
+ at: dateTime(),
16
+ successor: HandleSchema.optional(),
17
+ });
18
+ export const MemoryRecordSchema = z.strictObject({
19
+ ...MemoryTaxonomySchema.omit({ schemaVersion: true }).shape,
20
+ schemaVersion: z.literal('aiwg.memory-record.v1'),
21
+ id: MemoryDigestSchema,
22
+ sourcePath: z.string().min(1).refine(value => !/[\r\n\0]/.test(value)),
23
+ digest: MemoryDigestSchema,
24
+ version: integer().min(1).max(Number.MAX_SAFE_INTEGER),
25
+ aliases: HandlesSchema,
26
+ supersedes: HandlesSchema,
27
+ mergedFrom: HandlesSchema,
28
+ splitFrom: HandlesSchema,
29
+ sourceWorkspaceId: HandleSchema.optional(),
30
+ tombstone: MemoryTombstoneSchema.optional(),
31
+ }).superRefine((record, context) => {
32
+ if (record.lifecycle === 'retired' && !record.tombstone) {
33
+ context.addIssue({ code: 'custom', message: 'Retired memory requires an owner tombstone', path: ['tombstone'] });
34
+ }
35
+ });
36
+ /** Locator spelling is significant. Compatibility spellings belong in aliases. */
37
+ export function memoryRecordId(sourcePath, digest) {
38
+ MemoryDigestSchema.parse(digest);
39
+ return sha256(JSON.stringify({ sourcePath, digest }));
40
+ }
41
+ /** Refuse unknown versions rather than silently assigning current semantics. */
42
+ export function loadMemoryRecord(input) {
43
+ const record = MemoryRecordSchema.parse(input);
44
+ if (record.id !== memoryRecordId(record.sourcePath, record.digest)) {
45
+ throw new Error('Memory record identity does not match locator and digest');
46
+ }
47
+ if (record.aliases.includes(record.id))
48
+ throw new Error('Memory record cannot alias itself');
49
+ if (record.tombstone && (record.tombstone.id !== record.id || record.tombstone.digest !== record.digest
50
+ || record.tombstone.disposition !== record.lifecycle)) {
51
+ throw new Error('Memory tombstone must match its record identity and lifecycle');
52
+ }
53
+ return record;
54
+ }
55
+ export function indexMemoryAliases(records) {
56
+ const index = new Map();
57
+ const parsed = records.map(loadMemoryRecord);
58
+ const canonicalIds = new Set();
59
+ for (const record of parsed) {
60
+ if (index.has(record.id))
61
+ throw new Error(`Memory alias collision: ${record.id}`);
62
+ index.set(record.id, record);
63
+ canonicalIds.add(record.id);
64
+ }
65
+ for (const record of parsed) {
66
+ for (const handle of record.aliases) {
67
+ const prior = index.get(handle);
68
+ if (prior) {
69
+ // Prior IDs may be compatibility aliases on successors, but an exact
70
+ // canonical ID must still address its immutable retained history.
71
+ const lineage = [...record.supersedes, ...record.mergedFrom, ...record.splitFrom];
72
+ if (canonicalIds.has(handle) && lineage.includes(handle))
73
+ continue;
74
+ throw new Error(`Memory alias collision: ${handle}`);
75
+ }
76
+ index.set(handle, record);
77
+ }
78
+ }
79
+ return index;
80
+ }
81
+ /** Explicit metadata projection from the existing intake v1 receipt; no owner data is rewritten. */
82
+ export function memoryRecordFromIntake(receipt, owner) {
83
+ if (receipt.schemaVersion !== 'aiwg.compound-memory.intake-receipt.v1') {
84
+ throw new Error('Unsupported memory intake receipt version');
85
+ }
86
+ return loadMemoryRecord({
87
+ schemaVersion: 'aiwg.memory-record.v1',
88
+ id: memoryRecordId(receipt.sourceLocator, receipt.sourceDigest),
89
+ sourcePath: receipt.sourceLocator,
90
+ digest: receipt.sourceDigest,
91
+ version: 1,
92
+ aliases: [receipt.receiptId],
93
+ supersedes: [], mergedFrom: [], splitFrom: [],
94
+ scope: 'project', placement: 'indexed', lifecycle: 'active',
95
+ authority: { owner, source: 'import', protection: 'unprotected' },
96
+ observation: {
97
+ status: 'on-disk',
98
+ evidence: { source: receipt.receiptId, at: receipt.registeredAt, session: null, provider: null, version: null },
99
+ },
100
+ });
101
+ }
102
+ /** Validate supplied include edges only. Discovery and file loading belong to the audit owner. */
103
+ export function detectMemoryIncludeCycles(graph) {
104
+ const done = new Set();
105
+ const stack = [];
106
+ const active = new Map();
107
+ const cycles = [];
108
+ function visit(locator) {
109
+ const position = active.get(locator);
110
+ if (position !== undefined) {
111
+ cycles.push([...stack.slice(position), locator]);
112
+ return;
113
+ }
114
+ if (done.has(locator))
115
+ return;
116
+ active.set(locator, stack.length);
117
+ stack.push(locator);
118
+ for (const included of Object.hasOwn(graph, locator) ? graph[locator] : [])
119
+ visit(included);
120
+ stack.pop();
121
+ active.delete(locator);
122
+ done.add(locator);
123
+ }
124
+ for (const locator of Object.keys(graph).sort())
125
+ visit(locator);
126
+ return cycles;
127
+ }
128
+ /** Shared canonical Markdown parsing for inventory and the existing artifact owner. */
129
+ export function parseMemoryMarkdown(content) {
130
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
131
+ if (!match)
132
+ return { data: {}, body: content };
133
+ const data = load(match[1]) ?? {};
134
+ if (typeof data !== 'object' || Array.isArray(data))
135
+ throw new Error('Memory source frontmatter must be an object');
136
+ return { data: data, body: match[2] };
137
+ }
138
+ //# sourceMappingURL=maintenance-record.js.map