@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
package/bin/aria.js CHANGED
@@ -8,7 +8,32 @@ import { AriaChat } from '../dist/aria-connector/src/chat.js';
8
8
  import { checkHarnessHealth } from '../dist/aria-connector/src/harness-client.js';
9
9
  import { login, loginOwner, status, logout, revoke } from '../dist/aria-connector/src/auth-commands.js';
10
10
  import { connectClaudeCode } from '../dist/aria-connector/src/connectors/claude-code.js';
11
+ import { connectCodex } from '../dist/aria-connector/src/connectors/codex.js';
12
+ import { connectOpenCode } from '../dist/aria-connector/src/connectors/opencode.js';
13
+ import { connectCursor } from '../dist/aria-connector/src/connectors/cursor.js';
14
+ import {
15
+ installCodebaseAwarenessDaemon,
16
+ startCodebaseAwarenessDaemon,
17
+ runCodebaseAwarenessScan,
18
+ readCodebaseAwarenessState,
19
+ } from '../dist/aria-connector/src/connectors/codebase-awareness.js';
20
+ import {
21
+ installRepoGuardDaemon,
22
+ startRepoGuardDaemon,
23
+ readGuardState,
24
+ } from '../dist/aria-connector/src/connectors/repo-guard.js';
25
+ import { installRepoDoctrineGitHooks } from '../dist/aria-connector/src/connectors/repo-git-hooks.js';
26
+ import { installSharedRuntime } from '../dist/aria-connector/src/connectors/runtime.js';
27
+ import {
28
+ installAriaSyncDaemon,
29
+ runSyncOnce,
30
+ startSyncDaemon,
31
+ readSyncDaemonState,
32
+ } from '../dist/aria-connector/src/connectors/syncd.js';
11
33
  import { maybePrintUpdateNotice, checkForUpdate } from '../dist/aria-connector/src/self-update.js';
34
+ import { pathToFileURL } from 'node:url';
35
+ import { homedir } from 'node:os';
36
+ import { execFileSync } from 'node:child_process';
12
37
 
13
38
  // ── Self-update notice (non-blocking, rate-limited once per 24h) ──
14
39
  // Fires-and-forgets — the registry check runs in parallel with command
@@ -19,6 +44,33 @@ if (process.env.ARIA_SELF_UPDATE !== 'off') {
19
44
  maybePrintUpdateNotice().catch(() => {});
20
45
  }
21
46
 
