@aria_asi/cli 0.2.25 → 0.2.29

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 (249) 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 +111 -21
  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/setup-wizard.d.ts.map +1 -1
  90. package/dist/aria-connector/src/setup-wizard.js +34 -2
  91. package/dist/aria-connector/src/setup-wizard.js.map +1 -1
  92. package/dist/assets/hooks/aria-agent-handoff.mjs +224 -0
  93. package/dist/assets/hooks/aria-agent-ledger-merge.mjs +164 -0
  94. package/dist/assets/hooks/aria-architect-fallback.mjs +267 -0
  95. package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +676 -0
  96. package/dist/assets/hooks/aria-discovery-record.mjs +101 -0
  97. package/dist/assets/hooks/aria-harness-via-sdk.mjs +412 -0
  98. package/dist/assets/hooks/aria-import-resolution-gate.mjs +330 -0
  99. package/dist/assets/hooks/aria-outcome-record.mjs +84 -0
  100. package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +294 -0
  101. package/dist/assets/hooks/aria-pre-text-gate.mjs +112 -0
  102. package/dist/assets/hooks/aria-pre-tool-gate.mjs +2133 -0
  103. package/dist/assets/hooks/aria-preprompt-consult.mjs +438 -0
  104. package/dist/assets/hooks/aria-preturn-memory-gate.mjs +570 -0
  105. package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +397 -0
  106. package/dist/assets/hooks/aria-stop-gate.mjs +1551 -0
  107. package/dist/assets/hooks/aria-trigger-autolearn.mjs +229 -0
  108. package/dist/assets/hooks/aria-userprompt-abandon-detect.mjs +192 -0
  109. package/dist/assets/hooks/doctrine_trigger_map.json +479 -0
  110. package/dist/assets/hooks/lib/canonical-lenses.mjs +64 -0
  111. package/dist/assets/hooks/lib/gate-audit.mjs +43 -0
  112. package/dist/assets/hooks/test-aria-preturn-memory-gate.mjs +245 -0
  113. package/dist/assets/hooks/test-tier-lens-labeling.mjs +399 -0
  114. package/dist/assets/opencode-plugins/harness-context/index.js +60 -0
  115. package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +179 -0
  116. package/dist/assets/opencode-plugins/harness-context/package.json +9 -0
  117. package/dist/assets/opencode-plugins/harness-gate/index.js +248 -0
  118. package/dist/assets/opencode-plugins/harness-outcome/index.js +129 -0
  119. package/dist/assets/opencode-plugins/harness-role/index.js +77 -0
  120. package/dist/assets/opencode-plugins/harness-role/package.json +9 -0
  121. package/dist/assets/opencode-plugins/harness-stop/index.js +241 -0
  122. package/dist/runtime/discipline/CLAUDE.md +339 -0
  123. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +63 -0
  124. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
  125. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
  126. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
  127. package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
  128. package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
  129. package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
  130. package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
  131. package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
  132. package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
  133. package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
  134. package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +72 -0
  135. package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +38 -0
  136. package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
  137. package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +25 -0
  138. package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
  139. package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +25 -0
  140. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +81 -0
  141. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +98 -0
  142. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +99 -0
  143. package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +127 -0
  144. package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +117 -0
  145. package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +112 -0
  146. package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +102 -0
  147. package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +121 -0
  148. package/dist/runtime/doctor.mjs +23 -0
  149. package/dist/runtime/local-phase.mjs +632 -0
  150. package/dist/runtime/manifest.json +15 -0
  151. package/dist/runtime/mizan-scheduler.mjs +331 -0
  152. package/dist/runtime/package.json +6 -0
  153. package/dist/runtime/provider-proxy.mjs +594 -0
  154. package/dist/runtime/sdk/BUNDLED.json +5 -0
  155. package/dist/runtime/sdk/index.d.ts +477 -0
  156. package/dist/runtime/sdk/index.js +1469 -0
  157. package/dist/runtime/sdk/index.js.map +1 -0
  158. package/dist/runtime/sdk/package.json +8 -0
  159. package/dist/runtime/sdk/runWithCognition.d.ts +77 -0
  160. package/dist/runtime/sdk/runWithCognition.js +157 -0
  161. package/dist/runtime/sdk/runWithCognition.js.map +1 -0
  162. package/dist/runtime/service.mjs +2708 -0
  163. package/dist/runtime/vendor/aria-gate-runtime/index.d.ts +53 -0
  164. package/dist/runtime/vendor/aria-gate-runtime/index.d.ts.map +1 -0
  165. package/dist/runtime/vendor/aria-gate-runtime/index.js +277 -0
  166. package/dist/runtime/vendor/aria-gate-runtime/index.js.map +1 -0
  167. package/dist/runtime/vendor/aria-gate-runtime/package.json +6 -0
  168. package/dist/sdk/BUNDLED.json +2 -2
  169. package/dist/sdk/index.d.ts +317 -0
  170. package/dist/sdk/index.js +827 -85
  171. package/dist/sdk/index.js.map +1 -1
  172. package/dist/sdk/runWithCognition.d.ts +77 -0
  173. package/dist/sdk/runWithCognition.js +157 -0
  174. package/dist/sdk/runWithCognition.js.map +1 -0
  175. package/hooks/aria-agent-handoff.mjs +11 -1
  176. package/hooks/aria-architect-fallback.mjs +267 -0
  177. package/hooks/aria-cognition-substrate-binding.mjs +676 -0
  178. package/hooks/aria-discovery-record.mjs +101 -0
  179. package/hooks/aria-harness-via-sdk.mjs +34 -21
  180. package/hooks/aria-import-resolution-gate.mjs +330 -0
  181. package/hooks/aria-outcome-record.mjs +84 -0
  182. package/hooks/aria-pre-emit-dryrun.mjs +294 -0
  183. package/hooks/aria-pre-tool-gate.mjs +985 -40
  184. package/hooks/aria-preprompt-consult.mjs +113 -13
  185. package/hooks/aria-preturn-memory-gate.mjs +298 -6
  186. package/hooks/aria-repo-doctrine-gate.mjs +397 -0
  187. package/hooks/aria-stop-gate.mjs +840 -75
  188. package/hooks/aria-userprompt-abandon-detect.mjs +5 -1
  189. package/hooks/doctrine_trigger_map.json +209 -15
  190. package/hooks/lib/canonical-lenses.mjs +64 -0
  191. package/hooks/lib/gate-audit.mjs +43 -0
  192. package/opencode-plugins/harness-context/index.js +1 -1
  193. package/opencode-plugins/harness-context/inject-context.mjs +82 -23
  194. package/opencode-plugins/harness-gate/index.js +248 -0
  195. package/opencode-plugins/harness-outcome/index.js +129 -0
  196. package/opencode-plugins/harness-stop/index.js +241 -0
  197. package/package.json +8 -2
  198. package/runtime-src/doctor.mjs +23 -0
  199. package/runtime-src/local-phase.mjs +632 -0
  200. package/runtime-src/mizan-scheduler.mjs +331 -0
  201. package/runtime-src/provider-proxy.mjs +594 -0
  202. package/runtime-src/service.mjs +2708 -0
  203. package/scripts/bundle-sdk.mjs +317 -0
  204. package/scripts/install-client.sh +176 -0
  205. package/scripts/publish-all.sh +344 -0
  206. package/scripts/publish-docker.sh +27 -0
  207. package/scripts/validate-hook-contracts.mjs +54 -0
  208. package/scripts/validate-skill-prompts.mjs +95 -0
  209. package/skills/aria-cognition/aria-essence/SKILL.md +63 -0
  210. package/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
  211. package/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
  212. package/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
  213. package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
  214. package/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
  215. package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
  216. package/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
  217. package/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
  218. package/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
  219. package/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
  220. package/skills/aria-cognition/mizan/SKILL.md +72 -0
  221. package/skills/aria-cognition/nadia/SKILL.md +38 -0
  222. package/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
  223. package/skills/aria-cognition/predictor/SKILL.md +25 -0
  224. package/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
  225. package/skills/aria-cognition/soul-domains/SKILL.md +25 -0
  226. package/src/auth-commands.ts +111 -45
  227. package/src/chat.ts +174 -13
  228. package/src/codebase-scanner.ts +4 -0
  229. package/src/config.ts +15 -0
  230. package/src/connectors/claude-code.ts +115 -26
  231. package/src/connectors/codebase-awareness.ts +408 -0
  232. package/src/connectors/codex.ts +274 -0
  233. package/src/connectors/cognitive-skills.ts +51 -0
  234. package/src/connectors/opencode.ts +93 -4
  235. package/src/connectors/repo-git-hooks.ts +86 -0
  236. package/src/connectors/repo-guard.ts +589 -0
  237. package/src/connectors/runtime.ts +374 -0
  238. package/src/connectors/shell.ts +83 -14
  239. package/src/connectors/syncd.ts +488 -0
  240. package/src/decisions.ts +469 -0
  241. package/src/garden-control-plane.ts +101 -26
  242. package/src/github-connect.ts +143 -0
  243. package/src/harness-client.ts +128 -3
  244. package/src/hive-client.ts +165 -5
  245. package/src/index.ts +41 -2
  246. package/src/lib/aristotle-noor-wire.ts +310 -0
  247. package/src/providers/types.ts +6 -0
  248. package/src/runtime-proof.ts +392 -0
  249. package/src/setup-wizard.ts +37 -2
