@aria_asi/cli 0.2.36 → 0.2.37

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 (195) hide show
  1. package/CLIENT-ONBOARDING.md +4 -2
  2. package/bin/aria.js +11 -7
  3. package/dist/aria-connector/src/auth.d.ts +14 -0
  4. package/dist/aria-connector/src/auth.d.ts.map +1 -1
  5. package/dist/aria-connector/src/auth.js +103 -1
  6. package/dist/aria-connector/src/auth.js.map +1 -1
  7. package/dist/aria-connector/src/chat.d.ts.map +1 -1
  8. package/dist/aria-connector/src/chat.js +13 -8
  9. package/dist/aria-connector/src/chat.js.map +1 -1
  10. package/dist/aria-connector/src/config.d.ts +6 -1
  11. package/dist/aria-connector/src/config.d.ts.map +1 -1
  12. package/dist/aria-connector/src/config.js.map +1 -1
  13. package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
  14. package/dist/aria-connector/src/connectors/claude-code.js +50 -6
  15. package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
  16. package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
  17. package/dist/aria-connector/src/connectors/codex.js +310 -10
  18. package/dist/aria-connector/src/connectors/codex.js.map +1 -1
  19. package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
  20. package/dist/aria-connector/src/connectors/opencode.js +35 -11
  21. package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
  22. package/dist/aria-connector/src/connectors/repo-guard.d.ts +10 -0
  23. package/dist/aria-connector/src/connectors/repo-guard.d.ts.map +1 -1
  24. package/dist/aria-connector/src/connectors/repo-guard.js +110 -164
  25. package/dist/aria-connector/src/connectors/repo-guard.js.map +1 -1
  26. package/dist/aria-connector/src/connectors/runtime.d.ts.map +1 -1
  27. package/dist/aria-connector/src/connectors/runtime.js +17 -7
  28. package/dist/aria-connector/src/connectors/runtime.js.map +1 -1
  29. package/dist/aria-connector/src/connectors/shell.d.ts.map +1 -1
  30. package/dist/aria-connector/src/connectors/shell.js +12 -8
  31. package/dist/aria-connector/src/connectors/shell.js.map +1 -1
  32. package/dist/aria-connector/src/harness-client.d.ts +3 -1
  33. package/dist/aria-connector/src/harness-client.d.ts.map +1 -1
  34. package/dist/aria-connector/src/harness-client.js +7 -20
  35. package/dist/aria-connector/src/harness-client.js.map +1 -1
  36. package/dist/aria-connector/src/model-context.d.ts.map +1 -1
  37. package/dist/aria-connector/src/model-context.js +5 -0
  38. package/dist/aria-connector/src/model-context.js.map +1 -1
  39. package/dist/aria-connector/src/providers/types.d.ts +1 -1
  40. package/dist/aria-connector/src/providers/types.d.ts.map +1 -1
  41. package/dist/aria-connector/src/providers/xai.d.ts +3 -0
  42. package/dist/aria-connector/src/providers/xai.d.ts.map +1 -0
  43. package/dist/aria-connector/src/providers/xai.js +40 -0
  44. package/dist/aria-connector/src/providers/xai.js.map +1 -0
  45. package/dist/aria-connector/src/setup-wizard.js +1 -0
  46. package/dist/aria-connector/src/setup-wizard.js.map +1 -1
  47. package/dist/aria-connector/src/types.d.ts +2 -0
  48. package/dist/aria-connector/src/types.d.ts.map +1 -1
  49. package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +51 -9
  50. package/dist/assets/hooks/aria-first-class-coach.mjs +129 -0
  51. package/dist/assets/hooks/aria-harness-via-sdk.mjs +33 -6
  52. package/dist/assets/hooks/aria-pre-tool-gate.mjs +33 -8
  53. package/dist/assets/hooks/aria-preprompt-consult.mjs +5 -6
  54. package/dist/assets/hooks/aria-preturn-memory-gate.mjs +5 -0
  55. package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +15 -0
  56. package/dist/assets/hooks/aria-stop-gate.mjs +125 -17
  57. package/dist/assets/hooks/doctrine_trigger_map.json +11 -0
  58. package/dist/assets/hooks/lib/emergency-gateoff-impl.mjs +39 -0
  59. package/dist/assets/hooks/lib/emergency-gateoff.mjs +6 -0
  60. package/dist/assets/hooks/lib/first-class-coach.mjs +755 -0
  61. package/dist/assets/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
  62. package/dist/assets/hooks/lib/skill-autoload-gate.mjs +1 -14
  63. package/dist/assets/opencode-plugins/harness-context/auth-token.mjs +126 -0
  64. package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +62 -22
  65. package/dist/assets/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
  66. package/dist/assets/opencode-plugins/harness-gate/index.js +87 -27
  67. package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
  68. package/dist/assets/opencode-plugins/harness-outcome/index.js +29 -24
  69. package/dist/assets/opencode-plugins/harness-stop/index.js +229 -68
  70. package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
  71. package/dist/runtime/auth-token.mjs +121 -0
  72. package/dist/runtime/coach-kernel.mjs +371 -0
  73. package/dist/runtime/codex-bridge.mjs +440 -69
  74. package/dist/runtime/discipline/doctrine_trigger_map.json +11 -0
  75. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +18 -0
  76. package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
  77. package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
  78. package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
  79. package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
  80. package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
  81. package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
  82. package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +18 -0
  83. package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +18 -0
  84. package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
  85. package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +18 -0
  86. package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
  87. package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +18 -0
  88. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +18 -0
  89. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +18 -0
  90. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +18 -0
  91. package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +18 -0
  92. package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +18 -0
  93. package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +18 -0
  94. package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +18 -0
  95. package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +18 -0
  96. package/dist/runtime/doctrine_trigger_map.json +11 -0
  97. package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +51 -9
  98. package/dist/runtime/hooks/aria-first-class-coach.mjs +129 -0
  99. package/dist/runtime/hooks/aria-harness-via-sdk.mjs +33 -6
  100. package/dist/runtime/hooks/aria-pre-tool-gate.mjs +33 -8
  101. package/dist/runtime/hooks/aria-preprompt-consult.mjs +5 -6
  102. package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +5 -0
  103. package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +15 -0
  104. package/dist/runtime/hooks/aria-stop-gate.mjs +125 -17
  105. package/dist/runtime/hooks/doctrine_trigger_map.json +11 -0
  106. package/dist/runtime/hooks/lib/emergency-gateoff-impl.mjs +39 -0
  107. package/dist/runtime/hooks/lib/emergency-gateoff.mjs +6 -0
  108. package/dist/runtime/hooks/lib/first-class-coach.mjs +755 -0
  109. package/dist/runtime/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
  110. package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +1 -14
  111. package/dist/runtime/local-phase.mjs +8 -0
  112. package/dist/runtime/manifest.json +2 -2
  113. package/dist/runtime/provider-proxy.mjs +136 -33
  114. package/dist/runtime/sdk/BUNDLED.json +2 -2
  115. package/dist/runtime/sdk/auth.d.ts +17 -0
  116. package/dist/runtime/sdk/auth.js +158 -0
  117. package/dist/runtime/sdk/auth.js.map +1 -0
  118. package/dist/runtime/sdk/index.d.ts +8 -1
  119. package/dist/runtime/sdk/index.js +15 -1
  120. package/dist/runtime/sdk/index.js.map +1 -1
  121. package/dist/runtime/service.mjs +1711 -74
  122. package/dist/runtime/task-project-ledger.mjs +290 -0
  123. package/dist/sdk/BUNDLED.json +2 -2
  124. package/dist/sdk/auth.d.ts +17 -0
  125. package/dist/sdk/auth.js +158 -0
  126. package/dist/sdk/auth.js.map +1 -0
  127. package/dist/sdk/index.d.ts +8 -1
  128. package/dist/sdk/index.js +15 -1
  129. package/dist/sdk/index.js.map +1 -1
  130. package/hooks/aria-cognition-substrate-binding.mjs +51 -9
  131. package/hooks/aria-first-class-coach.mjs +129 -0
  132. package/hooks/aria-harness-via-sdk.mjs +33 -6
  133. package/hooks/aria-pre-tool-gate.mjs +33 -8
  134. package/hooks/aria-preprompt-consult.mjs +5 -6
  135. package/hooks/aria-preturn-memory-gate.mjs +5 -0
  136. package/hooks/aria-repo-doctrine-gate.mjs +15 -0
  137. package/hooks/aria-stop-gate.mjs +125 -17
  138. package/hooks/doctrine_trigger_map.json +11 -0
  139. package/hooks/lib/emergency-gateoff-impl.mjs +39 -0
  140. package/hooks/lib/emergency-gateoff.mjs +6 -0
  141. package/hooks/lib/first-class-coach.mjs +755 -0
  142. package/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
  143. package/hooks/lib/skill-autoload-gate.mjs +1 -14
  144. package/opencode-plugins/harness-context/auth-token.mjs +126 -0
  145. package/opencode-plugins/harness-context/inject-context.mjs +62 -22
  146. package/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
  147. package/opencode-plugins/harness-gate/index.js +87 -27
  148. package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
  149. package/opencode-plugins/harness-outcome/index.js +29 -24
  150. package/opencode-plugins/harness-stop/index.js +229 -68
  151. package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
  152. package/package.json +8 -2
  153. package/runtime-src/auth-token.mjs +121 -0
  154. package/runtime-src/coach-kernel.mjs +371 -0
  155. package/runtime-src/codex-bridge.mjs +440 -69
  156. package/runtime-src/local-phase.mjs +8 -0
  157. package/runtime-src/provider-proxy.mjs +136 -33
  158. package/runtime-src/service.mjs +1711 -74
  159. package/scripts/bundle-sdk.mjs +8 -0
  160. package/scripts/check-client-compatibility.mjs +422 -0
  161. package/scripts/check-coach-kernel.mjs +204 -0
  162. package/scripts/check-managed-runtime-ledger.mjs +107 -0
  163. package/scripts/check-opencode-config-contract.mjs +78 -0
  164. package/scripts/check-quality-ledger.mjs +121 -0
  165. package/scripts/self-test-harness-gates.mjs +179 -11
  166. package/scripts/self-test-repo-guard.mjs +38 -0
  167. package/scripts/validate-skill-prompts.mjs +14 -1
  168. package/skills/aria-cognition/aria-essence/SKILL.md +18 -0
  169. package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
  170. package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
  171. package/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
  172. package/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
  173. package/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
  174. package/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
  175. package/skills/aria-cognition/mizan/SKILL.md +18 -0
  176. package/skills/aria-cognition/nadia/SKILL.md +18 -0
  177. package/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
  178. package/skills/aria-cognition/predictor/SKILL.md +18 -0
  179. package/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
  180. package/skills/aria-cognition/soul-domains/SKILL.md +18 -0
  181. package/src/auth.ts +136 -1
  182. package/src/chat.ts +13 -8
  183. package/src/config.ts +6 -1
  184. package/src/connectors/claude-code.ts +62 -18
  185. package/src/connectors/codex.ts +308 -10
  186. package/src/connectors/opencode.ts +35 -12
  187. package/src/connectors/repo-guard.ts +117 -172
  188. package/src/connectors/runtime.ts +19 -7
  189. package/src/connectors/shell.ts +12 -8
  190. package/src/harness-client.ts +8 -22
  191. package/src/model-context.ts +6 -0
  192. package/src/providers/types.ts +1 -1
  193. package/src/providers/xai.ts +55 -0
  194. package/src/setup-wizard.ts +1 -0
  195. package/src/types.ts +2 -0
