@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,254 @@
1
+ import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
2
+ import { dirname, resolve, sep } from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { isDeepStrictEqual } from 'node:util';
5
+ import { acquireDirectoryLock } from '../artifacts/prebuilt-build-lock.js';
6
+ import { sha256 } from './context-pack.js';
7
+ import { MaintenancePlanSchema, MaintenanceReceiptSchema, validateMaintenancePlan } from './maintenance-contract.js';
8
+ export function maintenancePlanDigest(plan) {
9
+ return sha256(JSON.stringify(MaintenancePlanSchema.parse(plan)));
10
+ }
11
+ export function maintenanceOperationKey(plan, index) {
12
+ return sha256(`${maintenancePlanDigest(plan)}:${index}`);
13
+ }
14
+ /** Reject paths escaping through either spelling or an existing symlink. */
15
+ export function maintenancePath(root, path) {
16
+ const base = realpathSync(root);
17
+ const target = resolve(root, path);
18
+ if (!target.startsWith(`${resolve(root)}${sep}`))
19
+ throw new Error('Maintenance paths must remain inside the workspace');
20
+ let ancestor = target;
21
+ while (!existsSync(ancestor))
22
+ ancestor = dirname(ancestor);
23
+ const actual = realpathSync(ancestor);
24
+ if (actual !== base && !actual.startsWith(`${base}${sep}`))
25
+ throw new Error('Maintenance path traverses outside the workspace');
26
+ return target;
27
+ }
28
+ function writeAtomic(path, value) {
29
+ mkdirSync(dirname(path), { recursive: true });
30
+ const temp = `${path}.${process.pid}.${randomUUID()}.tmp`;
31
+ try {
32
+ writeFileSync(temp, `${JSON.stringify(value, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
33
+ renameSync(temp, path);
34
+ }
35
+ finally {
36
+ if (existsSync(temp))
37
+ unlinkSync(temp);
38
+ }
39
+ }
40
+ function selectOwner(operation, owners) {
41
+ if (!operation.owner || !operation.review)
42
+ throw new Error('Executable maintenance requires an owner preview and explicit reviewer');
43
+ const owner = owners.find(value => value.name === operation.owner.name);
44
+ if (!owner)
45
+ throw new Error(`Unavailable maintenance owner: ${operation.owner.name}`);
46
+ if (operation.scope !== 'project')
47
+ throw new Error('These lifecycle owners support explicit project scope only');
48
+ if (operation.sessionEffect !== 'next-session')
49
+ throw new Error('Durable owner edits require next-session effect; current sessions are unchanged');
50
+ return owner;
51
+ }
52
+ export function removesResident(operation) {
53
+ return operation.from.placement === 'resident'
54
+ && (operation.to.placement !== 'resident' || operation.to.lifecycle !== 'active');
55
+ }
56
+ function checkOwnerUniqueness(plan) {
57
+ const names = plan.operations.map(op => op.owner?.name);
58
+ if (new Set(names).size !== names.length) {
59
+ throw new Error('One exact snapshot operation per owner is supported per plan; review a new plan for the next revision');
60
+ }
61
+ }
62
+ /** Read-only review. A plan file is the only output written by the CLI planner. */
63
+ export async function previewMaintenancePlan(input, owners) {
64
+ const plan = MaintenancePlanSchema.parse(input);
65
+ if (!plan.operations.length)
66
+ throw new Error('An executable plan requires at least one operation');
67
+ checkOwnerUniqueness(plan);
68
+ for (const operation of plan.operations) {
69
+ const owner = selectOwner(operation, owners);
70
+ if (!await owner.pending?.(operation)) {
71
+ validateMaintenancePlan({ ...plan, operations: [operation] }, await owner.records(), { retirementBasis: operation.review.retirementBasis });
72
+ }
73
+ await owner.validate(operation);
74
+ if (removesResident(operation) && !await verifyMaintenanceRetrieval(operation, owners)) {
75
+ throw new Error('Indexed retrieval must be verified before removing resident content');
76
+ }
77
+ }
78
+ // Also validate overlap between a target and another operation's merge inputs.
79
+ const inputs = plan.operations.flatMap(op => [op.target.id, ...(op.related ?? []).map(value => value.id)]);
80
+ if (new Set(inputs).size !== inputs.length)
81
+ throw new Error('Maintenance operations overlap');
82
+ return plan;
83
+ }
84
+ export async function verifyMaintenanceRetrieval(operation, owners) {
85
+ for (const owner of owners)
86
+ if (owner.verifyRetrieval && await owner.verifyRetrieval(operation))
87
+ return true;
88
+ return false;
89
+ }
90
+ /** Inspect committed owner receipts and end states without locks, journals or index refreshes. */
91
+ export async function verifyMaintenancePlan(input, owners) {
92
+ const plan = MaintenancePlanSchema.parse(input);
93
+ if (!plan.operations.length)
94
+ throw new Error('An executable plan requires at least one operation');
95
+ checkOwnerUniqueness(plan);
96
+ const selected = plan.operations.map(operation => selectOwner(operation, owners));
97
+ const inputs = plan.operations.flatMap(operation => [operation.target.id, ...(operation.related ?? []).map(item => item.id)]);
98
+ if (new Set(inputs).size !== inputs.length)
99
+ throw new Error('Maintenance operations overlap');
100
+ const operations = [];
101
+ for (const [index, operation] of plan.operations.entries()) {
102
+ const owner = selected[index];
103
+ const key = maintenanceOperationKey(plan, index);
104
+ const findings = [];
105
+ const receipt = await owner.receipt(key, { readOnly: true });
106
+ if (receipt === undefined)
107
+ findings.push('Exact owner receipt is missing; the operation is unapplied or incomplete');
108
+ let records;
109
+ try {
110
+ records = await owner.records();
111
+ }
112
+ catch (error) {
113
+ if (!(error instanceof Error) || error.message !== 'Canonical semantic-memory source identity or digest has changed')
114
+ throw error;
115
+ findings.push('Canonical source identity or digest has drifted');
116
+ records = [];
117
+ }
118
+ for (const [inputIndex, target] of [operation.target, ...(operation.related ?? [])].entries()) {
119
+ const record = records.find(item => item.id === target.id);
120
+ if (!record) {
121
+ findings.push(`Retained source is missing: ${target.id}`);
122
+ continue;
123
+ }
124
+ const expected = inputIndex === 0 ? operation.to : {
125
+ placement: operation.from.placement, lifecycle: 'superseded',
126
+ };
127
+ if (record.digest !== target.digest || record.version !== target.version + 1
128
+ || record.scope !== operation.scope || record.authority.owner !== owner.name
129
+ || record.placement !== expected.placement || record.lifecycle !== expected.lifecycle) {
130
+ findings.push(`Source revision or end state differs from the plan: ${target.id}`);
131
+ }
132
+ if (expected.lifecycle !== 'active' && (!record.tombstone || record.tombstone.id !== target.id
133
+ || record.tombstone.digest !== target.digest || record.tombstone.disposition !== expected.lifecycle
134
+ || record.tombstone.reason !== operation.rationale || record.tombstone.reviewer !== operation.review.reviewer)) {
135
+ findings.push(`Retained tombstone differs from the plan: ${target.id}`);
136
+ }
137
+ if (expected.lifecycle === 'active' && record.tombstone)
138
+ findings.push(`Active source retains a stale tombstone: ${target.id}`);
139
+ }
140
+ const lineage = [operation.target.id, ...(operation.related ?? []).map(item => item.id)];
141
+ const lineageField = operation.op === 'merge' ? 'mergedFrom' : operation.op === 'split' ? 'splitFrom' : 'supersedes';
142
+ for (const replacement of operation.replacements ?? []) {
143
+ const matches = records.filter(record => record.digest === sha256(replacement.value)
144
+ && isDeepStrictEqual(record[lineageField], lineage));
145
+ if (!matches.some(record => record.version === 1 && record.lifecycle === 'active'
146
+ && record.scope === operation.scope && record.authority.owner === owner.name
147
+ && record.placement === operation.to.placement)) {
148
+ findings.push(`Replacement revision or lineage differs from the plan: ${replacement.key}`);
149
+ }
150
+ }
151
+ if (owner.verifyEndState)
152
+ findings.push(...await owner.verifyEndState(operation, key));
153
+ if (removesResident(operation) || (operation.to.lifecycle === 'active' && ['indexed', 'task-context'].includes(operation.to.placement))) {
154
+ try {
155
+ if (!await verifyMaintenanceRetrieval(operation, owners))
156
+ findings.push('Indexed retrieval is unavailable for the recorded end state');
157
+ }
158
+ catch (error) {
159
+ if (!(error instanceof Error) || (!error.message.includes('no owner-native indexed retrieval projection')
160
+ && error.message !== 'Canonical semantic-memory source identity or digest has changed'))
161
+ throw error;
162
+ findings.push(error.message);
163
+ }
164
+ }
165
+ operations.push({ operationId: key, owner: owner.name, findings });
166
+ }
167
+ return { planDigest: maintenancePlanDigest(plan), operations,
168
+ findings: operations.flatMap(operation => operation.findings.map(finding => `${operation.owner}: ${finding}`)) };
169
+ }
170
+ export class MaintenanceApplyError extends Error {
171
+ receipt;
172
+ constructor(message, receipt) { super(message); this.name = 'MaintenanceApplyError'; this.receipt = receipt; }
173
+ }
174
+ /** Per-owner commits remain authoritative; this journal records progress, never memory bodies. */
175
+ export async function applyMaintenancePlan(input, options) {
176
+ const plan = MaintenancePlanSchema.parse(input);
177
+ const digest = maintenancePlanDigest(plan);
178
+ if (options.confirmedDigest !== digest)
179
+ throw new Error('Apply requires confirmation of the exact plan digest');
180
+ if (!plan.operations.length)
181
+ throw new Error('An executable plan requires at least one operation');
182
+ checkOwnerUniqueness(plan);
183
+ const selected = plan.operations.map(op => selectOwner(op, options.owners));
184
+ const journalPath = maintenancePath(options.root, `.aiwg/memory/maintenance/${digest.replace(':', '_')}.json`);
185
+ const lockPath = maintenancePath(options.root, '.aiwg/memory/maintenance/.lock');
186
+ mkdirSync(dirname(lockPath), { recursive: true });
187
+ let release;
188
+ try {
189
+ release = await acquireDirectoryLock(lockPath, { timeoutMs: 0, reclaimDeadOwner: true });
190
+ }
191
+ catch (error) {
192
+ throw new Error(`Concurrent maintenance plan owns the workspace lock: ${error instanceof Error ? error.message : String(error)}`);
193
+ }
194
+ const resumed = existsSync(journalPath);
195
+ const entries = [];
196
+ const keys = plan.operations.map((_, index) => maintenanceOperationKey(plan, index));
197
+ const receipt = () => {
198
+ const completed = entries.map(entry => entry.operationId);
199
+ const pending = keys.filter(key => !completed.includes(key));
200
+ return MaintenanceReceiptSchema.parse({ schemaVersion: 'aiwg.maintenance-receipt.v1', planDigest: digest,
201
+ ownerReceipts: entries, ...(pending.length ? { partial: { completed, pending } } : {}),
202
+ ...(resumed ? { resumedFrom: journalPath } : {}),
203
+ });
204
+ };
205
+ try {
206
+ if (resumed) {
207
+ const prior = MaintenanceReceiptSchema.parse(JSON.parse(readFileSync(journalPath, 'utf8')));
208
+ if (prior.planDigest !== digest)
209
+ throw new Error('Maintenance journal belongs to a different plan');
210
+ }
211
+ // Recover commits even if interruption happened before the coordinator journal write.
212
+ for (let index = 0; index < selected.length; index++) {
213
+ const committed = await selected[index].receipt(keys[index]);
214
+ if (committed !== undefined)
215
+ entries.push({ operationId: keys[index], owner: selected[index].name, receipt: committed });
216
+ }
217
+ const pending = plan.operations.filter((_, index) => !entries.some(entry => entry.operationId === keys[index]));
218
+ if (pending.length)
219
+ await previewMaintenancePlan({ ...plan, operations: pending }, options.owners);
220
+ writeAtomic(journalPath, receipt());
221
+ for (let index = 0; index < selected.length; index++) {
222
+ if (entries.some(entry => entry.operationId === keys[index]))
223
+ continue;
224
+ const operation = plan.operations[index];
225
+ if (removesResident(operation) && !await verifyMaintenanceRetrieval(operation, options.owners))
226
+ throw new Error('Indexed retrieval is unavailable');
227
+ const result = await selected[index].apply(operation, keys[index]);
228
+ await options.afterOwner?.(index);
229
+ entries.push({ operationId: keys[index], owner: selected[index].name, receipt: result });
230
+ writeAtomic(journalPath, receipt());
231
+ }
232
+ return receipt();
233
+ }
234
+ catch (error) {
235
+ // A thrown remote refresh or interruption can follow a committed local owner mutation.
236
+ for (let index = 0; index < selected.length; index++) {
237
+ if (entries.some(entry => entry.operationId === keys[index]))
238
+ continue;
239
+ try {
240
+ const committed = await selected[index].receipt(keys[index]);
241
+ if (committed !== undefined)
242
+ entries.push({ operationId: keys[index], owner: selected[index].name, receipt: committed });
243
+ }
244
+ catch { /* Unavailable owner remains pending; never claim its success. */ }
245
+ }
246
+ const partial = receipt();
247
+ writeAtomic(journalPath, partial);
248
+ throw new MaintenanceApplyError(error instanceof Error ? error.message : String(error), partial);
249
+ }
250
+ finally {
251
+ await release();
252
+ }
253
+ }
254
+ //# sourceMappingURL=maintenance.js.map
@@ -10,6 +10,7 @@ import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
10
10
  import { homedir } from 'node:os';
11
11
  import path from 'node:path';
12
12
  import { boundedExecFileSync } from '../process/bounded-child-process.mjs';
13
+ import { helperEnvironment } from '../process/cli-command.mjs';
13
14
  import { projectAiwgPath, resolveProjectAiwgDir } from '../config/project-artifacts.js';
14
15
  export function projectMemoryHome() {
15
16
  const override = process.env.AIWG_PROJECT_MEMORY_HOME;
@@ -248,7 +249,7 @@ function sanitizeProjectId(id) {
248
249
  }
249
250
  function discoverGitRemotes(cwd) {
250
251
  try {
251
- const stdout = boundedExecFileSync('git', ['remote', '-v'], 'quick', { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
252
+ const stdout = boundedExecFileSync('git', ['remote', '-v'], 'quick', { cwd, env: helperEnvironment(), encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
252
253
  const remotes = stdout
253
254
  .split('\n')
254
255
  .map((line) => line.trim().split(/\s+/)[1])
@@ -0,0 +1,154 @@
1
+ import path from 'node:path';
2
+ import { homedir } from 'node:os';
3
+ import { resolveHermesHomePath } from '../providers/hermes-home.js';
4
+ import { resolveOmpPaths } from '../providers/omp-paths.mjs';
5
+ import { PROVIDER_IDS, getProviderDefinition, getProviderArtifactPathStrings, resolveProviderPathValue, } from '../providers/provider-definitions.js';
6
+ import { deployedSkillRoots } from '../providers/deployed-skill-roots.js';
7
+ import { resolveMuseXdgSkillsDir } from '../providers/muse-paths.js';
8
+ import { grokBuildUserPaths, resolveGrokHome } from '../providers/grok-build-paths.js';
9
+ const COMMON_LIMITS = [
10
+ 'canonical-edit-and-regenerate', 'immutable-running-session', 'opaque-system-content',
11
+ 'explicit-scope-selection', 'authority-review-required',
12
+ ];
13
+ // Deliberately exhaustive: a new provider needs a reviewed maintenance policy.
14
+ // Paths, ceilings, nesting and loading syntax remain owned by provider definitions.
15
+ const POLICIES = {
16
+ antigravity: { limits: ['runtime-load-unobserved'], sessionEffect: 'next-session' },
17
+ claude: { limits: ['imports-consume-startup-context'], sessionEffect: 'next-session', liveLoadVisibility: true },
18
+ codex: { limits: ['runtime-truncation-and-restart', 'runtime-load-unobserved'], sessionEffect: 'next-session' },
19
+ copilot: { limits: ['no-general-precedence', 'surface-and-enabled-state-required', 'scope-limited-imports', 'runtime-load-unobserved'], sessionEffect: 'next-session' },
20
+ cursor: { limits: ['always-apply-except-globs', 'runtime-load-unobserved'], sessionEffect: 'next-session' },
21
+ 'deepseek-harness': { limits: ['runtime-load-unobserved'], sessionEffect: 'next-session' },
22
+ factory: { limits: ['runtime-load-unobserved'], sessionEffect: 'next-session' },
23
+ grokbot: { limits: ['runtime-load-unobserved'], sessionEffect: 'unknown' },
24
+ 'grok-build': { limits: ['runtime-load-unobserved'], sessionEffect: 'next-session' },
25
+ hermes: { limits: ['write-is-not-reload-proof', 'external-connections-only', 'distinct-native-memory-stores'], sessionEffect: 'next-session' },
26
+ muse: { limits: ['trust-gated-startup', 'runtime-load-unobserved'], sessionEffect: 'unknown' },
27
+ opencode: { limits: ['configuration-registration-mutation', 'runtime-load-unobserved'], sessionEffect: 'next-session' },
28
+ openclaw: { limits: ['durable-and-injected-sizes-separate', 'no-verified-project-startup'], sessionEffect: 'unknown', liveLoadVisibility: true },
29
+ openhuman: { limits: ['runtime-load-unobserved'], sessionEffect: 'unknown' },
30
+ pi: { limits: ['runtime-load-unobserved'], sessionEffect: 'next-session' },
31
+ omp: { limits: ['nearest-nonempty-context', 'depth-ordered-include-deduplication', 'runtime-load-unobserved'], sessionEffect: 'next-session' },
32
+ warp: { limits: ['runtime-load-unobserved'], sessionEffect: 'next-session' },
33
+ windsurf: { limits: ['runtime-load-unobserved'], sessionEffect: 'next-session' },
34
+ generic: { limits: ['indexed-baseline-only'], sessionEffect: 'unknown' },
35
+ };
36
+ function memoryRoots(definition) {
37
+ if (definition.id === 'generic')
38
+ return [];
39
+ const { paths, context } = definition;
40
+ const values = [
41
+ ...Object.values(paths.artifacts), ...Object.values(paths.contextDiscovery),
42
+ paths.kernelSkills, paths.contextFiles.contextFile, paths.contextFiles.hookFile,
43
+ ...context.startupFiles, ...context.bootstrapTargets, context.configRegistration?.file ?? null,
44
+ ...Object.values(getProviderArtifactPathStrings(definition.id) ?? {}),
45
+ // The deployment helper has a Claude compatibility fallback when no kernel
46
+ // root exists. That fallback is not this provider's memory surface.
47
+ ...(paths.kernelSkills ? deployedSkillRoots('.', definition.id) : []),
48
+ ...definition.surfaces.related
49
+ .filter(surface => surface.relationship === 'same-provider' || surface.relationship === 'shared-adapter')
50
+ .flatMap(surface => Object.values(surface.paths).flat()),
51
+ ];
52
+ if (context.includeSyntax) {
53
+ for (const include of context.includeSyntax.split('\n')) {
54
+ // A template such as @<relative-path> is syntax, not a concrete root.
55
+ if (/^@[^<>\s]+$/.test(include))
56
+ values.push(include.slice(1));
57
+ }
58
+ }
59
+ if (definition.skillNamespace.pathType === 'home-dir' && !['grokbot', 'hermes'].includes(definition.id)) {
60
+ values.push(resolveProviderPathValue(`~/${definition.skillNamespace.skillsBaseDir}`, '.'));
61
+ }
62
+ if (definition.id === 'muse')
63
+ values.push(resolveMuseXdgSkillsDir());
64
+ if (definition.id === 'grok-build') {
65
+ const home = resolveGrokHome();
66
+ if (home)
67
+ values.push(...Object.values(grokBuildUserPaths(home)));
68
+ }
69
+ // Native user stores absent from deployment paths. Keep these with the
70
+ // adapter owner so audit never invents another provider path registry.
71
+ if (definition.id === 'claude' || definition.id === 'codex') {
72
+ const home = definition.id === 'claude'
73
+ ? process.env.CLAUDE_CONFIG_DIR || path.join(homedir(), '.claude')
74
+ : process.env.CODEX_HOME || path.join(homedir(), '.codex');
75
+ for (const value of Object.values(paths.artifacts)) {
76
+ if (value?.startsWith(`.${definition.id}/`))
77
+ values.push(path.resolve(home, value.slice(definition.id.length + 2)));
78
+ }
79
+ values.push(path.resolve(home, definition.id === 'claude' ? 'CLAUDE.md' : 'AGENTS.md'));
80
+ if (definition.id === 'codex')
81
+ values.push(path.resolve(home, 'AGENTS.override.md'));
82
+ if (definition.id === 'claude')
83
+ values.push(path.resolve(home, 'projects/*/memory'));
84
+ }
85
+ if (definition.id === 'hermes')
86
+ values.push(resolveHermesHomePath('memories/MEMORY.md'), resolveHermesHomePath('memories/USER.md'));
87
+ if (definition.id === 'omp') {
88
+ const resolved = resolveOmpPaths();
89
+ values.push(path.join(resolved.agentDir, 'AGENTS.md'), ...Object.values(resolved.resourceDirs));
90
+ }
91
+ return [...new Set(values.filter((value) => Boolean(value)))];
92
+ }
93
+ function hasRuntimeEvidence(item, providerId) {
94
+ const { evidence } = item.observation;
95
+ return item.visibility === 'runtime' && Boolean(evidence.source && evidence.at
96
+ && evidence.session && evidence.version && evidence.provider === providerId);
97
+ }
98
+ function createAdapter(definition, policy) {
99
+ const supported = definition.context.support === 'supported';
100
+ const native = definition.id !== 'generic';
101
+ const adapter = {
102
+ providerId: definition.id,
103
+ memoryRoots: () => memoryRoots(definition),
104
+ disposition(item) {
105
+ const { status } = item.observation;
106
+ if (item.visibility === 'hidden' || status === 'opaque')
107
+ return 'opaque';
108
+ if (status === 'observed' && (!policy.liveLoadVisibility || !hasRuntimeEvidence(item, definition.id))) {
109
+ return 'inferred';
110
+ }
111
+ return status;
112
+ },
113
+ supports: { read: native, write: native, estimate: supported, liveLoadVisibility: policy.liveLoadVisibility ?? false },
114
+ sessionEffect: () => policy.sessionEffect,
115
+ context: definition.context,
116
+ limits: [...COMMON_LIMITS, ...policy.limits, ...(!supported ? ['unknown-estimates'] : [])],
117
+ diagnostic: native ? null : 'No native memory surface is supported; use the indexed AIWG baseline.',
118
+ estimate(size) {
119
+ const unknown = { bytes: null, confidence: 'unknown', kind: size.kind };
120
+ if (size.observation.status === 'unknown')
121
+ return unknown;
122
+ const known = { ...size, observation: { ...size.observation, status: size.observation.status } };
123
+ const disposition = adapter.disposition(known);
124
+ if (!supported || !Number.isSafeInteger(size.bytes) || (size.bytes ?? -1) < 0
125
+ || ['opaque', 'absent', 'inaccessible'].includes(disposition))
126
+ return unknown;
127
+ if (size.kind === 'injected') {
128
+ // A durable file's size cannot establish the amount injected into a session.
129
+ if (disposition !== 'observed' || !hasRuntimeEvidence(known, definition.id))
130
+ return unknown;
131
+ return { bytes: size.bytes, confidence: 'measured', kind: size.kind };
132
+ }
133
+ return { bytes: size.bytes, confidence: disposition === 'inferred' ? 'inferred' : 'measured', kind: size.kind };
134
+ },
135
+ };
136
+ return adapter;
137
+ }
138
+ export const PROVIDER_MEMORY_ADAPTERS = new Map(PROVIDER_IDS.map(providerId => {
139
+ const definition = getProviderDefinition(providerId);
140
+ const policy = POLICIES[providerId];
141
+ if (!definition || !policy)
142
+ throw new Error(`Missing memory adapter contract for ${providerId}`);
143
+ return [providerId, createAdapter(definition, policy)];
144
+ }));
145
+ /** Always checks coverage, including generic; never silently skips a missing adapter. */
146
+ export function listProviderMemoryAdapters(registry = PROVIDER_MEMORY_ADAPTERS) {
147
+ return PROVIDER_IDS.map(providerId => {
148
+ const adapter = registry.get(providerId);
149
+ if (!adapter || adapter.providerId !== providerId)
150
+ throw new Error(`Missing memory adapter contract for ${providerId}`);
151
+ return adapter;
152
+ });
153
+ }
154
+ //# sourceMappingURL=provider-memory-adapter.js.map
@@ -0,0 +1,83 @@
1
+ import { memoryUsage, memoryInput, MEMORY_EXIT_USAGE } from './cli-result.js';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { parseMemoryCostOptions, resolveMemoryCostInputs } from './cli.js';
4
+ import { auditMemory } from './audit.js';
5
+ import { formatMemoryRecommendations, recommendMemory, RecommendationInputsSchema } from './recommend.js';
6
+ export const MEMORY_RECOMMEND_USAGE = `Usage: aiwg memory recommend [--scope global|project|provider] [--provider <id>] [--json]
7
+ [--evidence <json-file>] [--usage <json-file>] [--candidate <id> --emit-review-input]
8
+ Read-only recommendations: duplicates, taxonomy, conflicts, supersession, tiers and retirement.
9
+ JSON: aiwg.memory-recommendations.v1. Writes nothing; never approves or applies a plan.
10
+ --evidence supplies per-item owner/provenance/criticality/pin/review/creation/history evidence
11
+ and configurable thresholds. --usage uses the same observed utility input as memory cost.
12
+ Unknown history and rare obligations block retirement. Thresholds are local starting points.
13
+ New knowledge defaults to indexed storage; prefer buildWorkspaceContextPack before residency.
14
+ --emit-review-input prints one selected advisory candidate as JSON to stdout. Save it with
15
+ shell redirection, review it, then use memory plan --recommendation <file> --reviewer <name>
16
+ --out <new-plan-file>. Conflicts and blocked/rejected proposals require owner resolution.
17
+ ${MEMORY_EXIT_USAGE}`;
18
+ export function parseMemoryRecommendOptions(args) {
19
+ const shared = [];
20
+ const extra = {};
21
+ const seen = new Set();
22
+ for (let index = 0; index < args.length; index++) {
23
+ const [flag, inline, ...rest] = args[index].split('=');
24
+ if (['--evidence', '--candidate', '--emit-review-input'].includes(flag)) {
25
+ if (rest.length)
26
+ throw new Error(`Unknown memory recommend argument: ${args[index]}`);
27
+ if (seen.has(flag))
28
+ throw new Error(`Duplicate memory recommend option: ${flag}`);
29
+ seen.add(flag);
30
+ if (flag === '--emit-review-input') {
31
+ if (inline !== undefined)
32
+ throw new Error(`${flag} takes no value`);
33
+ extra.emitReviewInput = true;
34
+ }
35
+ else {
36
+ const value = inline ?? args[++index];
37
+ if (!value || value.startsWith('-'))
38
+ throw new Error(`${flag} requires a value`);
39
+ if (flag === '--evidence')
40
+ extra.evidence = value;
41
+ else
42
+ extra.candidate = value;
43
+ }
44
+ }
45
+ else {
46
+ if (['--demote', '--startup-measurement'].includes(flag))
47
+ throw new Error(`Unknown memory recommend argument: ${args[index]}`);
48
+ shared.push(args[index]);
49
+ if (['--scope', '--provider', '--usage'].includes(flag) && inline === undefined) {
50
+ const value = args[++index];
51
+ if (!value || value.startsWith('-'))
52
+ throw new Error(`${flag} requires a value`);
53
+ shared.push(value);
54
+ }
55
+ }
56
+ }
57
+ // Reuse the audit/cost strict scope and provider conventions.
58
+ const opts = { ...parseMemoryCostOptions(shared), ...extra };
59
+ if (!opts.help && Boolean(opts.emitReviewInput) !== Boolean(opts.candidate))
60
+ throw new Error('--candidate and --emit-review-input must be selected together');
61
+ return opts;
62
+ }
63
+ export async function runMemoryRecommendCli(args) {
64
+ const opts = memoryUsage(() => parseMemoryRecommendOptions(args));
65
+ if (opts.help) {
66
+ console.log(MEMORY_RECOMMEND_USAGE);
67
+ return;
68
+ }
69
+ const input = opts.evidence ? await memoryInput(async () => RecommendationInputsSchema.parse(JSON.parse(await readFile(opts.evidence, 'utf8')))) : {};
70
+ const audit = await auditMemory(opts);
71
+ const report = recommendMemory(audit, input, await memoryInput(() => resolveMemoryCostInputs(opts)));
72
+ if (opts.candidate) {
73
+ const selected = report.candidates.find(c => c.id === opts.candidate);
74
+ if (!selected)
75
+ throw new Error('Recommendation candidate is missing or changed; rerun recommend');
76
+ if (selected.status !== 'advisory')
77
+ throw new Error(`Cannot emit review input: candidate is ${selected.status}: ${selected.blockedReasons.join('; ')}`);
78
+ report.candidates = [selected];
79
+ }
80
+ console.log(opts.json || opts.emitReviewInput ? JSON.stringify(report, null, 2) : formatMemoryRecommendations(report));
81
+ return report.candidates.length || audit.findings.length ? 1 : 0;
82
+ }
83
+ //# sourceMappingURL=recommend-cli.js.map