@@ -36,6 +36,23 @@ const HOOK_FILES = [
36
36
  // Pre-text gate — validates state-dependent claims in prose against
37
37
  // probe evidence before emission. Closes "WHEN TO LOOK before speaking" gap.
38
38
  'aria-pre-text-gate.mjs',
39
+ // Discovery-ledger write primitive (#83) — sub-agents pipe findings here;
40
+ // outcome-record fires on every state-mutating tool PostToolUse.
41
+ 'aria-discovery-record.mjs',
42
+ 'aria-outcome-record.mjs',
43
+ // Substrate-binding gate — validates cognition lenses cite real loaded
44
+ // substrate (axioms, frames, memories) not forged/generic anchors.
45
+ // Writes ~/.claude/.aria-loaded-substrate.json manifest (#142).
46
+ 'aria-cognition-substrate-binding.mjs',
47
+ // Repo-side doctrine gate — scans edited/staged source files for
48
+ // mock/stub/pending semantics in doctrine-bound packages.
49
+ 'aria-repo-doctrine-gate.mjs',
50
+ // Pre-emit dry-run validator (#140) — model self-checks draft against
51
+ // substrate-binding + drift-triggers before emit. CLI tool, not auto-hook.
52
+ 'aria-pre-emit-dryrun.mjs',
53
+ ];
54
+ const HOOK_DIRS = [
55
+ 'lib',
39
56
  ];