@@ -34,9 +34,10 @@
34
34
  // 2026-04-27 gates are unconditional from the gated process. If the gate
35
35
  // misfires on legitimate cognition, fix the gate.
36
36
 
37
- import { readFileSync, appendFileSync, existsSync, mkdirSync } from 'node:fs';
37
+ import { readFileSync, appendFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
38
38
  import { dirname } from 'node:path';
39
39
  import { homedir } from 'node:os';
40
+ import { createHash } from 'node:crypto';
40
41
  import { ALL_LENS_NAMES, lensNamesForTier } from './lib/canonical-lenses.mjs';
41
42
  import { collectTurnWindowFromMessages } from './lib/hook-message-window.mjs';
42
43
 
@@ -79,6 +80,7 @@ const MEMORY_DIR = `${HOME}/.claude/projects/-home-hamzaibrahim1/memory`;
79
80
  const RECENT_VIOLATIONS_PATH = `${HOME}/.claude/.aria-recent-violations.jsonl`;
80
81
  const THRASHING_STATE_PATH = `${HOME}/.claude/.aria-thrashing-state.json`;
81
82
  const CLEAR_VIOLATIONS_SCRIPT = `${HOME}/.claude/aria-clear-violations.sh`;
83
+ const CURRENT_RECOVERY_PATH = `${HOME}/.aria/governance-recovery-current.json`;
82
84
 
83
85
  function buildForceReauthorReason({ source, reason, violations = [] }) {
84
86
  return [
@@ -95,6 +97,11 @@ function buildForceReauthorReason({ source, reason, violations = [] }) {
95
97
  '- The cognition block must reference first_principle and must not cite inactive language state.',
96
98
  violations.length ? `\nVIOLATIONS TO FIX:\n${violations.map((v) => `- ${v}`).join('\n')}` : '',
97
99
  '',
100
+ 'Recovery contract:',
101
+ '1. Do not retry the same blocked text unchanged.',
102
+ '2. Apply the teaching above to the next draft before re-emitting.',
103
+ '3. Re-test by submitting the revised cognition through this same gate.',
104
+ '',
98
105
  'REQUIRED REDO SHAPE:',
99
106
  '1. Re-emit <cognition> with all required lenses.',
100
107
  '2. Each lens cites >=1 loaded anchor: axiom:, frame:, memory:, doctrine:, packet:, or active language:.',
@@ -105,6 +112,45 @@ function buildForceReauthorReason({ source, reason, violations = [] }) {
105
112
  ].filter(Boolean).join('\n');
106
113
  }
107
114
 
115
+ function recoveryFingerprint(reason, source = 'substrate-binding') {
116
+ return createHash('sha256')
117
+ .update([source, String(reason || '').replace(/\s+/g, ' ').trim().slice(0, 1200)].join('\0'))
118
+ .digest('hex');
119
+ }
120
+
121
+ function emitRecoverableSubstrateBinding(reason, { source = 'substrate-binding' } = {}) {
122
+ const fingerprint = recoveryFingerprint(reason, source);
123
+ const recovery = {
124
+ schema: 'aria.governance_recovery_current.v1',
125
+ updatedAt: new Date().toISOString(),
126
+ deliveryRule: 'This file is injected into the next system prompt. Execute recoveryLoop.nextStep before any completion claim.',
127
+ ok: true,
128
+ decision: 'warn',
129
+ source,
130
+ governanceMode: 'recovery-required',
131
+ recoveryLoop: {
132
+ fingerprint,
133
+ allowedRecoveryAttempts: 1,
134
+ priorRecoveryAttempts: 0,
135
+ remainingRecoveryAttempts: 1,
136
+ nextStep: 'Re-author the cognition/output with loaded substrate anchors, applied_cognition, and first_principle, then re-run the same substrate-binding gate.',
137
+ architectFallback: 'If Aria consult is unavailable or this same fingerprint repeats, use the strongest available client LLM under the architect harness, produce and execute the recovery plan, then verify.',
138
+ },
139
+ recoveryContract: {
140
+ retry: 'One recovery attempt is allowed for this exact substrate-binding fingerprint; repeat failure enters architect execution mode.',
141
+ architectMode: 'On repeat, load architecture-decision plus substrate-binding/output-discipline skills, define the smallest executable plan, execute the first recovery action, and verify before output.',
142
+ fallbackWhenAriaUnavailable: 'Do not stop or ask the owner to fix it. Bind the strongest available client LLM to the architect harness, give it this JSON contract and failed evidence, execute its recovery plan, then verify.',
143
+ repairRecoveryCycle: ['load or cite only real substrate anchors', 'include first_principle', 'include applied_cognition', 'remove repeated blocked substrings'],
144
+ retest: 'Submit the revised cognition/output through the same substrate-binding gate.',
145
+ blockedReason: reason,
146
+ },
147
+ };
148
+ mkdirSync(dirname(CURRENT_RECOVERY_PATH), { recursive: true, mode: 0o700 });
149
+ writeFileSync(CURRENT_RECOVERY_PATH, `${JSON.stringify(recovery, null, 2)}\n`, { mode: 0o600 });
150
+ console.log(JSON.stringify({ decision: 'allow', recoveryRequired: recovery }));
151
+ process.exit(0);
152
+ }
153
+
108
154
  function validateAppliedCognitionContract(text) {
109
155
  const match = String(text || '').match(APPLIED_COGNITION_BLOCK_RX);
110
156
  if (!match) {
@@ -470,8 +516,7 @@ Recovery surfaces:
470
516
 
471
517
  Per feedback_block_and_force_with_recovery.md, repetition of a recently-blocked phrase is not advisory drift; it is a hard block until the phrase is removed or the carry-forward state is intentionally cleared.`;
472
518
 
473
- console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/carry-forward', reason, violations: [`repeated blocked substring: ${carryForwardMatch.substring}`] }) }));
474
- process.exit(2);
519
+ emitRecoverableSubstrateBinding(buildForceReauthorReason({ source: 'substrate-binding/carry-forward', reason, violations: [`repeated blocked substring: ${carryForwardMatch.substring}`] }), { source: 'substrate-binding/carry-forward' });
475
520
  }
476
521
 
477
522
  const cogMatch = assistantText.match(COGNITION_BLOCK_RX);
@@ -505,8 +550,7 @@ Re-emit with:
505
550
 
506
551
  No process-level disable path per Hamza directive 2026-04-27.`;
507
552
  audit('block_no_cognition_block', { length: assistantText.length });
508
- console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/no-cognition-block', reason: noCogReason, violations: ['missing <cognition>...</cognition> block'] }) }));
509
- process.exit(2);
553
+ emitRecoverableSubstrateBinding(buildForceReauthorReason({ source: 'substrate-binding/no-cognition-block', reason: noCogReason, violations: ['missing <cognition>...</cognition> block'] }), { source: 'substrate-binding/no-cognition-block' });
510
554
  }
511
555
 
512
556
  const cognitionInner = cogMatch[1];
@@ -525,8 +569,7 @@ expected_predicate: <numeric, boolean, or state-string predicate proving success
525
569
  artifact_change: <how the produced artifact differs because cognition ran>
526
570
  </applied_cognition>`;
527
571
  audit('block_applied_cognition_missing', { violations: appliedContract.violations, length: assistantText.length });
528
- console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/applied-cognition-contract', reason, violations: appliedContract.violations }) }));
529
- process.exit(2);
572
+ emitRecoverableSubstrateBinding(buildForceReauthorReason({ source: 'substrate-binding/applied-cognition-contract', reason, violations: appliedContract.violations }), { source: 'substrate-binding/applied-cognition-contract' });
530
573
  }
531
574
  const lensTexts = extractLensTexts(cognitionInner);
532
575
 
@@ -757,5 +800,4 @@ Anchor grammar (each anchor must resolve to a real loaded substrate item):
757
800
 
758
801
  Re-emit cognition with: every lens citing ≥1 verifiable loaded anchor, the block referencing first_principle, and language: citations only for active language tiers. No process-level disable path; gates are unconditional from the gated process per Hamza directive 2026-04-27.`;
759
802
 
760
- console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/structural-violations', reason, violations: reasonParts }) }));
761
- process.exit(2);
803
+ emitRecoverableSubstrateBinding(buildForceReauthorReason({ source: 'substrate-binding/structural-violations', reason, violations: reasonParts }), { source: 'substrate-binding/structural-violations' });
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import {
4
+ FIRST_CLASS_COACH_VERSION,
5
+ evaluateTaskProjectClaim,
6
+ extractAssistantText,
7
+ formatCoachContext,
8
+ formatRuntimeCoachBlock,
9
+ formatTaskProjectLedgerContext,
10
+ inferCoachPhase,
11
+ inferCoachPlatform,
12
+ recordBlockedTaskProjectClaim,
13
+ recordCoachEvent,
14
+ recordRuntimeCoachForLifecycle,
15
+ runtimeCoachBlocksLocalPhase,
16
+ updateTaskProjectLedger,
17
+ } from './lib/first-class-coach.mjs';
18
+
19
+ function readInput() {
20
+ try {
21
+ const raw = readFileSync(0, 'utf8');
22
+ return raw.trim() ? JSON.parse(raw) : {};
23
+ } catch {
24
+ return {};
25
+ }
26
+ }
27
+
28
+ function emitRuntimeCoachBlock(result) {
29
+ process.stderr.write(formatRuntimeCoachBlock(result));
30
+ process.exit(2);
31
+ }
32
+
33
+ async function main() {
34
+ const event = readInput();
35
+ const platform = inferCoachPlatform(event);
36
+ const phase = inferCoachPhase(event);
37
+ const hookEvidence = { hook_event_name: process.env.HOOK_EVENT_NAME || event.hookEventName || event.hook_event_name || null };
38
+ const ledgerResult = updateTaskProjectLedger({
39
+ platform,
40
+ phase,
41
+ source: 'aria-first-class-coach-hook',
42
+ event,
43
+ evidence: hookEvidence,
44
+ });
45
+ recordCoachEvent({
46
+ platform,
47
+ phase,
48
+ source: 'aria-first-class-coach-hook',
49
+ event,
50
+ evidence: {
51
+ ...hookEvidence,
52
+ task_project_ledger: ledgerResult.ledger.ledgerId,
53
+ },
54
+ });
55
+
56
+ const runtimeResult = await recordRuntimeCoachForLifecycle({
57
+ platform,
58
+ phase,
59
+ event,
60
+ ledgerResult,
61
+ evidence: hookEvidence,
62
+ });
63
+ const runtimeBlock = runtimeCoachBlocksLocalPhase(phase, runtimeResult);
64
+ if (runtimeBlock) emitRuntimeCoachBlock(runtimeBlock);
65
+
66
+ if (phase === 'stop' || phase === 'pre_emit' || phase === 'post_cognition') {
67
+ const text = extractAssistantText(event);
68
+ const evaluation = evaluateTaskProjectClaim({ text, ledger: ledgerResult.ledger });
69
+ if (!evaluation.ok) {
70
+ recordBlockedTaskProjectClaim({
71
+ ledger: ledgerResult.ledger,
72
+ paths: ledgerResult.paths,
73
+ text,
74
+ evaluation,
75
+ });
76
+ process.stderr.write([
77
+ '=== ARIA TASK/PROJECT LEDGER BLOCK ===',
78
+ '',
79
+ `ledger_id: ${ledgerResult.ledger.ledgerId}`,
80
+ `missing_readiness_gates: ${evaluation.missingReadinessGates.join(', ') || 'none'}`,
81
+ `open_blockers: ${evaluation.openBlockers.length}`,
82
+ '',
83
+ 'Recovery contract:',
84
+ '1. Do not repeat the same completion/readiness claim unchanged.',
85
+ '2. Record concrete verification evidence in the task/project ledger.',
86
+ '3. Resolve or record blockers before making completion/readiness claims.',
87
+ '4. Emit a bounded status instead of a completion claim if evidence is still missing.',
88
+ '',
89
+ ].join('\n'));
90
+ process.exit(2);
91
+ }
92
+ }
93
+
94
+ if (phase === 'stop' || phase === 'pre_emit') {
95
+ const releaseRuntimeResult = await recordRuntimeCoachForLifecycle({
96
+ platform,
97
+ phase,
98
+ event,
99
+ ledgerResult,
100
+ runtimePhases: phase === 'stop' ? ['claim_or_release', 'post_output'] : ['claim_or_release'],
101
+ evidence: {
102
+ ...hookEvidence,
103
+ task_project_claim_ok: true,
104
+ },
105
+ });
106
+ const releaseBlock = runtimeCoachBlocksLocalPhase(phase, releaseRuntimeResult);
107
+ if (releaseBlock) emitRuntimeCoachBlock(releaseBlock);
108
+ }
109
+
110
+ if (phase === 'session_start' || phase === 'pre_prompt_injection') {
111
+ console.log(JSON.stringify({
112
+ hookSpecificOutput: {
113
+ hookEventName: process.env.HOOK_EVENT_NAME || 'UserPromptSubmit',
114
+ additionalContext: [
115
+ formatCoachContext({ platform, phase }),
116
+ formatTaskProjectLedgerContext({ ledger: ledgerResult.ledger, paths: ledgerResult.paths, platform, phase }),
117
+ ].join('\n\n'),
118
+ },
119
+ }));
120
+ } else {
121
+ process.stderr.write(`[aria-first-class-coach] ${FIRST_CLASS_COACH_VERSION} platform=${platform} phase=${phase} ledger=${ledgerResult.ledger.ledgerId}\n`);
122
+ }
123
+ }
124
+
125
+ main().catch((error) => {
126
+ const message = error instanceof Error ? error.message : String(error);
127
+ process.stderr.write(`[aria-first-class-coach] failed: ${message}\n`);
128
+ process.exit(2);
129
+ });
@@ -168,8 +168,14 @@ function normalizeHarnessPacketPayload(payload) {
168
168
  let current = payload;
169
169
  for (let depth = 0; depth < 3; depth++) {
170
170
  if (!current || typeof current !== 'object' || Array.isArray(current)) break;
171
+ if (typeof current.harness === 'string' || typeof current?.prompt?.fullText === 'string') break;
171
172
  if (!('packet' in current) || !current.packet || typeof current.packet !== 'object') break;
172
- if (!('timestamp' in current) && !('version' in current)) break;
173
+ if (
174
+ !('timestamp' in current) &&
175
+ !('version' in current) &&
176
+ typeof current.packet.harness !== 'string' &&
177
+ typeof current.packet?.prompt?.fullText !== 'string'
178
+ ) break;
173
179
  current = current.packet;
174
180
  }
175
181
  return current;
@@ -325,6 +331,17 @@ async function runMizanPre(apiKey, packet, sourceLabel) {
325
331
  return payload;
326
332
  }
327
333
 
334
+ async function tryRunMizanPre(apiKey, packet, sourceLabel) {
335
+ try {
336
+ return await runMizanPre(apiKey, packet, sourceLabel);
337
+ } catch (err) {
338
+ try {
339
+ appendFileSync(LOG_FILE, `${new Date().toISOString()} mizan-pre-skip mode=${MODE} source=${sourceLabel} err="${String(err).replace(/"/g, "'").slice(0, 200)}"\n`);
340
+ } catch {}
341
+ return null;
342
+ }
343
+ }
344
+
328
345
  async function tryViaSdk(baseUrl, apiKey) {
329
346
  // Canonical path: HTTPHarnessClient.getHarnessPacket(). The SDK POSTs to
330
347
  // /api/harness/codex with the right shape and returns { packet, timestamp,
@@ -440,6 +457,10 @@ function renderPacket(json, source, ageNote = '') {
440
457
  });
441
458
  }
442
459
 
460
+ function normalizeCachedPacketForRender(cached) {
461
+ return normalizeHarnessPacketPayload(cached?.packet ?? cached);
462
+ }
463
+
443
464
  // TCP connect probe. Resolves true if the OS completes a TCP handshake to
444
465
  // the URL's host:port; false if the OS reports a real network error
445
466
  // (ECONNREFUSED, EHOSTUNREACH, ENOTFOUND). No policy timeout — for routable
@@ -479,9 +500,12 @@ async function main() {
479
500
  const stat = fs.statSync(PACKET_CACHE);
480
501
  const ageSec = (Date.now() - stat.mtimeMs) / 1000;
481
502
  if (ageSec < PACKET_CACHE_TTL_SEC) {
482
- const cached = JSON.parse(fs.readFileSync(PACKET_CACHE, 'utf8'));
483
- await runMizanPre(apiKey, cached, '(cache)');
484
- return renderPacket(cached, '(cache)', ` cached ${Math.round(ageSec)}s`);
503
+ const cached = normalizeCachedPacketForRender(JSON.parse(fs.readFileSync(PACKET_CACHE, 'utf8')));
504
+ if (!cached?.harness && !cached?.packet?.prompt?.fullText) {
505
+ throw new Error('cached packet has no harness text after normalization');
506
+ }
507
+ await tryRunMizanPre(apiKey, cached, '(cache)');
508
+ return renderPacket(cached, '(cache)', ` cached ${Math.round(ageSec)}s`);
485
509
  }
486
510
  } catch {}
487
511
  }
@@ -526,8 +550,11 @@ async function main() {
526
550
  const stat = fs.statSync(PACKET_CACHE);
527
551
  const ageSec = (Date.now() - stat.mtimeMs) / 1000;
528
552
  if (ageSec >= 0) {
529
- const cached = JSON.parse(fs.readFileSync(PACKET_CACHE, 'utf8'));
530
- await runMizanPre(apiKey, cached, '(stale-cache)');
553
+ const cached = normalizeCachedPacketForRender(JSON.parse(fs.readFileSync(PACKET_CACHE, 'utf8')));
554
+ if (!cached?.harness && !cached?.packet?.prompt?.fullText) {
555
+ throw new Error('stale cached packet has no harness text after normalization');
556
+ }
557
+ await tryRunMizanPre(apiKey, cached, '(stale-cache)');
531
558
  try {
532
559
  appendFileSync(LOG_FILE, `${new Date().toISOString()} stale mode=${MODE} cache_age=${Math.round(ageSec)}s last_err="${lastErr.replace(/"/g, "'")}" sdk=harness-http-client\n`);
533
560
  } catch {}
@@ -53,6 +53,7 @@ import {
53
53
  normalizeRole,
54
54
  } from './lib/hook-message-window.mjs';
55
55
  import { evaluateSkillGate, formatSkillGateBlock } from './lib/skill-autoload-gate.mjs';
56
+ import { emergencyGateOffDecision } from './lib/emergency-gateoff.mjs';
56
57
 
57
58
  const HOME = process.env.HOME || '/tmp';
58
59
  const LOG = `${HOME}/.claude/aria-pre-tool-gate.log`;
@@ -72,7 +73,20 @@ function runUniversalGovernanceGate(payload) {
72
73
  try { result = stdout ? JSON.parse(stdout) : null; } catch {}
73
74
  if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
74
75
  const reason = stdout || child.stderr || 'aria-governance-gate blocked this action.';
75
- throw new Error(`=== ARIA UNIVERSAL GOVERNANCE GATE BLOCK ===\n\n${reason}`);
76
+ throw new Error([
77
+ '=== ARIA UNIVERSAL GOVERNANCE GATE BLOCK ===',
78
+ '',
79
+ reason,
80
+ '',
81
+ 'Recovery contract:',
82
+ '1. Do not retry the same blocked action unchanged.',
83
+ '2. Load or apply the doctrine/skill named by the governance output.',
84
+ '3. Re-write the action with <applied_cognition> and concrete proof.',
85
+ '4. Re-test by submitting the revised action through this same gate.',
86
+ ].join('\n'));
87
+ }
88
+ if (result?.decision === 'warn' || result?.governanceMode === 'recovery-required' || result?.governanceMode === 'architectural-intervention-required') {
89
+ process.stderr.write(`[aria-governance:${result.governanceMode || 'recovery-required'}] ${JSON.stringify(result)}\n`);
76
90
  }
77
91
  return result;
78
92
  }
@@ -181,7 +195,7 @@ function audit(decision, summary) {
181
195
  // Bootstrap: if no plan exists, the hook STILL blocks (per Hamza 2026-04-27
182
196
  // "the point is to stop wasting my time"). Claude must wait for Aria to issue
183
197
  // a plan via preprompt-consult on the next user prompt. NO unbound execution.
184
- const BINDING_ENABLED = (process.env.ARIA_BINDING_ENABLED || 'true').toLowerCase() !== 'false';
198
+ const BINDING_ENABLED = true;
185
199
  const BINDING_AUDIT = `${HOME}/.claude/aria-binding-audit.jsonl`;
186
200
 
187
201
  function bindingAuditAppend(record) {
@@ -599,12 +613,12 @@ const SHORT_BASH_LIMIT = 30;
599
613
  // accept flattened generic aliases because they change the lens meaning.
600
614
  const _INLINE_LENS_PATTERN = LENS_NAMES.join('|');
601
615
  const INLINE_LENS_LINE_RX_GLOBAL = new RegExp(
602
- `^\\s*#\\s*(${_INLINE_LENS_PATTERN})\\s*:\\s*(.+)$`,
616
+ `^\\s*(?:#|:\\s*["'])\\s*(${_INLINE_LENS_PATTERN})\\s*:\\s*(.+?)(?:["']\\s*)?$`,
603
617
  'gim',
604
618
  );
605
- const INLINE_COGNITION_HEADER_RX = /^\s*#\s*cognition\s*:\s*(.+)$/im;
606
- const INLINE_EXPECTED_LINE_RX = /^\s*#\s*expected\s*:\s*(.+)$/gim;
607
- const INLINE_VERIFY_LINE_RX = /^\s*#\s*verify\s*:\s*(.+)$/gim;
619
+ const INLINE_COGNITION_HEADER_RX = /^\s*(?:#|:\s*["'])\s*cognition\s*:\s*(.+?)(?:["']\s*)?$/im;
620
+ const INLINE_EXPECTED_LINE_RX = /^\s*(?:#|:\s*["'])\s*expected\s*:\s*(.+?)(?:["']\s*)?$/gim;
621
+ const INLINE_VERIFY_LINE_RX = /^\s*(?:#|:\s*["'])\s*verify\s*:\s*(.+?)(?:["']\s*)?$/gim;
608
622
 
609
623
  const VERIFY_REQUIRED_FIELDS = [
610
624
  { rx: /\btarget\s*:/i, name: 'target' },
@@ -1046,6 +1060,11 @@ try {
1046
1060
  audit('allow-parse-error', 'stdin not JSON');
1047
1061
  process.exit(0); // fail-open on malformed input
1048
1062
  }
1063
+ const emergencyGateOff = emergencyGateOffDecision(event);
1064
+ if (emergencyGateOff.off) {
1065
+ audit('allow-emergency-gateoff', `reason=${emergencyGateOff.reason}`);
1066
+ process.exit(0);
1067
+ }
1049
1068
 
1050
1069
  const toolName = event.tool_name ?? event.toolName ?? '';
1051
1070
  const toolInput = event.tool_input ?? event.toolInput ?? {};
@@ -1317,7 +1336,7 @@ const skillGate = evaluateSkillGate({
1317
1336
  isMutation: toolName !== 'Bash',
1318
1337
  autoLoadAvailable: false,
1319
1338
  });
1320
- if (!skillGate.ok) {
1339
+ if (!skillGate.ok && !skillGate.redirectOnly) {
1321
1340
  const reason = formatSkillGateBlock(skillGate);
1322
1341
  audit('block-missing-skill-receipt', `${skillGate.missingSkills.join(',')} ${cmdPreview}`);
1323
1342
  emitBlock(reason, { source: 'pre-tool/skill-autoload', tool: toolName, lensCount, requiredLenses: REQUIRED_LENSES });
@@ -1403,6 +1422,12 @@ function buildForceRedoActionReason(reasonText, { source = 'pre-tool-gate', tool
1403
1422
  'ORIGINAL GATE REASON:',
1404
1423
  String(reasonText || '').trim(),
1405
1424
  '',
1425
+ 'Recovery contract:',
1426
+ '1. Do not retry the same blocked tool call unchanged.',
1427
+ '2. Apply the teaching above to the next action draft before re-running the tool.',
1428
+ '3. Re-test by submitting the revised action through this same pre-tool gate.',
1429
+ '4. If the blocker is stale state, name the stale state and clear or repair it before retrying.',
1430
+ '',
1406
1431
  'REQUIRED REDO SHAPE:',
1407
1432
  '1. Emit/attach <cognition> with the required lenses before retrying the tool.',
1408
1433
  '2. For Bash, prepend inline cognition comments to the command:',
@@ -2010,7 +2035,7 @@ What Claude must do:
2010
2035
  2. Surface the failure LOUDLY — this is a substrate-level break, not a routine consult miss
2011
2036
  3. Wait for next user prompt — preprompt-consult will retry; if it succeeds a plan will exist on next tool call
2012
2037
 
2013
- Non-trivial actions are blocked until a plan exists. Trivial reads (ls/cat/grep) bypass automatically per existing whitelist. To temporarily disable binding for emergency: ARIA_BINDING_ENABLED=false (logged).`;
2038
+ Non-trivial actions are blocked until a plan exists. Trivial reads (ls/cat/grep) bypass automatically per existing whitelist. Emergency disable requires removing the hook entry or a signed owner override; env-var disable is not honored.`;
2014
2039
  emitBlock(reason, { source: 'pre-tool/substrate-binding' });
2015
2040
  process.exit(2);
2016
2041
  }
@@ -93,16 +93,15 @@ const PACKET_CACHE_PATHS = [
93
93
  `${HOME}/.claude/.aria-harness-last-packet.json`,
94
94
  ];
95
95
  const SUBSTRATE_MANIFEST_PATH = `${HOME}/.claude/.aria-loaded-substrate.json`;
96
- // Default ON. Disable explicitly via ARIA_BINDING_ENABLED=false only when the
97
- // commander/binding architecture is actively being modified (otherwise the
98
- // modification turn itself would be unable to land its own changes). The
99
- // bootstrap path handles the no-plan-yet case by AUTO-ISSUING the first plan
100
- // at hook fire time, so "no plan exists" never becomes "operate unbound."
96
+ // Default ON. Env-var disable is intentionally not honored here; emergency
97
+ // bypass must be an owner-visible hook change, not ambient subprocess drift.
98
+ // The bootstrap path handles the no-plan-yet case by AUTO-ISSUING the first
99
+ // plan at hook fire time, so "no plan exists" never becomes "operate unbound."
101
100
  //
102
101
  // Hamza 2026-04-27: "why would enforcing brick the session? the point is to
103
102
  // stop wasting my time and do quality work." Default-off was convenience-
104
103
  // seeking dressed as responsible-staging. Flipped to default-on per directive.
105
- const BINDING_ENABLED = (process.env.ARIA_BINDING_ENABLED || 'true').toLowerCase() !== 'false';
104
+ const BINDING_ENABLED = true;
106
105
 
107
106
  const HARNESS_URL =
108
107
  process.env.ARIA_HIVE_RUNTIME_URL ||
@@ -72,6 +72,11 @@ function buildForceRedoActionReason({ source, reason, missingSignals = [], incid
72
72
  missingSignals.length ? `\nMISSING SIGNALS:\n${missingSignals.map((signal) => `- ${signal}`).join('\n')}` : '',
73
73
  incidents.length ? `\nINCIDENTS TO RESOLVE:\n${incidents.map((incident) => `- ${incident}`).join('\n')}` : '',
74
74
  '',
75
+ 'Recovery contract:',
76
+ '1. Do not proceed with tools from the blocked context unchanged.',
77
+ '2. Run the structured recovery action in hookSpecificOutput.recovery.',
78
+ '3. Re-test by verifying harness_packet, aria_direction/binding_plan, and memory references are loaded.',
79
+ '',
75
80
  'REQUIRED REDO SHAPE:',
76
81
  '1. Run the structured recovery action in hookSpecificOutput.recovery.',
77
82
  '2. Verify harness_packet, aria_direction/binding_plan, and memory references are loaded.',
@@ -102,6 +102,11 @@ function buildForceRedoActionReason({ source, reason, violations = [] }) {
102
102
  '- External provider calls must use an approved runtime/SDK path or carry the explicit external-call allow marker.',
103
103
  violations.length ? `\nVIOLATIONS TO FIX:\n${violations.map((v) => `- ${v}`).join('\n')}` : '',
104
104
  '',
105
+ 'Recovery contract:',
106
+ '1. Do not retry the same blocked edit/action unchanged.',
107
+ '2. Apply the teaching above by removing or isolating every violating production-path pattern.',
108
+ '3. Re-test by running this repo doctrine gate before retrying the original action.',
109
+ '',
105
110
  'REQUIRED REDO SHAPE:',
106
111
  '1. Preserve the intended behavior without stub/mock/pending semantics.',
107
112
  '2. Use real implementation wiring or an explicit reviewed allow marker.',
@@ -373,6 +378,16 @@ function renderReason(repoRoot, violations, mode) {
373
378
  '',
374
379
  `Allow path categories: tests/specs/fixtures/examples/demos/mocks, or add ${ALLOW_MARKER} in the file when the exception is intentional and reviewable.`,
375
380
  `External provider calls require explicit ${ALLOW_EXTERNAL_LLM_CALL_MARKER} marker or an approved internal runtime/SDK path.`,
381
+ '',
382
+ 'TEACHING:',
383
+ '- Repo doctrine blocks protect production paths from fake or placeholder behavior.',
384
+ '- If this is a real implementation, replace the flagged language with shipped behavior or isolate it under an allowed test/example surface.',
385
+ '',
386
+ 'Recovery contract:',
387
+ '1. Do not retry the same commit/tool action unchanged.',
388
+ '2. Remove or replace each flagged stub/mock/pending/external-call pattern in production paths.',
389
+ `3. If an exception is intentional, add ${ALLOW_MARKER} or ${ALLOW_EXTERNAL_LLM_CALL_MARKER} with a reviewable reason.`,
390
+ '4. Re-run this repo doctrine gate before retrying the original action.',
376
391
  ].join('\n');
377
392
  }
378
393