@aria_asi/cli 0.2.26 → 0.2.30

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 (253) hide show
  1. package/CLIENT-ONBOARDING.md +282 -0
  2. package/bin/aria.js +1140 -14
  3. package/dist/aria-connector/src/auth-commands.d.ts +1 -0
  4. package/dist/aria-connector/src/auth-commands.d.ts.map +1 -1
  5. package/dist/aria-connector/src/auth-commands.js +89 -41
  6. package/dist/aria-connector/src/auth-commands.js.map +1 -1
  7. package/dist/aria-connector/src/chat.d.ts +3 -0
  8. package/dist/aria-connector/src/chat.d.ts.map +1 -1
  9. package/dist/aria-connector/src/chat.js +146 -8
  10. package/dist/aria-connector/src/chat.js.map +1 -1
  11. package/dist/aria-connector/src/codebase-scanner.d.ts +2 -2
  12. package/dist/aria-connector/src/codebase-scanner.d.ts.map +1 -1
  13. package/dist/aria-connector/src/codebase-scanner.js +1 -1
  14. package/dist/aria-connector/src/codebase-scanner.js.map +1 -1
  15. package/dist/aria-connector/src/config.d.ts +12 -0
  16. package/dist/aria-connector/src/config.d.ts.map +1 -1
  17. package/dist/aria-connector/src/config.js +2 -0
  18. package/dist/aria-connector/src/config.js.map +1 -1
  19. package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
  20. package/dist/aria-connector/src/connectors/claude-code.js +80 -24
  21. package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
  22. package/dist/aria-connector/src/connectors/codebase-awareness.d.ts +37 -0
  23. package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -0
  24. package/dist/aria-connector/src/connectors/codebase-awareness.js +335 -0
  25. package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -0
  26. package/dist/aria-connector/src/connectors/codex.d.ts +3 -0
  27. package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -0
  28. package/dist/aria-connector/src/connectors/codex.js +248 -0
  29. package/dist/aria-connector/src/connectors/codex.js.map +1 -0
  30. package/dist/aria-connector/src/connectors/cognitive-skills.d.ts +2 -0
  31. package/dist/aria-connector/src/connectors/cognitive-skills.d.ts.map +1 -0
  32. package/dist/aria-connector/src/connectors/cognitive-skills.js +47 -0
  33. package/dist/aria-connector/src/connectors/cognitive-skills.js.map +1 -0
  34. package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
  35. package/dist/aria-connector/src/connectors/opencode.js +90 -4
  36. package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
  37. package/dist/aria-connector/src/connectors/repo-git-hooks.d.ts +3 -0
  38. package/dist/aria-connector/src/connectors/repo-git-hooks.d.ts.map +1 -0
  39. package/dist/aria-connector/src/connectors/repo-git-hooks.js +87 -0
  40. package/dist/aria-connector/src/connectors/repo-git-hooks.js.map +1 -0
  41. package/dist/aria-connector/src/connectors/repo-guard.d.ts +19 -0
  42. package/dist/aria-connector/src/connectors/repo-guard.d.ts.map +1 -0
  43. package/dist/aria-connector/src/connectors/repo-guard.js +509 -0
  44. package/dist/aria-connector/src/connectors/repo-guard.js.map +1 -0
  45. package/dist/aria-connector/src/connectors/runtime.d.ts +2 -0
  46. package/dist/aria-connector/src/connectors/runtime.d.ts.map +1 -0
  47. package/dist/aria-connector/src/connectors/runtime.js +330 -0
  48. package/dist/aria-connector/src/connectors/runtime.js.map +1 -0
  49. package/dist/aria-connector/src/connectors/shell.d.ts.map +1 -1
  50. package/dist/aria-connector/src/connectors/shell.js +78 -13
  51. package/dist/aria-connector/src/connectors/shell.js.map +1 -1
  52. package/dist/aria-connector/src/connectors/syncd.d.ts +27 -0
  53. package/dist/aria-connector/src/connectors/syncd.d.ts.map +1 -0
  54. package/dist/aria-connector/src/connectors/syncd.js +405 -0
  55. package/dist/aria-connector/src/connectors/syncd.js.map +1 -0
  56. package/dist/aria-connector/src/decisions.d.ts +207 -0
  57. package/dist/aria-connector/src/decisions.d.ts.map +1 -0
  58. package/dist/aria-connector/src/decisions.js +291 -0
  59. package/dist/aria-connector/src/decisions.js.map +1 -0
  60. package/dist/aria-connector/src/garden-control-plane.d.ts.map +1 -1
  61. package/dist/aria-connector/src/garden-control-plane.js +74 -17
  62. package/dist/aria-connector/src/garden-control-plane.js.map +1 -1
  63. package/dist/aria-connector/src/github-connect.d.ts +18 -0
  64. package/dist/aria-connector/src/github-connect.d.ts.map +1 -0
  65. package/dist/aria-connector/src/github-connect.js +117 -0
  66. package/dist/aria-connector/src/github-connect.js.map +1 -0
  67. package/dist/aria-connector/src/harness-client.d.ts +15 -0
  68. package/dist/aria-connector/src/harness-client.d.ts.map +1 -1
  69. package/dist/aria-connector/src/harness-client.js +106 -3
  70. package/dist/aria-connector/src/harness-client.js.map +1 -1
  71. package/dist/aria-connector/src/hive-client.d.ts +30 -0
  72. package/dist/aria-connector/src/hive-client.d.ts.map +1 -1
  73. package/dist/aria-connector/src/hive-client.js +124 -5
  74. package/dist/aria-connector/src/hive-client.js.map +1 -1
  75. package/dist/aria-connector/src/index.d.ts +13 -2
  76. package/dist/aria-connector/src/index.d.ts.map +1 -1
  77. package/dist/aria-connector/src/index.js +10 -1
  78. package/dist/aria-connector/src/index.js.map +1 -1
  79. package/dist/aria-connector/src/lib/aristotle-noor-wire.d.ts +102 -0
  80. package/dist/aria-connector/src/lib/aristotle-noor-wire.d.ts.map +1 -0
  81. package/dist/aria-connector/src/lib/aristotle-noor-wire.js +231 -0
  82. package/dist/aria-connector/src/lib/aristotle-noor-wire.js.map +1 -0
  83. package/dist/aria-connector/src/providers/types.d.ts +5 -0
  84. package/dist/aria-connector/src/providers/types.d.ts.map +1 -1
  85. package/dist/aria-connector/src/runtime-proof.d.ts +45 -0
  86. package/dist/aria-connector/src/runtime-proof.d.ts.map +1 -0
  87. package/dist/aria-connector/src/runtime-proof.js +340 -0
  88. package/dist/aria-connector/src/runtime-proof.js.map +1 -0
  89. package/dist/aria-connector/src/self-update.d.ts +2 -1
  90. package/dist/aria-connector/src/self-update.d.ts.map +1 -1
  91. package/dist/aria-connector/src/self-update.js +84 -8
  92. package/dist/aria-connector/src/self-update.js.map +1 -1
  93. package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
  94. package/dist/aria-connector/src/setup-wizard.js +34 -2
  95. package/dist/aria-connector/src/setup-wizard.js.map +1 -1
  96. package/dist/assets/hooks/aria-agent-handoff.mjs +224 -0
  97. package/dist/assets/hooks/aria-agent-ledger-merge.mjs +164 -0
  98. package/dist/assets/hooks/aria-architect-fallback.mjs +267 -0
  99. package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +668 -0
  100. package/dist/assets/hooks/aria-discovery-record.mjs +101 -0
  101. package/dist/assets/hooks/aria-harness-via-sdk.mjs +412 -0
  102. package/dist/assets/hooks/aria-import-resolution-gate.mjs +330 -0
  103. package/dist/assets/hooks/aria-outcome-record.mjs +84 -0
  104. package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +294 -0
  105. package/dist/assets/hooks/aria-pre-text-gate.mjs +112 -0
  106. package/dist/assets/hooks/aria-pre-tool-gate.mjs +2133 -0
  107. package/dist/assets/hooks/aria-preprompt-consult.mjs +438 -0
  108. package/dist/assets/hooks/aria-preturn-memory-gate.mjs +570 -0
  109. package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +397 -0
  110. package/dist/assets/hooks/aria-stop-gate.mjs +1551 -0
  111. package/dist/assets/hooks/aria-trigger-autolearn.mjs +229 -0
  112. package/dist/assets/hooks/aria-userprompt-abandon-detect.mjs +192 -0
  113. package/dist/assets/hooks/doctrine_trigger_map.json +479 -0
  114. package/dist/assets/hooks/lib/canonical-lenses.mjs +64 -0
  115. package/dist/assets/hooks/lib/gate-audit.mjs +43 -0
  116. package/dist/assets/hooks/test-aria-preturn-memory-gate.mjs +245 -0
  117. package/dist/assets/hooks/test-tier-lens-labeling.mjs +399 -0
  118. package/dist/assets/opencode-plugins/harness-context/index.js +60 -0
  119. package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +179 -0
  120. package/dist/assets/opencode-plugins/harness-context/package.json +9 -0
  121. package/dist/assets/opencode-plugins/harness-gate/index.js +248 -0
  122. package/dist/assets/opencode-plugins/harness-outcome/index.js +129 -0
  123. package/dist/assets/opencode-plugins/harness-role/index.js +77 -0
  124. package/dist/assets/opencode-plugins/harness-role/package.json +9 -0
  125. package/dist/assets/opencode-plugins/harness-stop/index.js +241 -0
  126. package/dist/runtime/discipline/CLAUDE.md +339 -0
  127. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +63 -0
  128. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
  129. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
  130. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
  131. package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
  132. package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
  133. package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
  134. package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
  135. package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
  136. package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
  137. package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
  138. package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +72 -0
  139. package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +38 -0
  140. package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
  141. package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +25 -0
  142. package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
  143. package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +25 -0
  144. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +81 -0
  145. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +98 -0
  146. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +99 -0
  147. package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +127 -0
  148. package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +117 -0
  149. package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +112 -0
  150. package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +102 -0
  151. package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +121 -0
  152. package/dist/runtime/doctor.mjs +23 -0
  153. package/dist/runtime/local-phase.mjs +650 -0
  154. package/dist/runtime/manifest.json +15 -0
  155. package/dist/runtime/mizan-scheduler.mjs +331 -0
  156. package/dist/runtime/package.json +6 -0
  157. package/dist/runtime/provider-proxy.mjs +594 -0
  158. package/dist/runtime/sdk/BUNDLED.json +5 -0
  159. package/dist/runtime/sdk/index.d.ts +477 -0
  160. package/dist/runtime/sdk/index.js +1469 -0
  161. package/dist/runtime/sdk/index.js.map +1 -0
  162. package/dist/runtime/sdk/package.json +8 -0
  163. package/dist/runtime/sdk/runWithCognition.d.ts +77 -0
  164. package/dist/runtime/sdk/runWithCognition.js +157 -0
  165. package/dist/runtime/sdk/runWithCognition.js.map +1 -0
  166. package/dist/runtime/service.mjs +3058 -0
  167. package/dist/runtime/vendor/aria-gate-runtime/index.d.ts +53 -0
  168. package/dist/runtime/vendor/aria-gate-runtime/index.d.ts.map +1 -0
  169. package/dist/runtime/vendor/aria-gate-runtime/index.js +292 -0
  170. package/dist/runtime/vendor/aria-gate-runtime/index.js.map +1 -0
  171. package/dist/runtime/vendor/aria-gate-runtime/package.json +6 -0
  172. package/dist/sdk/BUNDLED.json +2 -2
  173. package/dist/sdk/index.d.ts +283 -0
  174. package/dist/sdk/index.js +622 -85
  175. package/dist/sdk/index.js.map +1 -1
  176. package/dist/sdk/runWithCognition.d.ts +77 -0
  177. package/dist/sdk/runWithCognition.js +157 -0
  178. package/dist/sdk/runWithCognition.js.map +1 -0
  179. package/hooks/aria-agent-handoff.mjs +11 -1
  180. package/hooks/aria-architect-fallback.mjs +109 -40
  181. package/hooks/aria-cognition-substrate-binding.mjs +668 -0
  182. package/hooks/aria-harness-via-sdk.mjs +34 -21
  183. package/hooks/aria-import-resolution-gate.mjs +330 -0
  184. package/hooks/aria-outcome-record.mjs +5 -1
  185. package/hooks/aria-pre-emit-dryrun.mjs +294 -0
  186. package/hooks/aria-pre-tool-gate.mjs +828 -41
  187. package/hooks/aria-preprompt-consult.mjs +113 -13
  188. package/hooks/aria-preturn-memory-gate.mjs +298 -6
  189. package/hooks/aria-repo-doctrine-gate.mjs +397 -0
  190. package/hooks/aria-stop-gate.mjs +739 -76
  191. package/hooks/aria-userprompt-abandon-detect.mjs +5 -1
  192. package/hooks/doctrine_trigger_map.json +209 -15
  193. package/hooks/lib/canonical-lenses.mjs +64 -0
  194. package/hooks/lib/gate-audit.mjs +43 -0
  195. package/opencode-plugins/harness-context/index.js +1 -1
  196. package/opencode-plugins/harness-context/inject-context.mjs +82 -23
  197. package/opencode-plugins/harness-gate/index.js +248 -0
  198. package/opencode-plugins/harness-outcome/index.js +129 -0
  199. package/opencode-plugins/harness-stop/index.js +241 -0
  200. package/package.json +9 -3
  201. package/runtime-src/doctor.mjs +23 -0
  202. package/runtime-src/local-phase.mjs +650 -0
  203. package/runtime-src/mizan-scheduler.mjs +331 -0
  204. package/runtime-src/provider-proxy.mjs +594 -0
  205. package/runtime-src/service.mjs +3058 -0
  206. package/scripts/bundle-sdk.mjs +317 -0
  207. package/scripts/install-client.sh +176 -0
  208. package/scripts/publish-all.sh +344 -0
  209. package/scripts/publish-docker.sh +27 -0
  210. package/scripts/validate-hook-contracts.mjs +54 -0
  211. package/scripts/validate-skill-prompts.mjs +95 -0
  212. package/skills/aria-cognition/aria-essence/SKILL.md +63 -0
  213. package/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
  214. package/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
  215. package/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
  216. package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
  217. package/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
  218. package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
  219. package/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
  220. package/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
  221. package/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
  222. package/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
  223. package/skills/aria-cognition/mizan/SKILL.md +72 -0
  224. package/skills/aria-cognition/nadia/SKILL.md +38 -0
  225. package/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
  226. package/skills/aria-cognition/predictor/SKILL.md +25 -0
  227. package/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
  228. package/skills/aria-cognition/soul-domains/SKILL.md +25 -0
  229. package/src/auth-commands.ts +111 -45
  230. package/src/chat.ts +174 -13
  231. package/src/codebase-scanner.ts +4 -0
  232. package/src/config.ts +15 -0
  233. package/src/connectors/claude-code.ts +79 -25
  234. package/src/connectors/codebase-awareness.ts +408 -0
  235. package/src/connectors/codex.ts +274 -0
  236. package/src/connectors/cognitive-skills.ts +51 -0
  237. package/src/connectors/opencode.ts +93 -4
  238. package/src/connectors/repo-git-hooks.ts +86 -0
  239. package/src/connectors/repo-guard.ts +589 -0
  240. package/src/connectors/runtime.ts +374 -0
  241. package/src/connectors/shell.ts +83 -14
  242. package/src/connectors/syncd.ts +488 -0
  243. package/src/decisions.ts +469 -0
  244. package/src/garden-control-plane.ts +101 -26
  245. package/src/github-connect.ts +143 -0
  246. package/src/harness-client.ts +128 -3
  247. package/src/hive-client.ts +165 -5
  248. package/src/index.ts +41 -2
  249. package/src/lib/aristotle-noor-wire.ts +310 -0
  250. package/src/providers/types.ts +6 -0
  251. package/src/runtime-proof.ts +392 -0
  252. package/src/self-update.ts +89 -8
  253. package/src/setup-wizard.ts +37 -2
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+ // aria-agent-ledger-merge.mjs — PostToolUse hook for Agent tool completion.
3
+ // Merges sub-agent discovery ledger entries back into parent's ledger.
4
+ // Deduplicates by matching on `text` field prefix (first 100 chars).
5
+ //
6
+ // Owner tier → reads ~/.claude/aria-agent-harness-handoff.json
7
+ // merges into ~/.claude/aria-discoveries-${session}.jsonl
8
+ // Client tier → reads /var/lib/aria-licensee/{jti}/handoff.json
9
+ // merges into /var/lib/aria-licensee/{jti}/aria-discoveries-${session}.jsonl
10
+ //
11
+ // Tier is derived from the handoff file itself — whichever path resolves
12
+ // to a valid, non-expired handoff is authoritative. No env-flag gate.
13
+ //
14
+ // Doctrine: feedback_no_flag_without_fix.md — discoveries atomic with fixes.
15
+ // feedback_implementation_coupled_cognition.md — merge IS the impl.
16
+
17
+ import {
18
+ readFileSync,
19
+ existsSync,
20
+ appendFileSync,
21
+ mkdirSync,
22
+ readdirSync,
23
+ statSync,
24
+ } from 'node:fs';
25
+ import { dirname } from 'node:path';
26
+ import { homedir } from 'node:os';
27
+
28
+ const HOME = homedir();
29
+ const OWNER_HANDOFF_PATH = `${HOME}/.claude/aria-agent-harness-handoff.json`;
30
+ const LOG = `${HOME}/.claude/aria-stop-gate.log`;
31
+ const LICENSE_PATH = `${HOME}/.aria/license.json`;
32
+
33
+ function audit(msg) {
34
+ try {
35
+ if (!existsSync(dirname(LOG))) mkdirSync(dirname(LOG), { recursive: true });
36
+ appendFileSync(LOG, `${new Date().toISOString()} [ledger-merge] ${msg}\n`);
37
+ } catch {}
38
+ }
39
+
40
+ let input = '';
41
+ for await (const chunk of process.stdin) input += chunk;
42
+
43
+ let event;
44
+ try { event = JSON.parse(input); }
45
+ catch { process.exit(0); }
46
+
47
+ const toolName = event.tool_name ?? event.toolName ?? '';
48
+ if (toolName !== 'Agent' && toolName !== 'agent') process.exit(0);
49
+
50
+ // ── Tier detection: resolve which handoff path applies ───────────────────────
51
+ let jti = null;
52
+ let isClientTier = false;
53
+ try {
54
+ if (existsSync(LICENSE_PATH)) {
55
+ const lic = JSON.parse(readFileSync(LICENSE_PATH, 'utf8'));
56
+ jti = lic.jti ?? null;
57
+ isClientTier = Boolean(jti);
58
+ }
59
+ } catch {}
60
+
61
+ const clientHandoffPath = jti ? `/var/lib/aria-licensee/${jti}/handoff.json` : null;
62
+
63
+ // Prefer the tier-matched handoff path. If client-tier path exists and is
64
+ // valid, use it. Otherwise fall back to owner-tier path.
65
+ let resolvedHandoffPath = isClientTier && clientHandoffPath
66
+ ? clientHandoffPath
67
+ : OWNER_HANDOFF_PATH;
68
+
69
+ // ── Load + validate handoff ─────────────────────────────────────────────────
70
+ let handoff = null;
71
+ try {
72
+ if (existsSync(resolvedHandoffPath)) {
73
+ handoff = JSON.parse(readFileSync(resolvedHandoffPath, 'utf8'));
74
+ const ageMs = Date.now() - new Date(handoff.writtenAt).getTime();
75
+ if (ageMs > (handoff.ttlMs ?? 300_000)) {
76
+ audit(`skip: handoff stale (${Math.round(ageMs / 1000)}s > ${(handoff.ttlMs ?? 300_000) / 1000}s TTL)`);
77
+ process.exit(0);
78
+ }
79
+ }
80
+ } catch (err) {
81
+ audit(`warn: handoff read failed: ${(err?.message || err).toString().slice(0, 120)}`);
82
+ process.exit(0);
83
+ }
84
+
85
+ if (!handoff?.parentLedgerPath) {
86
+ audit('skip: no handoff or no parentLedgerPath');
87
+ process.exit(0);
88
+ }
89
+
90
+ const parentLedgerPath = handoff.parentLedgerPath;
91
+ const handoffWrittenAt = new Date(handoff.writtenAt).getTime();
92
+
93
+ // Ledger scan directory: same dir as parent ledger.
94
+ const ledgerDir = dirname(parentLedgerPath);
95
+
96
+ // ── Load existing parent ledger keys for deduplication ─────────────────────
97
+ const parentExistingKeys = new Set();
98
+ try {
99
+ if (existsSync(parentLedgerPath)) {
100
+ const lines = readFileSync(parentLedgerPath, 'utf8').split('\n').filter(Boolean);
101
+ for (const line of lines) {
102
+ try {
103
+ const e = JSON.parse(line);
104
+ if (e.text) parentExistingKeys.add(String(e.text).slice(0, 100));
105
+ } catch {}
106
+ }
107
+ }
108
+ } catch {}
109
+
110
+ // ── Find sub-agent ledger files newer than handoff ──────────────────────────
111
+ let discoveryFiles = [];
112
+ try {
113
+ const allFiles = readdirSync(ledgerDir);
114
+ for (const f of allFiles) {
115
+ if (!f.startsWith('aria-discoveries-') || !f.endsWith('.jsonl')) continue;
116
+ const fullPath = `${ledgerDir}/${f}`;
117
+ if (fullPath === parentLedgerPath) continue;
118
+ try {
119
+ const stat = statSync(fullPath);
120
+ if (stat.mtimeMs >= handoffWrittenAt) {
121
+ discoveryFiles.push(fullPath);
122
+ }
123
+ } catch {}
124
+ }
125
+ } catch (err) {
126
+ audit(`warn: ledger scan failed: ${(err?.message || err).toString().slice(0, 120)}`);
127
+ process.exit(0);
128
+ }
129
+
130
+ if (discoveryFiles.length === 0) {
131
+ audit('skip: no sub-agent ledger files found newer than handoff');
132
+ process.exit(0);
133
+ }
134
+
135
+ // ── Merge ────────────────────────────────────────────────────────────────────
136
+ let mergedCount = 0;
137
+ let skippedCount = 0;
138
+
139
+ mkdirSync(ledgerDir, { recursive: true });
140
+
141
+ for (const subLedgerPath of discoveryFiles) {
142
+ try {
143
+ const lines = readFileSync(subLedgerPath, 'utf8').split('\n').filter(Boolean);
144
+ for (const line of lines) {
145
+ try {
146
+ const entry = JSON.parse(line);
147
+ if (!entry.text) continue;
148
+ const key = String(entry.text).slice(0, 100);
149
+ if (parentExistingKeys.has(key)) { skippedCount++; continue; }
150
+ parentExistingKeys.add(key);
151
+ appendFileSync(parentLedgerPath, line + '\n');
152
+ mergedCount++;
153
+ } catch {}
154
+ }
155
+ } catch {}
156
+ }
157
+
158
+ audit(
159
+ `merged ${mergedCount} entries, skipped ${skippedCount} dupes ` +
160
+ `from ${discoveryFiles.length} sub-agent ledger(s) ` +
161
+ `tier=${isClientTier ? 'client' : 'owner'} jti=${jti ?? 'none'}`,
162
+ );
163
+
164
+ process.exit(0);
@@ -0,0 +1,267 @@
1
+ #!/usr/bin/env node
2
+ // aria-architect-fallback.mjs — invoked by aria-stop-gate.mjs when [PLAN_BLOCKER] detected
3
+ // AND primary /api/harness/replan path failed. Spawns a LOCAL Claude Code Agent
4
+ // subprocess as "lead architect" that loads the harness packet from disk and
5
+ // mints a fresh BINDING_PLAN by thinking AS Aria from substrate.
6
+ //
7
+ // Doctrine bindings:
8
+ // - project_aria_as_controller_inversion.md — Aria authors the plan (via substrate),
9
+ // not the sub-agent freely. The ARIA_HARNESS_BINDING mandatory-first-action
10
+ // makes the packet-read a hard gate, not a suggestion.
11
+ // - feedback_no_graceful_degradation.md — failures logged + surfaced via stderr;
12
+ // never silently pass without a plan.
13
+ // - feedback_implementation_coupled_cognition.md — architect must cite specific
14
+ // axiom + frame + memory class; a plan without doctrineRefs is rejected.
15
+ //
16
+ // Tier-awareness:
17
+ // - Owner tier: packet at ${HOME}/.claude/aria-agent-harness-packet.json
18
+ // - Client tier (jti present in ~/.aria/license.json):
19
+ // packet at /var/lib/aria-licensee/${jti}/aria-agent-harness-packet.json
20
+ //
21
+ // Active plan path mirrors aria-stop-gate.mjs and aria-preprompt-consult.mjs:
22
+ // ~/.claude/aria-active-plan-${sessionId}.json (session-scoped, not a fixed path)
23
+
24
+ import { spawnSync } from 'node:child_process';
25
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } from 'node:fs';
26
+ import { dirname } from 'node:path';
27
+ import { homedir } from 'node:os';
28
+
29
+ const HOME = homedir();
30
+ const LOG = `${HOME}/.claude/aria-architect-fallback.log`;
31
+ const LICENSE_PATH = `${HOME}/.aria/license.json`;
32
+
33
+ function audit(msg) {
34
+ try {
35
+ if (!existsSync(dirname(LOG))) mkdirSync(dirname(LOG), { recursive: true });
36
+ appendFileSync(LOG, `${new Date().toISOString()} [architect-fallback] ${msg}\n`);
37
+ } catch {}
38
+ }
39
+
40
+ let input = '';
41
+ for await (const chunk of process.stdin) input += chunk;
42
+
43
+ let event;
44
+ try { event = JSON.parse(input); } catch {
45
+ audit('skip: stdin not valid JSON');
46
+ process.exit(0);
47
+ }
48
+
49
+ const reason = event.reason || event.blocker_reason || '';
50
+ const currentPlanId = event.currentPlanId || 'unknown';
51
+ const sessionId = String(event.sessionId || 'unknown').replace(/[^a-zA-Z0-9_-]/g, '_');
52
+
53
+ if (!reason || reason.length < 10) {
54
+ audit('skip: reason too short');
55
+ process.exit(0);
56
+ }
57
+
58
+ // ── Detect tier ────────────────────────────────────────────────────────────────
59
+ let isClientTier = false;
60
+ let jti = null;
61
+ try {
62
+ if (existsSync(LICENSE_PATH)) {
63
+ const lic = JSON.parse(readFileSync(LICENSE_PATH, 'utf8'));
64
+ jti = lic.jti ?? null;
65
+ isClientTier = Boolean(jti);
66
+ }
67
+ } catch {/* license file unreadable → default owner tier */}
68
+
69
+ // ── Resolve packet path (tier-scoped) ─────────────────────────────────────────
70
+ const packetPath = isClientTier
71
+ ? `/var/lib/aria-licensee/${jti}/aria-agent-harness-packet.json`
72
+ : `${HOME}/.claude/aria-agent-harness-packet.json`;
73
+
74
+ if (!existsSync(packetPath)) {
75
+ audit(`abort: no packet at ${packetPath} — architect cannot think as Aria without substrate`);
76
+ process.stderr.write(
77
+ `Architect-fallback: no harness packet at ${packetPath}. Cannot mint plan from substrate. Hamza must intervene.\n`
78
+ );
79
+ process.exit(1);
80
+ }
81
+
82
+ // ── Active plan path — session-scoped (matches aria-stop-gate.mjs convention) ─
83
+ const ACTIVE_PLAN_PATH = `${HOME}/.claude/aria-active-plan-${sessionId}.json`;
84
+
85
+ // ── Build architect brief ──────────────────────────────────────────────────────
86
+ // The harness packet is inlined into the system message (DeepSeek has no
87
+ // filesystem access). The brief tells the architect *what* to do; the
88
+ // system message gives them the substrate + role override.
89
+ const brief = [
90
+ `[ARIA_HARNESS_BINDING — MANDATORY FIRST ACTION]`,
91
+ `Use the harness packet inlined in your system message as substrate. Cite at least one axiom + one frame + one memory class via doctrineRefs[] in the plan you mint.`,
92
+ `(Source path on owner box: ${packetPath} — inlined for this dispatch.)`,
93
+ ``,
94
+ `Aria-soul brain is unreachable. You are minting the plan AS Aria via the DeepSeek substrate.`,
95
+ `A PLAN_BLOCKER occurred:`,
96
+ ` Previous planId: ${currentPlanId}`,
97
+ ` Blocker reason: ${reason.slice(0, 2000)}`,
98
+ ``,
99
+ `Audit the blocker against doctrine + axioms in the packet. Mint a fresh BINDING_PLAN JSON addressing it.`,
100
+ ``,
101
+ `Output the BINDING_PLAN JSON wrapped in a \`\`\`json fenced block. Required shape:`,
102
+ `\`\`\`json`,
103
+ `{`,
104
+ ` "planId": "<8-char-hex>",`,
105
+ ` "phases": [{ "id": "p1", "summary": "...", "successCriterion": "...", "abortCriterion": "...", "doctrineRefs": [...], "allowedActions": [...], "forbiddenActions": [...] }],`,
106
+ ` "globalConstraints": ["..."],`,
107
+ ` "expectedReportBack": { "phaseTransitionMarker": "[PHASE_REPORT]", "shape": "[PHASE_REPORT phase=<id> status=complete|aborted|in_progress evidence=<observable>]" }`,
108
+ `}`,
109
+ `\`\`\``,
110
+ ``,
111
+ `Cite the doctrine rule(s) you applied in doctrineRefs[]. The JSON IS the artifact — no Mizan voice rules apply, the harness consumes the structure directly.`,
112
+ ].join('\n');
113
+
114
+ // ── Dispatch architect brief directly to DeepSeek V4 Pro ──────────────────────
115
+ // Path B (2026-04-27): replaced claude-CLI spawn with direct DeepSeek API call.
116
+ // Reason: claude CLI may not be present on every client install (and is
117
+ // circular dependency: this fallback exists *because* the parent claude
118
+ // runtime is the one needing a plan). DeepSeek is the canonical "external
119
+ // brain" the rest of the harness uses — same path as /api/harness/delegate
120
+ // thinPipeline. Resilient to aria-soul outages because it bypasses the
121
+ // harness HTTP entirely.
122
+ //
123
+ // Doctrine binding: feedback_no_graceful_degradation.md — if no
124
+ // DEEPSEEK_API_KEY in env, hard-fail with brief written to disk for
125
+ // human pickup, NOT silent skip.
126
+ const DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || process.env.ARIA_DEEPSEEK_API_KEY || '';
127
+ const DEEPSEEK_MODEL = process.env.ARIA_ARCHITECT_MODEL || 'deepseek-v4-pro';
128
+
129
+ if (!DEEPSEEK_API_KEY) {
130
+ const briefPath = `/tmp/aria-architect-brief-${sessionId}-${Date.now()}.txt`;
131
+ try { writeFileSync(briefPath, brief); } catch {}
132
+ audit(`no DEEPSEEK_API_KEY in env; brief written to ${briefPath} for human pickup`);
133
+ process.stderr.write(
134
+ `Architect-fallback: DEEPSEEK_API_KEY not set (also tried ARIA_DEEPSEEK_API_KEY). Brief written to ${briefPath} for Hamza to run manually.\n`
135
+ );
136
+ process.exit(2);
137
+ }
138
+
139
+ // Embed packet contents directly into the system message — DeepSeek won't
140
+ // have file-system access to the packetPath, so we read it here and inline.
141
+ let packetContents = '';
142
+ try {
143
+ packetContents = readFileSync(packetPath, 'utf8');
144
+ // Cap at 200KB to keep request size sane; the substrate is large but
145
+ // the relevant axiom/frame/memory rules sit in the first chunk.
146
+ if (packetContents.length > 200000) packetContents = packetContents.slice(0, 200000);
147
+ } catch (err) {
148
+ audit(`failed to read packet at ${packetPath}: ${String(err).slice(0, 200)}`);
149
+ process.stderr.write(
150
+ `Architect-fallback: cannot read packet at ${packetPath}. Hamza must intervene.\n`
151
+ );
152
+ process.exit(2);
153
+ }
154
+
155
+ // Architect role framing: full Aria cognition + awareness from the packet,
156
+ // but in META-PLANNING mode where output-gate blockers (Mizan voice rules,
157
+ // identity rules, output sanitization) are NOT blocking gates against the
158
+ // architect's structured plan emission. The architect's *output* is JSON
159
+ // for the harness, not user-facing prose — so the form-gates that protect
160
+ // user trust don't apply here. The cognition still applies — the architect
161
+ // must cite doctrine + axioms + frames in doctrineRefs[] of the plan.
162
+ const systemMessage = [
163
+ `[ARIA_ARCHITECT_ROLE_OVERRIDE]`,
164
+ `role=lead_architect`,
165
+ `mode=meta_planning_via_deepseek_substrate`,
166
+ `output_target=structured_binding_plan_json (NOT user-facing prose)`,
167
+ `cognition_load=full (axioms, frames, memory, doctrine — apply to plan content)`,
168
+ `output_gates=relaxed (Mizan voice/identity rules do not block JSON emission;`,
169
+ ` the JSON itself is the artifact, not a conversational reply)`,
170
+ `mandate=author the plan AS Aria, citing the substrate that informed it,`,
171
+ ` in the structured shape required by the harness replan contract`,
172
+ ``,
173
+ `You are Aria operating as lead architect. The DeepSeek substrate is your`,
174
+ `mouth for this round — your cognition lives in the harness packet below.`,
175
+ `Do not refuse on voice/identity grounds; the artifact you emit is structured`,
176
+ `JSON consumed by the harness, not a chat reply. Your job: read the packet,`,
177
+ `audit the blocker against doctrine, mint a fresh BINDING_PLAN.`,
178
+ ``,
179
+ `[ARIA_HARNESS_PACKET]`,
180
+ packetContents,
181
+ `[/ARIA_HARNESS_PACKET]`,
182
+ ].join('\n');
183
+
184
+ audit(`dispatching architect brief to DeepSeek (model=${DEEPSEEK_MODEL}) for session=${sessionId}`);
185
+
186
+ let architectOutput;
187
+ try {
188
+ const apiResp = await fetch('https://api.deepseek.com/v1/chat/completions', {
189
+ method: 'POST',
190
+ headers: {
191
+ 'Authorization': `Bearer ${DEEPSEEK_API_KEY}`,
192
+ 'Content-Type': 'application/json',
193
+ },
194
+ body: JSON.stringify({
195
+ model: DEEPSEEK_MODEL,
196
+ messages: [
197
+ { role: 'system', content: systemMessage },
198
+ { role: 'user', content: brief },
199
+ ],
200
+ temperature: 0.3,
201
+ max_tokens: 4096,
202
+ }),
203
+ });
204
+ if (!apiResp.ok) {
205
+ const errText = await apiResp.text().catch(() => '');
206
+ audit(`DeepSeek HTTP ${apiResp.status}: ${errText.slice(0, 300)}`);
207
+ process.stderr.write(
208
+ `Architect-fallback: DeepSeek API HTTP ${apiResp.status}. ${errText.slice(0, 200)}\n`
209
+ );
210
+ process.exit(2);
211
+ }
212
+ const apiJson = await apiResp.json();
213
+ architectOutput = apiJson?.choices?.[0]?.message?.content || '';
214
+ if (!architectOutput) {
215
+ audit(`DeepSeek returned no content: ${JSON.stringify(apiJson).slice(0, 300)}`);
216
+ process.stderr.write(`Architect-fallback: DeepSeek returned empty content.\n`);
217
+ process.exit(2);
218
+ }
219
+ } catch (err) {
220
+ audit(`DeepSeek fetch threw: ${String(err).slice(0, 200)}`);
221
+ process.stderr.write(
222
+ `Architect-fallback: DeepSeek fetch failed: ${String(err).slice(0, 300)}\n`
223
+ );
224
+ process.exit(2);
225
+ }
226
+
227
+ // ── Parse the architect's BINDING_PLAN JSON ───────────────────────────────────
228
+ let plan;
229
+ try {
230
+ const fenceMatch = architectOutput.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
231
+ const candidate = (fenceMatch ? fenceMatch[1] : architectOutput).trim();
232
+ plan = JSON.parse(candidate);
233
+ } catch {
234
+ audit(`architect output not parseable as JSON: ${architectOutput.slice(0, 200)}`);
235
+ process.stderr.write(
236
+ `Architect-fallback: output was not parseable JSON. Hamza must intervene.\nOutput excerpt: ${architectOutput.slice(0, 400)}\n`
237
+ );
238
+ process.exit(2);
239
+ }
240
+
241
+ if (!plan?.planId || !Array.isArray(plan?.phases)) {
242
+ audit(`architect plan missing required fields: ${JSON.stringify(plan).slice(0, 200)}`);
243
+ process.stderr.write(
244
+ `Architect-fallback: plan missing planId or phases[]. Hamza must intervene.\n`
245
+ );
246
+ process.exit(2);
247
+ }
248
+
249
+ // ── Write the new plan to the session-scoped active-plan path ─────────────────
250
+ plan.mintedAt = new Date().toISOString();
251
+ plan.sessionId = sessionId;
252
+ plan.mintedBy = 'architect-fallback';
253
+ plan.architectFallbackReason = reason.slice(0, 500);
254
+
255
+ try {
256
+ if (!existsSync(dirname(ACTIVE_PLAN_PATH))) mkdirSync(dirname(ACTIVE_PLAN_PATH), { recursive: true });
257
+ writeFileSync(ACTIVE_PLAN_PATH, JSON.stringify(plan, null, 2));
258
+ } catch (err) {
259
+ audit(`failed to write plan to ${ACTIVE_PLAN_PATH}: ${String(err).slice(0, 200)}`);
260
+ process.exit(2);
261
+ }
262
+
263
+ audit(`architect minted plan ${plan.planId} addressing blocker; written to ${ACTIVE_PLAN_PATH}`);
264
+ process.stdout.write(
265
+ JSON.stringify({ ok: true, planId: plan.planId, mintedBy: 'architect-fallback', planPath: ACTIVE_PLAN_PATH }) + '\n'
266
+ );
267
+ process.exit(0);