40
57
  // Compiled location: <pkg>/dist/aria-connector/src/connectors/claude-code.js
41
58
  // (tsc preserves the src/ rooted layout under outDir). From this file:
@@ -53,7 +70,12 @@ const HOOK_FILES = [
53
70
  // the fix lands in the same turn as the discovery.
54
71
  function packageHooksDir(): string {
55
72
  const here = path.dirname(fileURLToPath(import.meta.url));
56
- return path.resolve(here, '..', '..', '..', '..', 'hooks');
73
+ const candidates = [
74
+ path.resolve(here, '..', '..', '..', '..', 'hooks'),
75
+ path.resolve(here, '..', '..', '..', 'assets', 'hooks'),
76
+ ];
77
+ const found = candidates.find((candidate) => existsSync(candidate));
78
+ return found || candidates[0];
57
79
  }
58
80
 
59
81
  function packageSdkDir(): string {
@@ -162,15 +184,35 @@ const HOOKS_BLOCK = {
162
184
  }],
163
185
  },
164
186
  ],
165
- PostToolUse: [{
166
- matcher: 'Agent',
167
- hooks: [{
168
- type: 'command',
169
- command: 'node $HOME/.claude/hooks/aria-agent-ledger-merge.mjs',
170
- timeout: 8,
171
- statusMessage: 'Merging sub-agent ledger...',
172
- }],
173
- }],
187
+ PostToolUse: [
188
+ {
189
+ matcher: 'Agent',
190
+ hooks: [{
191
+ type: 'command',
192
+ command: 'node $HOME/.claude/hooks/aria-agent-ledger-merge.mjs',
193
+ timeout: 8,
194
+ statusMessage: 'Merging sub-agent ledger...',
195
+ }],
196
+ },
197
+ {
198
+ matcher: 'Bash|Edit|Write|NotebookEdit',
199
+ hooks: [
200
+ {
201
+ type: 'command',
202
+ command: 'node $HOME/.claude/hooks/aria-repo-doctrine-gate.mjs',
203
+ timeout: 5,
204
+ },
205
+ {
206
+ // Outcome-record: fires on every state-mutating tool to accumulate the
207
+ // outcome ledger (Sonnet H's #76 endpoint). Fire-and-forget — HTTP
208
+ // failures in the hook do not block the tool pipeline.
209
+ type: 'command',
210
+ command: 'node $HOME/.claude/hooks/aria-outcome-record.mjs',
211
+ timeout: 3,
212
+ },
213
+ ],
214
+ },
215
+ ],
174
216
  Stop: [{
175
217
  // Stop gate — text-decision boundary. Reflexive replies fail this
176
218
  // gate the same way reflexive Bash does. Mirrors PreToolUse
@@ -180,6 +222,11 @@ const HOOKS_BLOCK = {
180
222
  // against probe evidence in this turn's tool results. Closes the
181
223
  // "WHEN TO LOOK before speaking" gap left open by both existing gates.
182
224
  hooks: [
225
+ {
226
+ type: 'command',
227
+ command: 'node $HOME/.claude/hooks/aria-cognition-substrate-binding.mjs',
228
+ timeout: 3,
229
+ },
183
230
  {
184
231
  type: 'command',
185
232
  command: 'node $HOME/.claude/hooks/aria-stop-gate.mjs',
@@ -200,6 +247,25 @@ function installHooks(claudeDir: string, logs: string[], opts: { force?: boolean
200
247
  mkdirSync(hooksTargetDir, { recursive: true, mode: 0o700 });
201
248
  }
202
249
  const sourceDir = packageHooksDir();
250
+ for (const dirName of HOOK_DIRS) {
251
+ const srcDir = path.join(sourceDir, dirName);
252
+ if (!existsSync(srcDir)) continue;
253
+ const dstDir = path.join(hooksTargetDir, dirName);
254
+ if (!existsSync(dstDir)) {
255
+ mkdirSync(dstDir, { recursive: true, mode: 0o700 });
256
+ }
257
+ for (const child of readdirSync(srcDir)) {
258
+ const src = path.join(srcDir, child);
259
+ const stat = statSync(src);
260
+ if (!stat.isFile()) continue;
261
+ const dst = path.join(dstDir, child);
262
+ copyFileSync(src, dst);
263
+ if (child.endsWith('.mjs') || child.endsWith('.js')) {
264
+ try { chmodSync(dst, 0o755); } catch {}
265
+ }
266
+ logs.push(`Installed hook helper: ${dirName}/${child}`);
267
+ }
268
+ }
203
269
  for (const name of HOOK_FILES) {
204
270
  const src = path.join(sourceDir, name);
205
271
  if (!existsSync(src)) {
@@ -277,29 +343,34 @@ function wireHooksBlock(settings: Record<string, unknown>, logs: string[]): void
277
343
  }
278
344
  const hooks = settings.hooks as Record<string, unknown[]>;
279
345
  let mergedEvents = 0;
346
+
347
+ const isManagedAriaCommand = (command: string): boolean =>
348
+ command.includes('$HOME/.claude/hooks/aria-');
349
+
350
+ const isSameManagedEntry = (entry: unknown, matcher: string, commands: string[]): boolean => {
351
+ if (typeof entry !== 'object' || entry === null) return false;
352
+ const eMatcher = (entry as { matcher?: string }).matcher ?? '';
353
+ if (eMatcher !== matcher) return false;
354
+ const eCommands = ((entry as { hooks?: Array<{ command?: string }> }).hooks ?? [])
355
+ .map((h) => h.command)
356
+ .filter((c): c is string => typeof c === 'string');
357
+ if (eCommands.length === 0) return false;
358
+ return eCommands.every(isManagedAriaCommand) || commands.every((c) => eCommands.includes(c));
359
+ };
360
+
280
361
  for (const [event, ourEntries] of Object.entries(HOOKS_BLOCK)) {
281
362
  const existingEntries = Array.isArray(hooks[event]) ? hooks[event] : [];
363
+ const normalizedEntries = [...existingEntries];
282
364
  for (const ourEntry of ourEntries) {
283
365
  const ourMatcher = (ourEntry as { matcher?: string }).matcher ?? '';
284
366
  const ourCommands = ((ourEntry as { hooks?: Array<{ command?: string }> }).hooks ?? [])
285
367
  .map((h) => h.command)
286
368
  .filter((c): c is string => typeof c === 'string');
287
- // Idempotent: skip if an entry with the same matcher AND same set
288
- // of commands already exists. Re-running connect stays clean.
289
- const alreadyPresent = existingEntries.some((e) => {
290
- if (typeof e !== 'object' || e === null) return false;
291
- const eMatcher = (e as { matcher?: string }).matcher ?? '';
292
- if (eMatcher !== ourMatcher) return false;
293
- const eCommands = ((e as { hooks?: Array<{ command?: string }> }).hooks ?? [])
294
- .map((h) => h.command)
295
- .filter((c): c is string => typeof c === 'string');
296
- return ourCommands.every((c) => eCommands.includes(c));
297
- });
298
- if (!alreadyPresent) {
299
- existingEntries.push(ourEntry);
300
- }
369
+ const filteredEntries = normalizedEntries.filter((e) => !isSameManagedEntry(e, ourMatcher, ourCommands));
370
+ normalizedEntries.length = 0;
371
+ normalizedEntries.push(...filteredEntries, ourEntry);
301
372
  }
302
- hooks[event] = existingEntries;
373
+ hooks[event] = normalizedEntries;
303
374
  mergedEvents++;
304
375
  }
305
376
  settings.hooks = hooks;
@@ -307,9 +378,25 @@ function wireHooksBlock(settings: Record<string, unknown>, logs: string[]): void
307
378
  if (!settings.$schema) {
308
379
  settings.$schema = 'https://json.schemastore.org/claude-code-settings.json';
309
380
  }
310
- logs.push(`Wired hooks into settings.json (${mergedEvents} events: SessionStart, UserPromptSubmit, PreToolUse [cognition+memory-gate+Agent-handoff], PostToolUse [Agent-ledger-merge], Stop) — merge-safe, preserves third-party entries`);
381
+ logs.push(`Wired hooks into settings.json (${mergedEvents} events: SessionStart, UserPromptSubmit, PreToolUse [cognition+memory-gate+Agent-handoff], PostToolUse [repo-doctrine-gate + Agent-ledger-merge + outcome-record], Stop) — merge-safe, preserves third-party entries`);
311
382
  }
312
383
 
384
+ // Layer 2 (#84): hard prefix injected into every Agent dispatch so sub-agents
385
+ // know to load the harness packet before ANY tool call. This text appears in
386
+ // the system-prompt-prefix which Claude Code copies into spawned Agent contexts.
387
+ const ARIA_HARNESS_BINDING_PREFIX = `[ARIA_HARNESS_BINDING — MANDATORY FIRST ACTION]
388
+ Before any tool call, Read the harness packet at: $ARIA_HARNESS_PACKET_PATH
389
+ (path is also in your environment as ARIA_HARNESS_PACKET_PATH variable)
390
+ Cite it in your first cognition block — reference at least one axiom + one frame + one memory class from the packet.
391
+ Without packet-citation in your first cognition block, your output will be rejected by aria-pre-tool-gate.mjs in your sub-process.
392
+ [/ARIA_HARNESS_BINDING]
393
+
394
+ [ARIA_DISCOVERY_RECORDING — when you find a defect, doctrine violation, or notable observation during work]
395
+ Record findings to your session ledger via:
396
+ echo '{"text":"<finding>","kind":"defect|observation|principle","refs":["<file:line>"]}' | node $HOME/.claude/hooks/aria-discovery-record.mjs
397
+ This makes findings visible to the parent session's ledger-merge hook + the auto-fix spawner.
398
+ [/ARIA_DISCOVERY_RECORDING]`;
399
+
313
400
  function buildAriaSystemBlock(config: AriaConfig): string {
314
401
  const repoList = config.repositories.map((r) => `- ${r.name} (${r.path})`).join('\n');
315
402
  const schemaText = Object.entries(config.schemaImages)
@@ -322,6 +409,8 @@ You are augmented with Aria's cognitive harness. This provides:
322
409
  - Garden memory: persistent project memory across sessions
323
410
  - 8-lens cognition: multi-perspective analysis for every decision
324
411
 
412
+ ${ARIA_HARNESS_BINDING_PREFIX}
413
+
325
414
  [SELF-GATE PROTOCOL]
326
415
  Before emitting any claim, verify against these hard constraints:
327
416
  1. Truth over deception — always.
@@ -0,0 +1,408 @@
1
+ import { execFileSync } from 'child_process';
2
+ import { createHash } from 'crypto';
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
4
+ import { homedir } from 'os';
5
+ import * as path from 'path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import type { AriaConfig, LinkedRepo } from '../config.js';
8
+ import { loadConfig, saveConfig } from '../config.js';
9
+ import { scanCodebase, schemaImageToText, watchCodebase } from '../codebase-scanner.js';
10
+
11
+ const ARIA_DIR = path.join(homedir(), '.aria');
12
+ const BIN_DIR = path.join(ARIA_DIR, 'bin');
13
+ const ENV_PATH = path.join(ARIA_DIR, 'codebase-awareness.env');
14
+ const STATE_PATH = path.join(ARIA_DIR, 'codebase-awareness-state.json');
15
+ const INDEX_PATH = path.join(ARIA_DIR, 'codebase-awareness-index.json');
16
+
17
+ type AwarenessStatus = 'idle' | 'watching' | 'scanning' | 'error';
18
+
19
+ interface RepoSnapshot {
20
+ path: string;
21
+ name: string;
22
+ scanHash: string;
23
+ lastScan: string;
24
+ fileCount: number;
25
+ language: string;
26
+ framework: string | null;
27
+ packageManager: string | null;
28
+ database: string | null;
29
+ orm: string | null;
30
+ architecture: string | null;
31
+ }
32
+
33
+ interface AwarenessState {
34
+ status: AwarenessStatus;
35
+ watchedRepos: string[];
36
+ repoSnapshots: RepoSnapshot[];
37
+ lastError: string | null;
38
+ updatedAt: string;
39
+ }
40
+
41
+ function connectorPackageRoot(): string {
42
+ const here = path.dirname(fileURLToPath(import.meta.url));
43
+ const candidates = [
44
+ path.resolve(here, '..', '..'),
45
+ path.resolve(here, '..', '..', '..', '..'),
46
+ ];
47
+
48
+ for (const candidate of candidates) {
49
+ if (existsSync(path.join(candidate, 'bin', 'aria.js')) && existsSync(path.join(candidate, 'package.json'))) {
50
+ return candidate;
51
+ }
52
+ }
53
+
54
+ return candidates[candidates.length - 1];
55
+ }
56
+
57
+ function writeWrapper(binPath: string, args: string[]): void {
58
+ const ariaBin = path.join(connectorPackageRoot(), 'bin', 'aria.js');
59
+ writeFileSync(
60
+ binPath,
61
+ `#!/usr/bin/env bash\nexec node "${ariaBin}" ${args.join(' ')} "$@"\n`,
62
+ { mode: 0o755 },
63
+ );
64
+ }
65
+
66
+ function defaultState(): AwarenessState {
67
+ return {
68
+ status: 'idle',
69
+ watchedRepos: [],
70
+ repoSnapshots: [],
71
+ lastError: null,
72
+ updatedAt: new Date(0).toISOString(),
73
+ };
74
+ }
75
+
76
+ function readState(): AwarenessState {
77
+ try {
78
+ const parsed = JSON.parse(readFileSync(STATE_PATH, 'utf8')) as Partial<AwarenessState>;
79
+ return {
80
+ status: parsed.status || 'idle',
81
+ watchedRepos: Array.isArray(parsed.watchedRepos) ? parsed.watchedRepos : [],
82
+ repoSnapshots: Array.isArray(parsed.repoSnapshots) ? parsed.repoSnapshots as RepoSnapshot[] : [],
83
+ lastError: parsed.lastError || null,
84
+ updatedAt: parsed.updatedAt || new Date(0).toISOString(),
85
+ };
86
+ } catch {
87
+ return defaultState();
88
+ }
89
+ }
90
+
91
+ function writeState(update: Partial<AwarenessState>): AwarenessState {
92
+ const current = readState();
93
+ const next: AwarenessState = {
94
+ ...current,
95
+ ...update,
96
+ updatedAt: new Date().toISOString(),
97
+ };
98
+ mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
99
+ writeFileSync(STATE_PATH, JSON.stringify(next, null, 2) + '\n', { mode: 0o600 });
100
+ return next;
101
+ }
102
+
103
+ function writeIndex(payload: Record<string, unknown>): void {
104
+ mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
105
+ writeFileSync(INDEX_PATH, JSON.stringify(payload, null, 2) + '\n', { mode: 0o600 });
106
+ }
107
+
108
+ function looksLikeRepoRoot(candidate: string): boolean {
109
+ return existsSync(path.join(candidate, '.git'));
110
+ }
111
+
112
+ function findRepoRoot(startDir: string): string | null {
113
+ let current = path.resolve(startDir);
114
+ while (true) {
115
+ if (looksLikeRepoRoot(current)) return current;
116
+ const parent = path.dirname(current);
117
+ if (parent === current) return null;
118
+ current = parent;
119
+ }
120
+ }
121
+
122
+ function resolveRepos(config?: AriaConfig, explicit?: string[], fallbackRepoPath?: string): string[] {
123
+ if (explicit?.length) return explicit.map((repo) => path.resolve(repo)).filter(looksLikeRepoRoot);
124
+
125
+ const envRepos = process.env.ARIA_CODEBASE_AWARENESS_REPOS?.split(path.delimiter)
126
+ .map((repo) => repo.trim())
127
+ .filter(Boolean) || [];
128
+ if (envRepos.length) return envRepos.map((repo) => path.resolve(repo)).filter(looksLikeRepoRoot);
129
+
130
+ const loaded = config || loadConfig();
131
+ const configured = (loaded.repositories || [])
132
+ .map((repo) => path.resolve(repo.path))
133
+ .filter(looksLikeRepoRoot);
134
+ if (configured.length) return configured;
135
+
136
+ if (fallbackRepoPath) {
137
+ const resolvedFallback = findRepoRoot(fallbackRepoPath);
138
+ if (resolvedFallback) return [resolvedFallback];
139
+ }
140
+
141
+ const cwd = findRepoRoot(process.cwd());
142
+ return cwd ? [cwd] : [];
143
+ }
144
+
145
+ function hashSchema(text: string): string {
146
+ return createHash('sha256').update(text).digest('hex').slice(0, 16);
147
+ }
148
+
149
+ function architectureSummary(image: {
150
+ architecture?: unknown;
151
+ }): string | null {
152
+ if (Array.isArray(image.architecture) && image.architecture.length > 0) {
153
+ const first = image.architecture[0];
154
+ if (typeof first === 'string' && first.trim()) return first.trim();
155
+ if (first && typeof first === 'object' && typeof first.pattern === 'string' && first.pattern.trim()) {
156
+ return first.pattern.trim();
157
+ }
158
+ }
159
+ if (typeof image.architecture === 'string' && image.architecture.trim()) return image.architecture.trim();
160
+ return null;
161
+ }
162
+
163
+ async function applyRepoScan(repoRoot: string): Promise<RepoSnapshot> {
164
+ const image = await scanCodebase(repoRoot);
165
+ const schemaText = schemaImageToText(image);
166
+ const scanHash = hashSchema(schemaText);
167
+ const lastScan = new Date().toISOString();
168
+
169
+ const config = loadConfig();
170
+ const nextRepo: LinkedRepo = {
171
+ path: repoRoot,
172
+ name: image.projectName,
173
+ scanHash,
174
+ lastScan,
175
+ };
176
+ const repositories = [
177
+ ...(config.repositories || []).filter((repo) => path.resolve(repo.path) !== repoRoot),
178
+ nextRepo,
179
+ ];
180
+
181
+ saveConfig({
182
+ ...config,
183
+ repositories,
184
+ schemaImages: {
185
+ ...(config.schemaImages || {}),
186
+ [image.projectName]: schemaText,
187
+ },
188
+ });
189
+
190
+ const snapshot: RepoSnapshot = {
191
+ path: repoRoot,
192
+ name: image.projectName,
193
+ scanHash,
194
+ lastScan,
195
+ fileCount: image.fileCount,
196
+ language: image.language,
197
+ framework: image.framework || null,
198
+ packageManager: image.packageManager || null,
199
+ database: image.database || null,
200
+ orm: image.orm || null,
201
+ architecture: architectureSummary(image),
202
+ };
203
+
204
+ const current = readState();
205
+ const nextSnapshots = [
206
+ snapshot,
207
+ ...current.repoSnapshots.filter((entry) => path.resolve(entry.path) !== repoRoot),
208
+ ];
209
+ writeState({
210
+ status: 'watching',
211
+ watchedRepos: Array.from(new Set([repoRoot, ...current.watchedRepos])),
212
+ repoSnapshots: nextSnapshots,
213
+ lastError: null,
214
+ });
215
+ writeIndex({
216
+ generatedAt: new Date().toISOString(),
217
+ watchedRepos: Array.from(new Set([repoRoot, ...current.watchedRepos])),
218
+ repoSnapshots: nextSnapshots,
219
+ schemaImages: loadConfig().schemaImages || {},
220
+ });
221
+ return snapshot;
222
+ }
223
+
224
+ export function readCodebaseAwarenessState(): AwarenessState {
225
+ return readState();
226
+ }
227
+
228
+ export async function runCodebaseAwarenessScan(options: {
229
+ repos?: string[];
230
+ fallbackRepoPath?: string;
231
+ } = {}): Promise<{ ok: true; repos: RepoSnapshot[] }> {
232
+ const repos = resolveRepos(undefined, options.repos, options.fallbackRepoPath);
233
+ if (!repos.length) {
234
+ writeState({ status: 'error', watchedRepos: [], lastError: 'No git repositories configured for codebase awareness.' });
235
+ throw new Error('No git repositories configured for codebase awareness.');
236
+ }
237
+
238
+ writeState({ status: 'scanning', watchedRepos: repos, lastError: null });
239
+ const snapshots: RepoSnapshot[] = [];
240
+ for (const repo of repos) {
241
+ snapshots.push(await applyRepoScan(repo));
242
+ }
243
+ writeState({ status: 'watching', watchedRepos: repos, repoSnapshots: snapshots, lastError: null });
244
+ writeIndex({
245
+ generatedAt: new Date().toISOString(),
246
+ watchedRepos: repos,
247
+ repoSnapshots: snapshots,
248
+ schemaImages: loadConfig().schemaImages || {},
249
+ });
250
+ return { ok: true, repos: snapshots };
251
+ }
252
+
253
+ export async function startCodebaseAwarenessDaemon(options: {
254
+ repos?: string[];
255
+ fallbackRepoPath?: string;
256
+ } = {}): Promise<void> {
257
+ const repos = resolveRepos(undefined, options.repos, options.fallbackRepoPath);
258
+ if (!repos.length) {
259
+ writeState({ status: 'error', watchedRepos: [], lastError: 'No git repositories configured for codebase awareness.' });
260
+ throw new Error('No git repositories configured for codebase awareness.');
261
+ }
262
+
263
+ await runCodebaseAwarenessScan({ repos });
264
+ writeState({ status: 'watching', watchedRepos: repos, lastError: null });
265
+
266
+ for (const repo of repos) {
267
+ watchCodebase(
268
+ repo,
269
+ (image) => {
270
+ const schemaText = schemaImageToText(image);
271
+ const scanHash = hashSchema(schemaText);
272
+ const lastScan = new Date().toISOString();
273
+ const config = loadConfig();
274
+ const repositories = [
275
+ ...(config.repositories || []).filter((entry) => path.resolve(entry.path) !== repo),
276
+ {
277
+ path: repo,
278
+ name: image.projectName,
279
+ scanHash,
280
+ lastScan,
281
+ },
282
+ ];
283
+ const nextConfig = {
284
+ ...config,
285
+ repositories,
286
+ schemaImages: {
287
+ ...(config.schemaImages || {}),
288
+ [image.projectName]: schemaText,
289
+ },
290
+ };
291
+ saveConfig(nextConfig);
292
+
293
+ const current = readState();
294
+ const snapshot: RepoSnapshot = {
295
+ path: repo,
296
+ name: image.projectName,
297
+ scanHash,
298
+ lastScan,
299
+ fileCount: image.fileCount,
300
+ language: image.language,
301
+ framework: image.framework || null,
302
+ packageManager: image.packageManager || null,
303
+ database: image.database || null,
304
+ orm: image.orm || null,
305
+ architecture: architectureSummary(image),
306
+ };
307
+ const repoSnapshots = [
308
+ snapshot,
309
+ ...current.repoSnapshots.filter((entry) => path.resolve(entry.path) !== repo),
310
+ ];
311
+ writeState({
312
+ status: 'watching',
313
+ watchedRepos: repos,
314
+ repoSnapshots,
315
+ lastError: null,
316
+ });
317
+ writeIndex({
318
+ generatedAt: new Date().toISOString(),
319
+ watchedRepos: repos,
320
+ repoSnapshots,
321
+ schemaImages: nextConfig.schemaImages || {},
322
+ });
323
+ },
324
+ {
325
+ debounceMs: 800,
326
+ pollIntervalMs: 4000,
327
+ onError: ({ error }) => {
328
+ writeState({
329
+ status: 'error',
330
+ watchedRepos: repos,
331
+ lastError: error.message,
332
+ });
333
+ },
334
+ },
335
+ );
336
+ }
337
+
338
+ await new Promise(() => {});
339
+ }
340
+
341
+ function writeEnv(repos: string[]): string {
342
+ mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
343
+ writeFileSync(
344
+ ENV_PATH,
345
+ [
346
+ `ARIA_CODEBASE_AWARENESS_REPOS=${repos.join(path.delimiter)}`,
347
+ '',
348
+ ].join('\n'),
349
+ { mode: 0o600 },
350
+ );
351
+ return ENV_PATH;
352
+ }
353
+
354
+ function installSystemdUserService(logs: string[]): void {
355
+ const systemctlPath = '/bin/systemctl';
356
+ if (process.platform !== 'linux' || !existsSync(systemctlPath)) return;
357
+
358
+ const serviceDir = path.join(homedir(), '.config', 'systemd', 'user');
359
+ const servicePath = path.join(serviceDir, 'aria-codebase-awareness.service');
360
+ mkdirSync(serviceDir, { recursive: true, mode: 0o755 });
361
+
362
+ const unit = [
363
+ '[Unit]',
364
+ 'Description=Aria Codebase Awareness',
365
+ 'After=network.target',
366
+ '',
367
+ '[Service]',
368
+ 'Type=simple',
369
+ `EnvironmentFile=-${ENV_PATH}`,
370
+ `ExecStart=${path.join(BIN_DIR, 'aria-codebase-awareness')} start`,
371
+ 'Restart=always',
372
+ 'RestartSec=2',
373
+ '',
374
+ '[Install]',
375
+ 'WantedBy=default.target',
376
+ '',
377
+ ].join('\n');
378
+
379
+ writeFileSync(servicePath, unit, { mode: 0o644 });
380
+ logs.push(`Installed systemd user unit → ${servicePath}`);
381
+
382
+ try {
383
+ execFileSync(systemctlPath, ['--user', 'daemon-reload'], { stdio: 'ignore' });
384
+ execFileSync(systemctlPath, ['--user', 'enable', '--now', 'aria-codebase-awareness.service'], { stdio: 'ignore' });
385
+ logs.push('Enabled and started systemd user service: aria-codebase-awareness.service');
386
+ } catch (error) {
387
+ logs.push(`⚠ codebase awareness service installed but not activated: ${error instanceof Error ? error.message : String(error)}`);
388
+ }
389
+ }
390
+
391
+ export async function installCodebaseAwarenessDaemon(config?: AriaConfig, fallbackRepoPath?: string): Promise<string[]> {
392
+ const repos = resolveRepos(config, undefined, fallbackRepoPath);
393
+ const logs: string[] = [];
394
+ if (!repos.length) {
395
+ logs.push('Skipped codebase awareness install: no git repositories configured.');
396
+ return logs;
397
+ }
398
+
399
+ mkdirSync(BIN_DIR, { recursive: true, mode: 0o755 });
400
+ const envPath = writeEnv(repos);
401
+ writeWrapper(path.join(BIN_DIR, 'aria-codebase-awareness'), ['codebase-awareness']);
402
+ installSystemdUserService(logs);
403
+
404
+ logs.push(`Installed codebase awareness wrapper → ${path.join(BIN_DIR, 'aria-codebase-awareness')}`);
405
+ logs.push(`Installed codebase awareness env → ${envPath}`);
406
+ logs.push(`Codebase awareness watching ${repos.length} repos`);
407
+ return logs;
408
+ }