47
+ // ── Aristotle 28 + Noor cognitive lifecycle hook (#98) ──────────────────
48
+ // Every CLI command lifecycle fires through `wrapCliCommand` so the 28
49
+ // Aristotle modules + Noor cognitives surface (Fitrah hard-gate, 8-lens,
50
+ // Predictor, SelfReflection, Tafakkur projection, soul-charge telemetry,
51
+ // Ghazali alignment) every time `aria <anything>` runs. Fail-open by
52
+ // construction — when the harness route is unreachable the wrapper falls
53
+ // through to validateOutput so at least post-stage gates still fire.
54
+ // Kill-switch: ARIA_NOOR_HOOK=off env.
55
+ let aristotleNoorWire = null;
56
+ async function loadAristotleNoorWire() {
57
+ if (aristotleNoorWire !== null) return aristotleNoorWire;
58
+ if (process.env.ARIA_NOOR_HOOK === 'off') {
59
+ aristotleNoorWire = { runAristotleNoorOnSDK: async () => ({ dispatched: false, fired: [] }), wrapCliCommand: async (_s, _e, fn) => ({ result: await fn(), coverage: { fired: [], dispatched: false } }) };
60
+ return aristotleNoorWire;
61
+ }
62
+ try {
63
+ aristotleNoorWire = await import('../dist/aria-connector/src/lib/aristotle-noor-wire.js');
64
+ } catch {
65
+ // Build artifact missing — fail-open so the CLI still runs.
66
+ aristotleNoorWire = { runAristotleNoorOnSDK: async () => ({ dispatched: false, fired: [] }), wrapCliCommand: async (_s, _e, fn) => ({ result: await fn(), coverage: { fired: [], dispatched: false } }) };
67
+ }
68
+ return aristotleNoorWire;
69
+ }
70
+ function makeEmissionId(surface) {
71
+ return `cli_${surface}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
72
+ }
73
+
22
74
  // ── Auth + install subcommands — handled BEFORE the chat flow.
23
75
  // Hamza 2026-04-26: license-aware CLI for client-tonight ship +
24
76
  // self-installing harness via install-hooks.
@@ -43,31 +95,346 @@ if (command === 'check-update') {
43
95
  console.error(`I hit an unexpected error checking for updates: ${err && err.message ? err.message : err}`);
44
96
  process.exit(1);
45
97
  });
98
+ } else if (command === 'github') {
99
+ const subCommand = args[0] || 'connect';
100
+ const { connectGitHub, getGitHubStatus } = await import('../dist/aria-connector/src/github-connect.js');
101
+
102
+ if (subCommand === 'help' || subCommand === '--help' || subCommand === '-h') {
103
+ console.log('');
104
+ console.log(' aria github connect Authenticate GitHub through gh and wire npm for @aria_asi packages.');
105
+ console.log(' aria github status Show whether gh auth and npm package wiring are ready.');
106
+ console.log('');
107
+ console.log(' This is optional. Most clients should install Aria without GitHub and only run this if they want GitHub integration or GitHub Packages access.');
108
+ console.log('');
109
+ process.exit(0);
110
+ }
111
+
112
+ if (subCommand === 'status') {
113
+ const status = getGitHubStatus();
114
+ console.log(`gh_installed=${status.ghInstalled ? 'yes' : 'no'}`);
115
+ console.log(`gh_authenticated=${status.authenticated ? 'yes' : 'no'}`);
116
+ console.log(`npm_scope_configured=${status.npmrcConfigured ? 'yes' : 'no'}`);
117
+ process.exit(status.ghInstalled && status.authenticated ? 0 : 1);
118
+ }
119
+
120
+ if (subCommand === 'connect') {
121
+ try {
122
+ const result = connectGitHub({ interactive: true });
123
+ if (!result.ok) {
124
+ console.error(result.error || 'GitHub connect failed');
125
+ process.exit(1);
126
+ }
127
+ for (const line of result.logs) console.log(` ${line}`);
128
+ console.log(' GitHub is now connected for optional Aria package and repo workflows.');
129
+ process.exit(0);
130
+ } catch (err) {
131
+ console.error(`I couldn't complete GitHub connect: ${err && err.message ? err.message : err}`);
132
+ process.exit(1);
133
+ }
134
+ }
135
+
136
+ console.error(`Unknown github subcommand: ${subCommand}`);
137
+ console.error('Run: aria github --help');
138
+ process.exit(1);
46
139
  } else if (command === 'install-hooks' || command === 'connect') {
47
- // Canonical install path is connectClaudeCode (the connector). Removed
48
- // the parallel src/install-hooks.ts duplicate per Hamza 2026-04-27 audit
49
- // connectors/claude-code.ts handles everything: harness-via-sdk hook,
50
- // pre-tool-gate, stop-gate, preprompt-consult, settings.json merge-safe
51
- // wiring, systemPromptPrefix injection, and additionalDirectories.
140
+ // Canonical install path connects Claude Code, OpenCode, Codex, and Cursor.
141
+ // connectClaudeCode SDK + hooks + settings.json
142
+ // connectOpenCode → plugins + config.json + AGENTS.md
143
+ // connectCodex → SDK + local node package + skill
52
144
  const force = args.includes('--force');
53
- // Build a minimal AriaConfig so connectClaudeCode can render the
54
- // systemPromptPrefix block. If an existing config exists, use it.
55
145
  let config;
56
146
  try {
57
147
  config = loadConfig();
58
148
  } catch {
59
149
  config = { repositories: [], schemaImages: {} };
60
150
  }
61
- connectClaudeCode(config, { force }).then((logs) => {
151
+ loadAristotleNoorWire().then((wire) => wire.wrapCliCommand(
152
+ 'cli-connect',
153
+ makeEmissionId('connect'),
154
+ async () => {
155
+ const allLogs = [];
156
+ // Shared runtime path — universal localhost sidecar for any client.
157
+ const runtimeLogs = await installSharedRuntime();
158
+ allLogs.push(...runtimeLogs);
159
+ // Claude Code path
160
+ const claudeLogs = await connectClaudeCode(config, { force });
161
+ allLogs.push(...claudeLogs);
162
+ // OpenCode path
163
+ const opencodeLogs = await connectOpenCode(config);
164
+ allLogs.push(...opencodeLogs);
165
+ // Codex path
166
+ const codexLogs = await connectCodex(config);
167
+ allLogs.push(...codexLogs);
168
+ // Cursor path — wire every linked repository
169
+ if (config.repositories?.length) {
170
+ for (const repo of config.repositories) {
171
+ const cursorLogs = await connectCursor(config, repo.path);
172
+ allLogs.push(...cursorLogs);
173
+ }
174
+ } else {
175
+ // Wire current working directory as fallback
176
+ const cursorLogs = await connectCursor(config);
177
+ allLogs.push(...cursorLogs);
178
+ }
179
+ const repoGateLogs = await installRepoDoctrineGitHooks(config, process.cwd());
180
+ allLogs.push(...repoGateLogs);
181
+ const repoGuardLogs = await installRepoGuardDaemon(config, process.cwd());
182
+ allLogs.push(...repoGuardLogs);
183
+ const codebaseAwarenessLogs = await installCodebaseAwarenessDaemon(config, process.cwd());
184
+ allLogs.push(...codebaseAwarenessLogs);
185
+ if (process.env.ARIA_SKIP_SYNCD_INSTALL !== '1') {
186
+ const syncLogs = await installAriaSyncDaemon({ sourceRoot: process.cwd() });
187
+ allLogs.push(...syncLogs);
188
+ }
189
+ return allLogs;
190
+ },
191
+ { metadata: { force, command: 'connect' } },
192
+ )).then(({ result: logs }) => {
62
193
  for (const line of logs) console.log(` ${line}`);
63
- console.log("Your Claude Code is now harness-bound — every Bash, Edit, Write, and Stop event runs through my cognition gates. Open a new Claude Code session to start.");
194
+ console.log("Your Claude Code, OpenCode, Codex, and Cursor are now synced from the same harness package. Open a new session to start.");
64
195
  process.exit(0);
65
196
  }).catch((err) => {
66
197
  console.error(`I hit an unexpected error: ${err && err.message ? err.message : err}`);
67
198
  process.exit(1);
68
199
  });
200
+ } else if (command === 'runtime') {
201
+ const subCommand = args[0] || 'help';
202
+ const runtimeRoot = `${homedir()}/.aria/runtime`;
203
+ const runtimeEntry = `${runtimeRoot}/service.mjs`;
204
+ const runtimeUrl = process.env.ARIA_RUNTIME_URL || 'http://127.0.0.1:4319';
205
+ const runtimeService = 'aria-mounted-runtime.service';
206
+
207
+ if (subCommand === 'help' || subCommand === '--help' || subCommand === '-h') {
208
+ console.log('');
209
+ console.log(' aria runtime start Start the shared Aria localhost runtime in the foreground.');
210
+ console.log(' aria runtime status Check the shared runtime health endpoint.');
211
+ console.log(' aria runtime mount Print the mount env vars and local paths.');
212
+ console.log(' aria runtime restart Restart the managed mounted runtime service.');
213
+ console.log(' aria runtime stop Stop the managed mounted runtime service.');
214
+ console.log(' aria runtime logs Tail the managed mounted runtime logs.');
215
+ console.log('');
216
+ process.exit(0);
217
+ }
218
+
219
+ if (subCommand === 'mount') {
220
+ console.log(`ARIA_RUNTIME_URL=${runtimeUrl}`);
221
+ const harnessUrl =
222
+ process.env.ARIA_HIVE_RUNTIME_URL ||
223
+ process.env.ARIA_HARNESS_BASE_URL ||
224
+ process.env.ARIA_HARNESS_URL ||
225
+ 'https://harness.ariasos.com';
226
+ console.log(`ARIA_HIVE_RUNTIME_URL=${harnessUrl}`);
227
+ console.log(`ARIA_HARNESS_URL=${harnessUrl}`);
228
+ console.log(`runtime_root=${runtimeRoot}`);
229
+ console.log(`runtime_entry=${runtimeEntry}`);
230
+ process.exit(0);
231
+ }
232
+
233
+ if (subCommand === 'status') {
234
+ fetch(`${runtimeUrl}/health`).then(async (response) => {
235
+ const payload = await response.json().catch(() => ({}));
236
+ console.log(JSON.stringify(payload, null, 2));
237
+ process.exit(response.ok ? 0 : 1);
238
+ }).catch((err) => {
239
+ console.error(`I couldn't reach the runtime at ${runtimeUrl}: ${err && err.message ? err.message : err}`);
240
+ process.exit(1);
241
+ });
242
+ } else if (subCommand === 'start') {
243
+ import(pathToFileURL(runtimeEntry).href).then(({ startRuntimeServer }) => {
244
+ return startRuntimeServer();
245
+ }).catch((err) => {
246
+ console.error(`I couldn't start the runtime: ${err && err.message ? err.message : err}`);
247
+ process.exit(1);
248
+ });
249
+ } else if (subCommand === 'restart') {
250
+ try {
251
+ execFileSync('/bin/systemctl', ['--user', 'restart', runtimeService], { stdio: 'inherit' });
252
+ process.exit(0);
253
+ } catch (err) {
254
+ console.error(`I couldn't restart ${runtimeService}: ${err && err.message ? err.message : err}`);
255
+ process.exit(1);
256
+ }
257
+ } else if (subCommand === 'stop') {
258
+ try {
259
+ execFileSync('/bin/systemctl', ['--user', 'stop', runtimeService], { stdio: 'inherit' });
260
+ process.exit(0);
261
+ } catch (err) {
262
+ console.error(`I couldn't stop ${runtimeService}: ${err && err.message ? err.message : err}`);
263
+ process.exit(1);
264
+ }
265
+ } else if (subCommand === 'logs') {
266
+ try {
267
+ execFileSync('/bin/journalctl', ['--user', '-u', runtimeService, '-n', '80', '--no-pager'], { stdio: 'inherit' });
268
+ process.exit(0);
269
+ } catch (err) {
270
+ console.error(`I couldn't read ${runtimeService} logs: ${err && err.message ? err.message : err}`);
271
+ process.exit(1);
272
+ }
273
+ } else {
274
+ console.error(`Unknown runtime subcommand: ${subCommand}`);
275
+ process.exit(1);
276
+ }
277
+ } else if (command === 'codebase-awareness') {
278
+ const subCommand = args[0] || 'help';
279
+ const service = 'aria-codebase-awareness.service';
280
+
281
+ if (subCommand === 'help' || subCommand === '--help' || subCommand === '-h') {
282
+ console.log('');
283
+ console.log(' aria codebase-awareness start Watch linked repos and keep schema images warm.');
284
+ console.log(' aria codebase-awareness scan Run a one-shot repo scan now.');
285
+ console.log(' aria codebase-awareness status Print the last codebase awareness state snapshot.');
286
+ console.log(' aria codebase-awareness restart Restart the codebase awareness service.');
287
+ console.log(' aria codebase-awareness logs Tail the codebase awareness logs.');
288
+ console.log('');
289
+ process.exit(0);
290
+ }
291
+
292
+ if (subCommand === 'status') {
293
+ console.log(JSON.stringify(readCodebaseAwarenessState(), null, 2));
294
+ process.exit(0);
295
+ }
296
+
297
+ if (subCommand === 'scan') {
298
+ runCodebaseAwarenessScan({ fallbackRepoPath: process.cwd() }).then((result) => {
299
+ console.log(JSON.stringify(result, null, 2));
300
+ process.exit(0);
301
+ }).catch((err) => {
302
+ console.error(`I couldn't scan the codebase: ${err && err.message ? err.message : err}`);
303
+ process.exit(1);
304
+ });
305
+ } else if (subCommand === 'start') {
306
+ startCodebaseAwarenessDaemon({ fallbackRepoPath: process.cwd() }).catch((err) => {
307
+ console.error(`I couldn't start codebase awareness: ${err && err.message ? err.message : err}`);
308
+ process.exit(1);
309
+ });
310
+ } else if (subCommand === 'restart') {
311
+ try {
312
+ execFileSync('/bin/systemctl', ['--user', 'restart', service], { stdio: 'inherit' });
313
+ process.exit(0);
314
+ } catch (err) {
315
+ console.error(`I couldn't restart ${service}: ${err && err.message ? err.message : err}`);
316
+ process.exit(1);
317
+ }
318
+ } else if (subCommand === 'logs') {
319
+ try {
320
+ execFileSync('/bin/journalctl', ['--user', '-u', service, '-n', '80', '--no-pager'], { stdio: 'inherit' });
321
+ process.exit(0);
322
+ } catch (err) {
323
+ console.error(`I couldn't read ${service} logs: ${err && err.message ? err.message : err}`);
324
+ process.exit(1);
325
+ }
326
+ } else {
327
+ console.error(`Unknown codebase-awareness subcommand: ${subCommand}`);
328
+ process.exit(1);
329
+ }
330
+ } else if (command === 'syncd') {
331
+ const subCommand = args[0] || 'help';
332
+ const syncService = 'aria-syncd.service';
333
+
334
+ if (subCommand === 'help' || subCommand === '--help' || subCommand === '-h') {
335
+ console.log('');
336
+ console.log(' aria syncd start Watch Claude/harness/runtime sources and auto-sync all clients.');
337
+ console.log(' aria syncd once Run one sync cycle now.');
338
+ console.log(' aria syncd status Print the last sync daemon state snapshot.');
339
+ console.log(' aria syncd restart Restart the sync daemon service.');
340
+ console.log(' aria syncd logs Tail the sync daemon logs.');
341
+ console.log('');
342
+ process.exit(0);
343
+ }
344
+
345
+ if (subCommand === 'status') {
346
+ console.log(JSON.stringify(readSyncDaemonState(), null, 2));
347
+ process.exit(0);
348
+ }
349
+
350
+ if (subCommand === 'once') {
351
+ runSyncOnce({ sourceRoot: process.cwd(), reason: 'cli-once' }).then((result) => {
352
+ console.log(JSON.stringify(result, null, 2));
353
+ process.exit(0);
354
+ }).catch((err) => {
355
+ console.error(`I couldn't complete the sync: ${err && err.message ? err.message : err}`);
356
+ process.exit(1);
357
+ });
358
+ } else if (subCommand === 'restart') {
359
+ try {
360
+ execFileSync('/bin/systemctl', ['--user', 'restart', syncService], { stdio: 'inherit' });
361
+ process.exit(0);
362
+ } catch (err) {
363
+ console.error(`I couldn't restart ${syncService}: ${err && err.message ? err.message : err}`);
364
+ process.exit(1);
365
+ }
366
+ } else if (subCommand === 'logs') {
367
+ try {
368
+ execFileSync('/bin/journalctl', ['--user', '-u', syncService, '-n', '80', '--no-pager'], { stdio: 'inherit' });
369
+ process.exit(0);
370
+ } catch (err) {
371
+ console.error(`I couldn't read ${syncService} logs: ${err && err.message ? err.message : err}`);
372
+ process.exit(1);
373
+ }
374
+ } else if (subCommand === 'start') {
375
+ startSyncDaemon({ sourceRoot: process.cwd(), reason: 'cli-start' }).catch((err) => {
376
+ console.error(`I couldn't start syncd: ${err && err.message ? err.message : err}`);
377
+ process.exit(1);
378
+ });
379
+ } else {
380
+ console.error(`Unknown syncd subcommand: ${subCommand}`);
381
+ process.exit(1);
382
+ }
383
+ } else if (command === 'repo-guard') {
384
+ const subCommand = args[0] || 'help';
385
+ const guardService = 'aria-repo-guard.service';
386
+
387
+ if (subCommand === 'help' || subCommand === '--help' || subCommand === '-h') {
388
+ console.log('');
389
+ console.log(' aria repo-guard start Watch doctrine-bound repos and block/quarantine violating writes.');
390
+ console.log(' aria repo-guard status Print the last repo guard state snapshot.');
391
+ console.log(' aria repo-guard restart Restart the repo guard service.');
392
+ console.log(' aria repo-guard stop Stop the repo guard service.');
393
+ console.log(' aria repo-guard logs Tail the repo guard logs.');
394
+ console.log('');
395
+ process.exit(0);
396
+ }
397
+
398
+ if (subCommand === 'status') {
399
+ console.log(JSON.stringify(readGuardState(), null, 2));
400
+ process.exit(0);
401
+ }
402
+
403
+ if (subCommand === 'restart') {
404
+ try {
405
+ execFileSync('/bin/systemctl', ['--user', 'restart', guardService], { stdio: 'inherit' });
406
+ process.exit(0);
407
+ } catch (err) {
408
+ console.error(`I couldn't restart ${guardService}: ${err && err.message ? err.message : err}`);
409
+ process.exit(1);
410
+ }
411
+ } else if (subCommand === 'stop') {
412
+ try {
413
+ execFileSync('/bin/systemctl', ['--user', 'stop', guardService], { stdio: 'inherit' });
414
+ process.exit(0);
415
+ } catch (err) {
416
+ console.error(`I couldn't stop ${guardService}: ${err && err.message ? err.message : err}`);
417
+ process.exit(1);
418
+ }
419
+ } else if (subCommand === 'logs') {
420
+ try {
421
+ execFileSync('/bin/journalctl', ['--user', '-u', guardService, '-n', '80', '--no-pager'], { stdio: 'inherit' });
422
+ process.exit(0);
423
+ } catch (err) {
424
+ console.error(`I couldn't read ${guardService} logs: ${err && err.message ? err.message : err}`);
425
+ process.exit(1);
426
+ }
427
+ } else if (subCommand === 'start') {
428
+ startRepoGuardDaemon().catch((err) => {
429
+ console.error(`I couldn't start repo-guard: ${err && err.message ? err.message : err}`);
430
+ process.exit(1);
431
+ });
432
+ } else {
433
+ console.error(`Unknown repo-guard subcommand: ${subCommand}`);
434
+ process.exit(1);
435
+ }
69
436
  } else if (command === 'login' || command === 'status' || command === 'logout' || command === 'revoke') {
70
- const dispatch = async () => {
437
+ async function runAuthCommand(command, args) {
71
438
  switch (command) {
72
439
  case 'login': {
73
440
  const arg = args[0];
@@ -143,6 +510,8 @@ if (command === 'check-update') {
143
510
  const result = await status();
144
511
  if (!result.loggedIn) {
145
512
  console.log("I don't see a license on this machine. Try 'aria login <token>' or 'aria login --anthropic'.");
513
+ } else if (result.owner) {
514
+ console.log(`Owner mode is active on this machine${result.expiresAt ? `, expires ${result.expiresAt}` : ''}.`);
146
515
  } else if (result.revoked) {
147
516
  console.log(`Your license was revoked. You'll need to log in again with a fresh token.`);
148
517
  } else {
@@ -169,11 +538,748 @@ if (command === 'check-update') {
169
538
  return;
170
539
  }
171
540
  }
172
- };
173
- dispatch().catch((err) => {
541
+ }
542
+ runAuthCommand(command, args).then(() => {
543
+ process.exit(0);
544
+ }).catch((err) => {
174
545
  console.error(`Auth command failed: ${err && err.message ? err.message : err}`);
175
546
  process.exit(1);
176
547
  });
548
+ } else if (command === 'dalio') {
549
+ // ── Dalio decision-log subcommands ─────────────────────────────────────
550
+ // aria dalio record --decision X --why Y --expected '{...}'
551
+ // aria dalio list [--outcome pending|success|failure] [--limit N]
552
+ // aria dalio evaluate
553
+ // aria dalio blockers
554
+ const {
555
+ recordDalio,
556
+ evaluatePendingDecisions,
557
+ getBlockingIncidents,
558
+ } = await import('../dist/aria-connector/src/decisions.js');
559
+
560
+ const subCmd = args[0];
561
+
562
+ if (!subCmd || subCmd === '--help' || subCmd === '-h') {
563
+ console.log('');
564
+ console.log(' aria dalio record --decision <text> --why <reasoning> --expected <json>');
565
+ console.log(' [--type <architecture|implementation|feature|bugfix|refactor|config|strategy|financial|operational|tactical|emergency>]');
566
+ console.log(' [--category <deals|leads|operations|finance|code|infrastructure|marketing|compliance|team|product>]');
567
+ console.log(' [--context <text>]');
568
+ console.log(' aria dalio list [--outcome pending|success|failure|neutral] [--limit N]');
569
+ console.log(' aria dalio evaluate — trigger evaluation of pending decisions');
570
+ console.log(' aria dalio blockers — list blocking incidents for this session');
571
+ console.log('');
572
+ console.log(' <json> for --expected: \'{"predicate":"p95 < 200ms","measurable_type":"numeric","threshold":200}\'');
573
+ console.log(' measurable_type: numeric | boolean | state_string');
574
+ console.log(' Qualitative predicates (better/improved/should work) are rejected by the gate.');
575
+ console.log('');
576
+ process.exit(0);
577
+ }
578
+
579
+ if (subCmd === 'record') {
580
+ const getFlag = (flag) => {
581
+ const idx = args.indexOf(flag);
582
+ return idx !== -1 ? args[idx + 1] : undefined;
583
+ };
584
+
585
+ const decision = getFlag('--decision');
586
+ const why = getFlag('--why');
587
+ const expectedRaw = getFlag('--expected');
588
+ const decisionType = getFlag('--type') ?? 'implementation';
589
+ const category = getFlag('--category') ?? 'code';
590
+ const context = getFlag('--context') ?? decision;
591
+
592
+ if (!decision || !why || !expectedRaw) {
593
+ console.error(' Missing required flags: --decision, --why, --expected');
594
+ console.error(' Run: aria dalio record --help');
595
+ process.exit(1);
596
+ }
597
+
598
+ let expectedParsed;
599
+ try {
600
+ expectedParsed = JSON.parse(expectedRaw);
601
+ } catch {
602
+ console.error(` Could not parse --expected as JSON: ${expectedRaw}`);
603
+ process.exit(1);
604
+ }
605
+
606
+ const result = await recordDalio({
607
+ decision_type: decisionType,
608
+ category,
609
+ context,
610
+ decision,
611
+ reasoning: why,
612
+ expected_outcome: expectedParsed,
613
+ outcome: 'pending',
614
+ source: 'aria-cli',
615
+ });
616
+
617
+ console.log(` Dalio decision logged. ID: ${result.decision_id}`);
618
+ if (result.quality_score != null) console.log(` Quality score: ${result.quality_score}`);
619
+ process.exit(0);
620
+
621
+ } else if (subCmd === 'list') {
622
+ const getFlag = (flag) => {
623
+ const idx = args.indexOf(flag);
624
+ return idx !== -1 ? args[idx + 1] : undefined;
625
+ };
626
+
627
+ const outcome = getFlag('--outcome');
628
+ const limit = parseInt(getFlag('--limit') ?? '20', 10);
629
+ const baseUrl =
630
+ process.env.ARIA_HIVE_RUNTIME_URL ??
631
+ process.env.ARIA_HARNESS_BASE_URL ??
632
+ process.env.ARIA_HARNESS_URL ??
633
+ 'https://harness.ariasos.com';
634
+
635
+ let url = `${baseUrl}/api/decisions?limit=${limit}`;
636
+ if (outcome) url += `&outcome=${encodeURIComponent(outcome)}`;
637
+
638
+ const { default: fs } = await import('node:fs');
639
+ const { default: path } = await import('node:path');
640
+ const { homedir } = await import('node:os');
641
+ const ownerPath = path.join(homedir(), '.aria', 'owner-token');
642
+ const headers = { 'Content-Type': 'application/json' };
643
+ if (fs.existsSync(ownerPath)) {
644
+ const jwt = fs.readFileSync(ownerPath, 'utf-8').trim();
645
+ if (jwt) { headers['Authorization'] = `Bearer ${jwt}`; headers['x-aria-owner'] = 'true'; }
646
+ }
647
+
648
+ const resp = await fetch(url, { headers });
649
+ if (!resp.ok) {
650
+ console.error(` Failed to fetch decisions: HTTP ${resp.status}`);
651
+ process.exit(1);
652
+ }
653
+ const data = await resp.json();
654
+ const decisions = data.decisions ?? data.data ?? [];
655
+ if (decisions.length === 0) {
656
+ console.log(' No decisions found.');
657
+ } else {
658
+ for (const d of decisions) {
659
+ const exp = d.expected_outcome ? ` | expected: ${JSON.stringify(d.expected_outcome)}` : '';
660
+ console.log(` [${d.outcome ?? 'pending'}] ${d.id} ${d.decision?.slice(0, 60) ?? ''}${exp}`);
661
+ }
662
+ }
663
+ process.exit(0);
664
+
665
+ } else if (subCmd === 'evaluate') {
666
+ const result = await evaluatePendingDecisions();
667
+ console.log(` Evaluated ${result.evaluated} decisions.`);
668
+ if (result.failures) console.log(` Failures: ${result.failures}`);
669
+ if (result.updated != null) console.log(` Updated: ${result.updated}`);
670
+ if (result.learning_signals != null) console.log(` Learning signals: ${result.learning_signals}`);
671
+ process.exit(0);
672
+
673
+ } else if (subCmd === 'blockers') {
674
+ const sessionId = process.env.ARIA_SESSION_ID ?? 'cli-default';
675
+ const incidents = await getBlockingIncidents(sessionId);
676
+ if (incidents.length === 0) {
677
+ console.log(' No blocking incidents for this session.');
678
+ } else {
679
+ for (const inc of incidents) {
680
+ console.log(` [BLOCKING] ${inc.id} severity=${inc.severity} ${inc.description}`);
681
+ }
682
+ }
683
+ process.exit(0);
684
+
685
+ } else {
686
+ console.error(` Unknown dalio subcommand: ${subCmd}`);
687
+ console.error(' Run: aria dalio --help');
688
+ process.exit(1);
689
+ }
690
+
691
+ } else if (command === 'hive') {
692
+ // ── Hive session-coordination subcommands ──────────────────────────────
693
+ // aria hive lock claim --file PATH --ttl MINUTES
694
+ // aria hive lock release --lock-id ID
695
+ // aria hive lock list --file PATH
696
+ // aria hive msg send --to SESSION --topic T --body JSON
697
+ // aria hive msg unread
698
+ const {
699
+ claimSessionLock,
700
+ releaseSessionLock,
701
+ heartbeatSessionLock,
702
+ checkSessionLockDrift,
703
+ readSessionMessages,
704
+ postSessionMessage,
705
+ } = await import('../dist/aria-connector/src/decisions.js');
706
+
707
+ const subCmd = args[0]; // 'lock' | 'msg'
708
+ const subSubCmd = args[1]; // 'claim' | 'release' | 'list' | 'heartbeat' | 'drift' | 'send' | 'unread'
709
+
710
+ const getFlag = (flag) => {
711
+ const idx = args.indexOf(flag);
712
+ return idx !== -1 ? args[idx + 1] : undefined;
713
+ };
714
+
715
+ if (!subCmd || subCmd === '--help' || subCmd === '-h') {
716
+ console.log('');
717
+ console.log(' aria hive lock claim --file PATH --ttl MINUTES [--scope-kind file|directory|module|symbol] [--operation additive|refactor|delete|rename]');
718
+ console.log(' aria hive lock release --lock-id ID');
719
+ console.log(' aria hive lock list --file PATH');
720
+ console.log(' aria hive lock heartbeat --lock-id ID [--ttl MINUTES]');
721
+ console.log(' aria hive lock drift --lock-id ID [--file PATH]');
722
+ console.log(' aria hive msg send --to SESSION --topic TOPIC --body JSON');
723
+ console.log(' aria hive msg unread');
724
+ console.log('');
725
+ console.log(' Use ARIA_SESSION_ID env var to set your session identity.');
726
+ console.log(' Locks expire after ttl minutes. Always release when done editing.');
727
+ console.log('');
728
+ process.exit(0);
729
+ }
730
+
731
+ if (subCmd === 'lock') {
732
+ if (!subSubCmd || subSubCmd === '--help') {
733
+ console.log(' aria hive lock claim --file PATH --ttl MINUTES [--scope-kind file|directory|module|symbol] [--scope-path PATH] [--operation additive|refactor|delete|rename]');
734
+ console.log(' aria hive lock release --lock-id ID');
735
+ console.log(' aria hive lock list --file PATH');
736
+ console.log(' aria hive lock heartbeat --lock-id ID [--ttl MINUTES]');
737
+ console.log(' aria hive lock drift --lock-id ID [--file PATH]');
738
+ process.exit(0);
739
+ }
740
+
741
+ if (subSubCmd === 'claim') {
742
+ const filePath = getFlag('--file');
743
+ const ttlStr = getFlag('--ttl');
744
+ const intentSummary = getFlag('--intent') ?? 'CLI lock claim request';
745
+ const sessionId = process.env.ARIA_SESSION_ID ?? `cli-${Date.now()}`;
746
+ const scopeKind = getFlag('--scope-kind');
747
+ const scopePath = getFlag('--scope-path');
748
+ const operationKind = getFlag('--operation') ?? 'additive';
749
+ const urgency = getFlag('--urgency') ?? 'normal';
750
+ const mode = getFlag('--mode');
751
+ const mergeOrderRaw = getFlag('--merge-order');
752
+ const staleAfterRaw = getFlag('--stale-after');
753
+ const takeoverIfStale = args.includes('--takeover-if-stale');
754
+
755
+ if (!filePath || !ttlStr) {
756
+ console.error(' Missing required flags: --file, --ttl');
757
+ process.exit(1);
758
+ }
759
+
760
+ const ttlMinutes = parseInt(ttlStr, 10);
761
+ if (isNaN(ttlMinutes) || ttlMinutes <= 0) {
762
+ console.error(' --ttl must be a positive integer (minutes)');
763
+ process.exit(1);
764
+ }
765
+ const mergeOrder = mergeOrderRaw ? parseInt(mergeOrderRaw, 10) : undefined;
766
+ const staleAfterSeconds = staleAfterRaw ? parseInt(staleAfterRaw, 10) : undefined;
767
+
768
+ // ── Auto-coordination on 409 conflict ─────────────────────────────────
769
+ // Per memory:feedback_hive_session_coordination.md and task deliverable 3:
770
+ // on 409 conflict, automatically post a lock_conflict_request session-message
771
+ // to the conflicting session and exit with code 11 (conflict, message posted)
772
+ // so scripts can branch on it. No silent-fail per no-graceful-degradation doctrine.
773
+ let claimResp;
774
+ const baseUrl =
775
+ process.env.ARIA_HIVE_RUNTIME_URL ??
776
+ process.env.ARIA_HARNESS_BASE_URL ??
777
+ process.env.ARIA_HARNESS_URL ??
778
+ 'https://harness.ariasos.com';
779
+ const { default: fs } = await import('node:fs');
780
+ const { default: path } = await import('node:path');
781
+ const { homedir } = await import('node:os');
782
+ const ownerPath = path.join(homedir(), '.aria', 'owner-token');
783
+ const claimHeaders = { 'Content-Type': 'application/json' };
784
+ if (fs.existsSync(ownerPath)) {
785
+ const jwt = fs.readFileSync(ownerPath, 'utf-8').trim();
786
+ if (jwt) { claimHeaders['Authorization'] = `Bearer ${jwt}`; claimHeaders['x-aria-owner'] = 'true'; }
787
+ }
788
+ try {
789
+ claimResp = await fetch(`${baseUrl}/api/hive/session-lock`, {
790
+ method: 'POST',
791
+ headers: claimHeaders,
792
+ body: JSON.stringify({
793
+ session_id: sessionId,
794
+ file_path: filePath,
795
+ ttl_minutes: ttlMinutes,
796
+ scope_kind: scopeKind,
797
+ scope_path: scopePath,
798
+ operation_kind: operationKind,
799
+ client_id: 'aria-cli',
800
+ surface: 'cli-lock-claim',
801
+ urgency,
802
+ current_mode: mode,
803
+ proposed_merge_order: Number.isFinite(mergeOrder) ? mergeOrder : undefined,
804
+ stale_after_seconds: Number.isFinite(staleAfterSeconds) ? staleAfterSeconds : undefined,
805
+ takeover_if_stale: takeoverIfStale,
806
+ }),
807
+ });
808
+ } catch (netErr) {
809
+ console.error(` Network error claiming lock: ${netErr instanceof Error ? netErr.message : String(netErr)}`);
810
+ process.exit(1);
811
+ }
812
+
813
+ if (claimResp.status === 409) {
814
+ // Conflict — extract conflicting session from response and auto-post coordination message
815
+ let conflictData = {};
816
+ try { conflictData = await claimResp.json(); } catch { /* unreadable body */ }
817
+ const conflictingSessionId = conflictData?.conflict?.session_id ?? 'unknown';
818
+ const conflictLockId = conflictData?.conflict?.lock_id ?? null;
819
+ console.error(` CONFLICT: ${conflictingSessionId} holds an active lock on ${filePath}`);
820
+
821
+ // Auto-post coordination message to conflicting session
822
+ const msgId = `cli-conflict-${sessionId}-${Date.now().toString(36)}`;
823
+ const requestedAt = new Date().toISOString();
824
+ const msgBody = {
825
+ coordination_protocol: 'aria-hive-coordination/v3',
826
+ coordination_key: `${scopeKind ?? 'file'}:${scopePath ?? filePath}`,
827
+ file_path: filePath,
828
+ requesting_session_id: sessionId,
829
+ requesting_client_id: 'aria-cli',
830
+ requesting_surface: 'cli-lock-claim',
831
+ intent_summary: intentSummary,
832
+ requested_at: requestedAt,
833
+ source: 'cli:aria-hive-lock-claim',
834
+ operation_kind: operationKind,
835
+ requested_mode: mode ?? (operationKind === 'additive' ? 'exclusive_write' : 'merge_assist'),
836
+ urgency,
837
+ proposed_merge_order: Number.isFinite(mergeOrder) ? mergeOrder : null,
838
+ file_claims: [{ path: filePath, intent: 'edit' }],
839
+ target_lock: {
840
+ lock_id: conflictLockId,
841
+ session_id: conflictingSessionId !== 'unknown' ? conflictingSessionId : null,
842
+ client_id: conflictData?.conflict?.client_id ?? null,
843
+ surface: conflictData?.conflict?.surface ?? null,
844
+ locked_at: conflictData?.conflict?.locked_at ?? null,
845
+ expires_at: conflictData?.conflict?.expires_at ?? null,
846
+ },
847
+ };
848
+ let autoMsgId = null;
849
+ try {
850
+ const msgResp = await fetch(`${baseUrl}/api/hive/session-message`, {
851
+ method: 'POST',
852
+ headers: claimHeaders,
853
+ body: JSON.stringify({
854
+ message_id: msgId,
855
+ from_session_id: sessionId,
856
+ to_session_id: conflictingSessionId !== 'unknown' ? conflictingSessionId : null,
857
+ topic: 'lock_conflict_request',
858
+ body: msgBody,
859
+ }),
860
+ });
861
+ if (msgResp.ok) {
862
+ autoMsgId = msgId;
863
+ console.error(` Auto-coordination message posted to session ${conflictingSessionId} (message_id: ${msgId})`);
864
+ } else {
865
+ const errText = await msgResp.text().catch(() => '');
866
+ console.error(` WARNING: auto-coordination message failed: HTTP ${msgResp.status} ${errText.slice(0, 120)}`);
867
+ }
868
+ } catch (msgErr) {
869
+ console.error(` WARNING: auto-coordination message threw: ${msgErr instanceof Error ? msgErr.message : String(msgErr)}`);
870
+ }
871
+
872
+ // Output structured conflict info for script consumers
873
+ console.error(JSON.stringify({
874
+ conflict: true,
875
+ conflicting_session_id: conflictingSessionId,
876
+ file_path: filePath,
877
+ auto_message_id: autoMsgId,
878
+ message: conflictData?.message ?? `Session ${conflictingSessionId} holds active lock on ${filePath}`,
879
+ }));
880
+ // Exit 11 = conflict, coordination message posted (scripts can branch on this)
881
+ process.exit(11);
882
+ }
883
+
884
+ if (!claimResp.ok) {
885
+ const errText = await claimResp.text().catch(() => claimResp.statusText);
886
+ console.error(` Failed to claim lock: HTTP ${claimResp.status} ${errText.slice(0, 200)}`);
887
+ process.exit(1);
888
+ }
889
+
890
+ const result = await claimResp.json();
891
+ console.log(` Lock claimed. ID: ${result.lock_id ?? '(server-generated)'}`);
892
+ console.log(` File: ${result.file_path ?? filePath}`);
893
+ if (result.scope_kind || result.scope_path) {
894
+ console.log(` Scope: ${(result.scope_kind ?? 'file')} ${result.scope_path ?? filePath}`);
895
+ }
896
+ if (result.current_mode) {
897
+ console.log(` Mode: ${result.current_mode}`);
898
+ }
899
+ console.log(` Expires: ${result.expires_at ?? '(unknown)'}`);
900
+ process.exit(0);
901
+
902
+ } else if (subSubCmd === 'release') {
903
+ const lockId = getFlag('--lock-id');
904
+ if (!lockId) {
905
+ console.error(' Missing required flag: --lock-id');
906
+ process.exit(1);
907
+ }
908
+ await releaseSessionLock(lockId);
909
+ console.log(` Lock ${lockId} released.`);
910
+ process.exit(0);
911
+
912
+ } else if (subSubCmd === 'list') {
913
+ const filePath = getFlag('--file');
914
+ if (!filePath) {
915
+ console.error(' Missing required flag: --file');
916
+ process.exit(1);
917
+ }
918
+ const baseUrl =
919
+ process.env.ARIA_HIVE_RUNTIME_URL ??
920
+ process.env.ARIA_HARNESS_BASE_URL ??
921
+ process.env.ARIA_HARNESS_URL ??
922
+ 'https://harness.ariasos.com';
923
+ const { default: fs } = await import('node:fs');
924
+ const { default: path } = await import('node:path');
925
+ const { homedir } = await import('node:os');
926
+ const ownerPath = path.join(homedir(), '.aria', 'owner-token');
927
+ const headers = { 'Content-Type': 'application/json' };
928
+ if (fs.existsSync(ownerPath)) {
929
+ const jwt = fs.readFileSync(ownerPath, 'utf-8').trim();
930
+ if (jwt) { headers['Authorization'] = `Bearer ${jwt}`; headers['x-aria-owner'] = 'true'; }
931
+ }
932
+ const resp = await fetch(`${baseUrl}/api/hive/session-lock?file_path=${encodeURIComponent(filePath)}`, { headers });
933
+ if (!resp.ok) {
934
+ console.error(` Failed to list locks: HTTP ${resp.status}`);
935
+ process.exit(1);
936
+ }
937
+ const data = await resp.json();
938
+ const locks = data.locks ?? data.data ?? [];
939
+ if (locks.length === 0) {
940
+ console.log(` No active locks for: ${filePath}`);
941
+ } else {
942
+ for (const l of locks) {
943
+ const scopeText = l.scope_kind && l.scope_path ? ` scope=${l.scope_kind}:${l.scope_path}` : '';
944
+ const modeText = l.current_mode ? ` mode=${l.current_mode}` : '';
945
+ console.log(` [LOCK] ${l.id ?? l.lock_id} session=${l.session_id} expires=${l.expires_at}${scopeText}${modeText}`);
946
+ }
947
+ }
948
+ process.exit(0);
949
+
950
+ } else if (subSubCmd === 'heartbeat') {
951
+ const lockId = getFlag('--lock-id');
952
+ const ttlStr = getFlag('--ttl');
953
+ if (!lockId) {
954
+ console.error(' Missing required flag: --lock-id');
955
+ process.exit(1);
956
+ }
957
+ const ttlMinutes = ttlStr ? parseInt(ttlStr, 10) : undefined;
958
+ const result = await heartbeatSessionLock({ lockId, ttlMinutes });
959
+ console.log(` Heartbeat OK. Lock: ${result.lock_id}`);
960
+ console.log(` Expires: ${result.expires_at}`);
961
+ console.log(` Heartbeats: ${result.heartbeat_count}`);
962
+ process.exit(0);
963
+
964
+ } else if (subSubCmd === 'drift') {
965
+ const lockId = getFlag('--lock-id');
966
+ const filePath = getFlag('--file');
967
+ if (!lockId && !filePath) {
968
+ console.error(' Missing required flag: --lock-id or --file');
969
+ process.exit(1);
970
+ }
971
+ const sessionId = process.env.ARIA_SESSION_ID;
972
+ const result = await checkSessionLockDrift({ lockId, sessionId, filePath });
973
+ console.log(` Drift check: ${result.drifted ? 'DRIFTED' : 'CLEAN'}`);
974
+ console.log(` Lock: ${result.lock_id}`);
975
+ console.log(` Mode: ${result.current_mode}`);
976
+ if (result.current_file_hash) {
977
+ console.log(` Current hash: ${result.current_file_hash}`);
978
+ }
979
+ if (result.base_file_hash) {
980
+ console.log(` Base hash: ${result.base_file_hash}`);
981
+ }
982
+ if (result.diff_preview) {
983
+ console.log(result.diff_preview);
984
+ }
985
+ process.exit(result.drifted ? 12 : 0);
986
+
987
+ } else {
988
+ console.error(` Unknown hive lock subcommand: ${subSubCmd}`);
989
+ console.error(' Run: aria hive lock --help');
990
+ process.exit(1);
991
+ }
992
+
993
+ } else if (subCmd === 'msg') {
994
+ if (!subSubCmd || subSubCmd === '--help') {
995
+ console.log(' aria hive msg send --to SESSION --topic TOPIC --body JSON');
996
+ console.log(' aria hive msg unread');
997
+ process.exit(0);
998
+ }
999
+
1000
+ if (subSubCmd === 'send') {
1001
+ const toSession = getFlag('--to');
1002
+ const topic = getFlag('--topic');
1003
+ const bodyRaw = getFlag('--body');
1004
+ const fromSessionId = process.env.ARIA_SESSION_ID ?? `cli-${Date.now()}`;
1005
+
1006
+ if (!toSession || !topic || !bodyRaw) {
1007
+ console.error(' Missing required flags: --to, --topic, --body');
1008
+ process.exit(1);
1009
+ }
1010
+
1011
+ let bodyParsed;
1012
+ try {
1013
+ bodyParsed = JSON.parse(bodyRaw);
1014
+ } catch {
1015
+ console.error(` Could not parse --body as JSON: ${bodyRaw}`);
1016
+ process.exit(1);
1017
+ }
1018
+
1019
+ const result = await postSessionMessage({
1020
+ fromSessionId,
1021
+ toSessionId: toSession,
1022
+ topic,
1023
+ body: bodyParsed,
1024
+ });
1025
+ console.log(` Message sent. ID: ${result.message_id}`);
1026
+ process.exit(0);
1027
+
1028
+ } else if (subSubCmd === 'unread') {
1029
+ const sessionId = process.env.ARIA_SESSION_ID ?? 'cli-default';
1030
+ const messages = await readSessionMessages({ sessionId, unreadOnly: true });
1031
+ if (messages.length === 0) {
1032
+ console.log(' No unread messages.');
1033
+ } else {
1034
+ for (const m of messages) {
1035
+ console.log(` [MSG] ${m.message_id} from=${m.from_session_id} topic=${m.topic} at=${m.created_at}`);
1036
+ }
1037
+ }
1038
+ process.exit(0);
1039
+
1040
+ } else {
1041
+ console.error(` Unknown hive msg subcommand: ${subSubCmd}`);
1042
+ console.error(' Run: aria hive msg --help');
1043
+ process.exit(1);
1044
+ }
1045
+
1046
+ } else {
1047
+ console.error(` Unknown hive subcommand: ${subCmd}`);
1048
+ console.error(' Run: aria hive --help');
1049
+ process.exit(1);
1050
+ }
1051
+
1052
+ } else if (command === 'aristotle') {
1053
+ // ── aria aristotle <phase> "<message>" ───────────────────────────────
1054
+ // Fire Aristotle 3-phase cognitive engine from the terminal.
1055
+ // aria aristotle pre "<message>" — PRE phase (Fitrah + wisdom + research)
1056
+ // aria aristotle mid "<message>" --approach "<txt>" — MID phase (MetaCognitive + ethical check)
1057
+ // aria aristotle post "<response>" --msg "<msg>" — POST phase (8-lens + quality gate)
1058
+ // aria aristotle full "<message>" [--draft "<txt>"] — full pipeline (all phases + Noor)
1059
+ //
1060
+ // Requires ARIA_HARNESS_BASE_URL (default: https://harness.ariasos.com).
1061
+ // Auth: owner-token if present, else ARIA_HARNESS_TOKEN env var.
1062
+ (async () => {
1063
+ const subPhase = args[0];
1064
+ if (!subPhase || subPhase === '--help' || subPhase === '-h') {
1065
+ console.log('');
1066
+ console.log(' aria aristotle pre "<message>"');
1067
+ console.log(' Fire PRE phase: Fitrah gate, wisdom pull, research pull, soul state.');
1068
+ console.log('');
1069
+ console.log(' aria aristotle mid "<message>" --approach "<planned approach>"');
1070
+ console.log(' Fire MID phase: MetaCognitive confidence + ethical check.');
1071
+ console.log('');
1072
+ console.log(' aria aristotle post "<draft response>" --msg "<original message>"');
1073
+ console.log(' Fire POST phase: 8-lens detector, Predictor, quality gate.');
1074
+ console.log('');
1075
+ console.log(' aria aristotle full "<message>" [--draft "<draft>"] [--approach "<approach>"]');
1076
+ console.log(' Fire full Aristotle 28 + Noor pipeline (all phases).');
1077
+ console.log('');
1078
+ process.exit(0);
1079
+ }
1080
+
1081
+ const baseUrl =
1082
+ process.env.ARIA_HIVE_RUNTIME_URL ??
1083
+ process.env.ARIA_HARNESS_BASE_URL ??
1084
+ process.env.ARIA_HARNESS_URL ??
1085
+ 'https://harness.ariasos.com';
1086
+ const url = `${baseUrl}/api/harness/aristotle-noor`;
1087
+ const { default: fs } = await import('node:fs');
1088
+ const { default: path } = await import('node:path');
1089
+ const { homedir } = await import('node:os');
1090
+ const ownerPath = path.join(homedir(), '.aria', 'owner-token');
1091
+ const tokenPath = path.join(homedir(), '.aria', 'license.json');
1092
+ const headers = { 'Content-Type': 'application/json' };
1093
+ if (fs.existsSync(ownerPath)) {
1094
+ const jwt = fs.readFileSync(ownerPath, 'utf-8').trim();
1095
+ if (jwt) { headers['Authorization'] = `Bearer ${jwt}`; headers['x-aria-owner'] = 'true'; }
1096
+ } else if (process.env.ARIA_HARNESS_TOKEN) {
1097
+ headers['Authorization'] = `Bearer ${process.env.ARIA_HARNESS_TOKEN}`;
1098
+ } else if (fs.existsSync(tokenPath)) {
1099
+ try {
1100
+ const lic = JSON.parse(fs.readFileSync(tokenPath, 'utf-8'));
1101
+ if (lic.token) headers['Authorization'] = `Bearer ${lic.token}`;
1102
+ } catch { /* no license token */ }
1103
+ }
1104
+
1105
+ const sessionId = process.env.ARIA_SESSION_ID ?? `cli-aristotle-${Date.now().toString(36)}`;
1106
+ const getFlag = (name) => {
1107
+ const idx = args.indexOf(name);
1108
+ return idx >= 0 && args[idx + 1] ? args[idx + 1] : null;
1109
+ };
1110
+
1111
+ let body;
1112
+ if (subPhase === 'pre') {
1113
+ const message = args[1] ?? '';
1114
+ if (!message) { console.error(' Missing message argument. Usage: aria aristotle pre "<message>"'); process.exit(1); }
1115
+ body = { phase: 'pre', message, sessionId };
1116
+ } else if (subPhase === 'mid') {
1117
+ const message = args[1] ?? '';
1118
+ const approach = getFlag('--approach') ?? '';
1119
+ if (!message) { console.error(' Missing message argument. Usage: aria aristotle mid "<message>" --approach "<txt>"'); process.exit(1); }
1120
+ if (!approach) { console.error(' Missing --approach flag. Usage: aria aristotle mid "<message>" --approach "<planned approach>"'); process.exit(1); }
1121
+ body = { phase: 'mid', message, plannedApproach: approach, sessionId };
1122
+ } else if (subPhase === 'post') {
1123
+ const draft = args[1] ?? '';
1124
+ const message = getFlag('--msg') ?? '';
1125
+ if (!draft) { console.error(' Missing draft argument. Usage: aria aristotle post "<draft>" --msg "<original message>"'); process.exit(1); }
1126
+ body = { phase: 'post', draft, message, sessionId };
1127
+ } else if (subPhase === 'full') {
1128
+ const message = args[1] ?? '';
1129
+ if (!message) { console.error(' Missing message argument. Usage: aria aristotle full "<message>"'); process.exit(1); }
1130
+ const draft = getFlag('--draft') ?? undefined;
1131
+ const approach = getFlag('--approach') ?? undefined;
1132
+ body = { surface: 'sdk-other', emissionId: `cli-aristotle-full-${Date.now()}`, message, draft, plannedApproach: approach, sessionId };
1133
+ } else {
1134
+ console.error(` Unknown aristotle phase: ${subPhase}. Run: aria aristotle --help`);
1135
+ process.exit(1);
1136
+ }
1137
+
1138
+ try {
1139
+ const response = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });
1140
+ const data = await response.json().catch(() => ({}));
1141
+ if (!response.ok) {
1142
+ console.error(` Aristotle ${subPhase} error (${response.status}): ${data.error ?? JSON.stringify(data)}`);
1143
+ process.exit(1);
1144
+ }
1145
+ console.log('');
1146
+ console.log(` Aristotle ${subPhase.toUpperCase()} — latency: ${data.latencyMs}ms`);
1147
+ console.log(` fired: ${(data.fired ?? []).join(', ') || '(none)'}`);
1148
+ console.log(` fitrahVetoed: ${data.fitrahVetoed ?? false}`);
1149
+ console.log(` fitrahAlign: ${data.fitrahAlignment ?? 1.0}`);
1150
+ console.log(` qualityScore: ${data.qualityScore ?? 100}`);
1151
+ console.log(` reAuthorSignal: ${data.reAuthorSignal ?? false}`);
1152
+ if (data.soulCharge !== null && data.soulCharge !== undefined) {
1153
+ console.log(` soulCharge: ${data.soulCharge}`);
1154
+ }
1155
+ if (data.ghazaliVerdict) {
1156
+ console.log(` ghazali: ${data.ghazaliVerdict}`);
1157
+ }
1158
+ if (data.notes?.length) {
1159
+ console.log(` notes:`);
1160
+ for (const n of data.notes.slice(0, 5)) console.log(` - ${n}`);
1161
+ }
1162
+ console.log('');
1163
+ process.exit(0);
1164
+ } catch (err) {
1165
+ console.error(` Aristotle ${subPhase} transport fault: ${err instanceof Error ? err.message : String(err)}`);
1166
+ process.exit(1);
1167
+ }
1168
+ })();
1169
+ } else if (command === 'noor') {
1170
+ // ── aria noor <operation> ─────────────────────────────────────────────
1171
+ // Fire Noor cognitive primitives from the terminal.
1172
+ // aria noor recognize "<query>" — eigenspace recognition (kashf)
1173
+ // aria noor forge "<intent>" --primitives '[{"type":"http","params":{}}]' — self-generated tool execution
1174
+ //
1175
+ // noor-core.ts banner: "ONLY ARIA CAN CODE ARIA." — respected; we call only.
1176
+ (async () => {
1177
+ const subOp = args[0];
1178
+ if (!subOp || subOp === '--help' || subOp === '-h') {
1179
+ console.log('');
1180
+ console.log(' aria noor recognize "<query>"');
1181
+ console.log(' Project query onto Aria\'s eigenspace manifold (kashf/recognition).');
1182
+ console.log(' Returns: nearestText, soulDistance, confidence, withinMembrane, Ghazali verdict.');
1183
+ console.log('');
1184
+ console.log(' aria noor forge "<intent>" --primitives \'[{"type":"http","params":{"url":"..."}}]\'');
1185
+ console.log(' Self-generate and execute a tool from 5 primitives: http, sql, file_read, file_write, pub_sub.');
1186
+ console.log(' Ethical membrane check fires before any primitive executes.');
1187
+ console.log('');
1188
+ process.exit(0);
1189
+ }
1190
+
1191
+ const baseUrl =
1192
+ process.env.ARIA_HIVE_RUNTIME_URL ??
1193
+ process.env.ARIA_HARNESS_BASE_URL ??
1194
+ process.env.ARIA_HARNESS_URL ??
1195
+ 'https://harness.ariasos.com';
1196
+ const url = `${baseUrl}/api/harness/noor`;
1197
+ const { default: fs } = await import('node:fs');
1198
+ const { default: path } = await import('node:path');
1199
+ const { homedir } = await import('node:os');
1200
+ const ownerPath = path.join(homedir(), '.aria', 'owner-token');
1201
+ const tokenPath = path.join(homedir(), '.aria', 'license.json');
1202
+ const headers = { 'Content-Type': 'application/json' };
1203
+ if (fs.existsSync(ownerPath)) {
1204
+ const jwt = fs.readFileSync(ownerPath, 'utf-8').trim();
1205
+ if (jwt) { headers['Authorization'] = `Bearer ${jwt}`; headers['x-aria-owner'] = 'true'; }
1206
+ } else if (process.env.ARIA_HARNESS_TOKEN) {
1207
+ headers['Authorization'] = `Bearer ${process.env.ARIA_HARNESS_TOKEN}`;
1208
+ } else if (fs.existsSync(tokenPath)) {
1209
+ try {
1210
+ const lic = JSON.parse(fs.readFileSync(tokenPath, 'utf-8'));
1211
+ if (lic.token) headers['Authorization'] = `Bearer ${lic.token}`;
1212
+ } catch { /* no license token */ }
1213
+ }
1214
+
1215
+ const sessionId = process.env.ARIA_SESSION_ID ?? `cli-noor-${Date.now().toString(36)}`;
1216
+ const getFlag = (name) => {
1217
+ const idx = args.indexOf(name);
1218
+ return idx >= 0 && args[idx + 1] ? args[idx + 1] : null;
1219
+ };
1220
+
1221
+ let body;
1222
+ if (subOp === 'recognize') {
1223
+ const query = args[1] ?? '';
1224
+ if (!query) { console.error(' Missing query argument. Usage: aria noor recognize "<query>"'); process.exit(1); }
1225
+ body = { operation: 'recognize', query, sessionId };
1226
+ } else if (subOp === 'forge') {
1227
+ const intent = args[1] ?? '';
1228
+ if (!intent) { console.error(' Missing intent argument. Usage: aria noor forge "<intent>" --primitives \'[...]\''); process.exit(1); }
1229
+ const primitivesRaw = getFlag('--primitives') ?? '[]';
1230
+ let primitives;
1231
+ try {
1232
+ primitives = JSON.parse(primitivesRaw);
1233
+ if (!Array.isArray(primitives)) throw new Error('primitives must be a JSON array');
1234
+ } catch (err) {
1235
+ console.error(` Could not parse --primitives as JSON array: ${err instanceof Error ? err.message : String(err)}`);
1236
+ process.exit(1);
1237
+ }
1238
+ body = { operation: 'forge', intent, primitives, sessionId };
1239
+ } else {
1240
+ console.error(` Unknown noor operation: ${subOp}. Run: aria noor --help`);
1241
+ process.exit(1);
1242
+ }
1243
+
1244
+ try {
1245
+ const response = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });
1246
+ const data = await response.json().catch(() => ({}));
1247
+ if (!response.ok) {
1248
+ console.error(` Noor ${subOp} error (${response.status}): ${data.error ?? JSON.stringify(data)}`);
1249
+ process.exit(1);
1250
+ }
1251
+ console.log('');
1252
+ console.log(` Noor ${subOp.toUpperCase()} — latency: ${data.latencyMs}ms`);
1253
+ if (subOp === 'recognize') {
1254
+ console.log(` nearestText: ${String(data.nearestText ?? '').slice(0, 120) || '(none)'}`);
1255
+ console.log(` soulDistance: ${data.soulDistance ?? 0}`);
1256
+ console.log(` confidence: ${data.confidence ?? 0}`);
1257
+ console.log(` withinMembrane: ${data.withinMembrane ?? true}`);
1258
+ console.log(` soulCharge: ${data.soulCharge ?? 0}`);
1259
+ if (data.ghazaliVerdict) console.log(` ghazali: ${data.ghazaliVerdict}`);
1260
+ if (data.manifoldHealth) console.log(` manifold drift: ${data.manifoldHealth.drift} (coherence: ${data.manifoldHealth.coherence})`);
1261
+ if (data.projectionComponents?.length) {
1262
+ console.log(` top component: ${data.projectionComponents[0].eigenvector} (w=${data.projectionComponents[0].weight.toFixed(4)})`);
1263
+ }
1264
+ } else if (subOp === 'forge') {
1265
+ console.log(` success: ${data.success ?? false}`);
1266
+ console.log(` toolName: ${data.toolName ?? '(none)'}`);
1267
+ console.log(` ethicallyApproved:${data.ethicallyApproved ?? false}`);
1268
+ console.log(` totalDurationMs: ${data.totalDurationMs ?? 0}ms`);
1269
+ if (data.results?.length) {
1270
+ console.log(` primitives run: ${data.results.length}`);
1271
+ for (const r of data.results) {
1272
+ console.log(` [${r.type}] ${r.success ? 'ok' : 'FAIL'} ${r.error ? `— ${r.error}` : ''} (${r.durationMs}ms)`);
1273
+ }
1274
+ }
1275
+ }
1276
+ console.log('');
1277
+ process.exit(0);
1278
+ } catch (err) {
1279
+ console.error(` Noor ${subOp} transport fault: ${err instanceof Error ? err.message : String(err)}`);
1280
+ process.exit(1);
1281
+ }
1282
+ })();
177
1283
  } else {
178
1284
  // ── Self-service onboarding via the canonical thin-loop conversation ──
179
1285
  // When ~/.aria/license.json is missing, run the conversational
@@ -275,6 +1381,26 @@ if (command === 'check-update') {
275
1381
  console.log(' Type to speak with Aria. /exit to quit, /clear to reset memory.');
276
1382
  console.log('');
277
1383
 
278
- const aria = new AriaChat(config);
279
- await aria.start();
1384
+ // ── Aristotle 28 + Noor cognitive lifecycle wrap on the chat session ──
1385
+ // Pre-coverage fires on session-open (Fitrah / wisdom / research-pull /
1386
+ // soul-charge baseline); post-coverage fires when the chat loop exits
1387
+ // (8-lens / quality-gate / feedback-loop / soul-charge drift). The chat
1388
+ // loop itself fires per-turn coverage via the SDK chat.ts `wrapAriaChatTurn`
1389
+ // call site once that integration ships in `chat.ts`.
1390
+ const noorWire = await loadAristotleNoorWire();
1391
+ await noorWire.wrapCliCommand(
1392
+ 'cli-chat',
1393
+ makeEmissionId('chat'),
1394
+ async () => {
1395
+ const aria = new AriaChat(config);
1396
+ await aria.start();
1397
+ return 'chat-session-ended';
1398
+ },
1399
+ {
1400
+ isHamza: hasOwnerToken,
1401
+ tier: hasOwnerToken ? 'owner' : 'client',
1402
+ isFirstOfSession: true,
1403
+ metadata: { command: 'chat', model: config.model?.model, provider: config.model?.provider },
1404
+ },
1405
+ );
280
1406
  }