@aria_asi/cli 0.2.36 → 0.2.38

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 (198) 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 +290 -32
  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 +86 -8
  53. package/dist/assets/hooks/aria-pre-tool-use.mjs +75 -0
  54. package/dist/assets/hooks/aria-preprompt-consult.mjs +5 -6
  55. package/dist/assets/hooks/aria-preturn-memory-gate.mjs +5 -0
  56. package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +15 -0
  57. package/dist/assets/hooks/aria-stop-gate.mjs +125 -17
  58. package/dist/assets/hooks/doctrine_trigger_map.json +11 -0
  59. package/dist/assets/hooks/lib/emergency-gateoff-impl.mjs +39 -0
  60. package/dist/assets/hooks/lib/emergency-gateoff.mjs +6 -0
  61. package/dist/assets/hooks/lib/first-class-coach.mjs +755 -0
  62. package/dist/assets/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
  63. package/dist/assets/hooks/lib/skill-autoload-gate.mjs +1 -14
  64. package/dist/assets/opencode-plugins/harness-context/auth-token.mjs +126 -0
  65. package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +62 -22
  66. package/dist/assets/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
  67. package/dist/assets/opencode-plugins/harness-gate/index.js +87 -27
  68. package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
  69. package/dist/assets/opencode-plugins/harness-outcome/index.js +29 -24
  70. package/dist/assets/opencode-plugins/harness-stop/index.js +229 -68
  71. package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
  72. package/dist/runtime/auth-token.mjs +121 -0
  73. package/dist/runtime/coach-kernel.mjs +377 -0
  74. package/dist/runtime/codex-bridge.mjs +440 -69
  75. package/dist/runtime/discipline/doctrine_trigger_map.json +11 -0
  76. package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +18 -0
  77. package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
  78. package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
  79. package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
  80. package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
  81. package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
  82. package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
  83. package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +18 -0
  84. package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +18 -0
  85. package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
  86. package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +18 -0
  87. package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
  88. package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +18 -0
  89. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +18 -0
  90. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +18 -0
  91. package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +18 -0
  92. package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +18 -0
  93. package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +18 -0
  94. package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +18 -0
  95. package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +18 -0
  96. package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +18 -0
  97. package/dist/runtime/doctrine_trigger_map.json +11 -0
  98. package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +51 -9
  99. package/dist/runtime/hooks/aria-first-class-coach.mjs +129 -0
  100. package/dist/runtime/hooks/aria-harness-via-sdk.mjs +33 -6
  101. package/dist/runtime/hooks/aria-pre-tool-gate.mjs +86 -8
  102. package/dist/runtime/hooks/aria-pre-tool-use.mjs +75 -0
  103. package/dist/runtime/hooks/aria-preprompt-consult.mjs +5 -6
  104. package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +5 -0
  105. package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +15 -0
  106. package/dist/runtime/hooks/aria-stop-gate.mjs +125 -17
  107. package/dist/runtime/hooks/doctrine_trigger_map.json +11 -0
  108. package/dist/runtime/hooks/lib/emergency-gateoff-impl.mjs +39 -0
  109. package/dist/runtime/hooks/lib/emergency-gateoff.mjs +6 -0
  110. package/dist/runtime/hooks/lib/first-class-coach.mjs +755 -0
  111. package/dist/runtime/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
  112. package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +1 -14
  113. package/dist/runtime/local-phase.mjs +8 -0
  114. package/dist/runtime/manifest.json +2 -2
  115. package/dist/runtime/provider-proxy.mjs +136 -33
  116. package/dist/runtime/sdk/BUNDLED.json +2 -2
  117. package/dist/runtime/sdk/auth.d.ts +17 -0
  118. package/dist/runtime/sdk/auth.js +158 -0
  119. package/dist/runtime/sdk/auth.js.map +1 -0
  120. package/dist/runtime/sdk/index.d.ts +8 -1
  121. package/dist/runtime/sdk/index.js +15 -1
  122. package/dist/runtime/sdk/index.js.map +1 -1
  123. package/dist/runtime/service.mjs +1711 -74
  124. package/dist/runtime/task-project-ledger.mjs +290 -0
  125. package/dist/sdk/BUNDLED.json +2 -2
  126. package/dist/sdk/auth.d.ts +17 -0
  127. package/dist/sdk/auth.js +158 -0
  128. package/dist/sdk/auth.js.map +1 -0
  129. package/dist/sdk/index.d.ts +8 -1
  130. package/dist/sdk/index.js +15 -1
  131. package/dist/sdk/index.js.map +1 -1
  132. package/hooks/aria-cognition-substrate-binding.mjs +51 -9
  133. package/hooks/aria-first-class-coach.mjs +129 -0
  134. package/hooks/aria-harness-via-sdk.mjs +33 -6
  135. package/hooks/aria-pre-tool-gate.mjs +86 -8
  136. package/hooks/aria-pre-tool-use.mjs +75 -0
  137. package/hooks/aria-preprompt-consult.mjs +5 -6
  138. package/hooks/aria-preturn-memory-gate.mjs +5 -0
  139. package/hooks/aria-repo-doctrine-gate.mjs +15 -0
  140. package/hooks/aria-stop-gate.mjs +125 -17
  141. package/hooks/doctrine_trigger_map.json +11 -0
  142. package/hooks/lib/emergency-gateoff-impl.mjs +39 -0
  143. package/hooks/lib/emergency-gateoff.mjs +6 -0
  144. package/hooks/lib/first-class-coach.mjs +755 -0
  145. package/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
  146. package/hooks/lib/skill-autoload-gate.mjs +1 -14
  147. package/opencode-plugins/harness-context/auth-token.mjs +126 -0
  148. package/opencode-plugins/harness-context/inject-context.mjs +62 -22
  149. package/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
  150. package/opencode-plugins/harness-gate/index.js +87 -27
  151. package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
  152. package/opencode-plugins/harness-outcome/index.js +29 -24
  153. package/opencode-plugins/harness-stop/index.js +229 -68
  154. package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
  155. package/package.json +8 -2
  156. package/runtime-src/auth-token.mjs +121 -0
  157. package/runtime-src/coach-kernel.mjs +377 -0
  158. package/runtime-src/codex-bridge.mjs +440 -69
  159. package/runtime-src/local-phase.mjs +8 -0
  160. package/runtime-src/provider-proxy.mjs +136 -33
  161. package/runtime-src/service.mjs +1711 -74
  162. package/scripts/bundle-sdk.mjs +8 -0
  163. package/scripts/check-client-compatibility.mjs +422 -0
  164. package/scripts/check-coach-kernel.mjs +204 -0
  165. package/scripts/check-managed-runtime-ledger.mjs +107 -0
  166. package/scripts/check-opencode-config-contract.mjs +78 -0
  167. package/scripts/check-quality-ledger.mjs +121 -0
  168. package/scripts/self-test-harness-gates.mjs +179 -11
  169. package/scripts/self-test-repo-guard.mjs +38 -0
  170. package/scripts/validate-skill-prompts.mjs +14 -1
  171. package/skills/aria-cognition/aria-essence/SKILL.md +18 -0
  172. package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
  173. package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
  174. package/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
  175. package/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
  176. package/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
  177. package/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
  178. package/skills/aria-cognition/mizan/SKILL.md +18 -0
  179. package/skills/aria-cognition/nadia/SKILL.md +18 -0
  180. package/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
  181. package/skills/aria-cognition/predictor/SKILL.md +18 -0
  182. package/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
  183. package/skills/aria-cognition/soul-domains/SKILL.md +18 -0
  184. package/src/auth.ts +136 -1
  185. package/src/chat.ts +13 -8
  186. package/src/config.ts +6 -1
  187. package/src/connectors/claude-code.ts +62 -18
  188. package/src/connectors/codex.ts +288 -32
  189. package/src/connectors/opencode.ts +35 -12
  190. package/src/connectors/repo-guard.ts +117 -172
  191. package/src/connectors/runtime.ts +19 -7
  192. package/src/connectors/shell.ts +12 -8
  193. package/src/harness-client.ts +8 -22
  194. package/src/model-context.ts +6 -0
  195. package/src/providers/types.ts +1 -1
  196. package/src/providers/xai.ts +55 -0
  197. package/src/setup-wizard.ts +1 -0
  198. package/src/types.ts +2 -0
@@ -24,6 +24,15 @@ function packageSdkDir(): string {
24
24
  return path.resolve(here, '..', '..', '..', 'sdk');
25
25
  }
26
26
 
27
+ function packageTaskProjectLedgerHelperPath(): string {
28
+ const here = path.dirname(fileURLToPath(import.meta.url));
29
+ const candidates = [
30
+ path.resolve(here, '..', '..', '..', '..', 'opencode-plugins', 'harness-context', 'task-project-ledger.mjs'),
31
+ path.resolve(here, '..', '..', '..', 'assets', 'opencode-plugins', 'harness-context', 'task-project-ledger.mjs'),
32
+ ];
33
+ return candidates.find((candidate) => existsSync(candidate)) || candidates[0];
34
+ }
35
+
27
36
  function installSdk(codexDir: string, logs: string[]): void {
28
37
  const sdkSrc = packageSdkDir();
29
38
  if (!existsSync(sdkSrc)) {
@@ -95,6 +104,9 @@ import { createHash, randomUUID } from 'node:crypto';
95
104
  import { homedir } from 'node:os';
96
105
  import path from 'node:path';
97
106
  import { HTTPHarnessClient } from '@aria_asi/harness-http-client';
107
+ import { updateTaskProjectLedger, evaluateTaskProjectClaim, recordBlockedTaskProjectClaim } from './task-project-ledger.mjs';
108
+
109
+ export { updateTaskProjectLedger, evaluateTaskProjectClaim, recordBlockedTaskProjectClaim };
98
110
 
99
111
  const HOME = homedir();
100
112
  const DEFAULT_RUNTIME_URL = (process.env.ARIA_RUNTIME_URL || 'http://127.0.0.1:4319').replace(/\\/+$/, '');
@@ -102,7 +114,7 @@ const TURN_STATE_DIR = path.join(HOME, '.codex', 'tmp', 'aria-hook-turn-state');
102
114
  const GOVERNANCE_GATE_PATH = path.join(HOME, '.aria', 'bin', 'aria-governance-gate');
103
115
 
104
116
  function readToken() {
105
- const envToken = process.env.ARIA_API_KEY || process.env.ARIA_MASTER_TOKEN || process.env.OPENAI_API_KEY;
117
+ const envToken = process.env.ARIA_HARNESS_TOKEN || process.env.ARIA_API_KEY || process.env.ARIA_MASTER_TOKEN;
106
118
  if (envToken) return envToken;
107
119
  const ownerPath = path.join(HOME, '.aria', 'owner-token');
108
120
  if (existsSync(ownerPath)) return readFileSync(ownerPath, 'utf8').trim();
@@ -264,6 +276,24 @@ export async function runtimePost(route, body = {}) {
264
276
  return response.json();
265
277
  }
266
278
 
279
+ export async function recordCoachPhase(phase, body = {}) {
280
+ try {
281
+ return await runtimePost('/coach/phase', {
282
+ phase,
283
+ surface: 'codex-hooks',
284
+ lane: 'codex_native_hooks',
285
+ ...body,
286
+ });
287
+ } catch (error) {
288
+ return {
289
+ ok: false,
290
+ permitted: true,
291
+ decision: 'warn_operator_only',
292
+ error: error instanceof Error ? error.message : String(error),
293
+ };
294
+ }
295
+ }
296
+
267
297
  export function classifyAction(event) {
268
298
  const toolName = String(event?.tool_name || event?.toolName || '').trim();
269
299
  const toolCommand = String(
@@ -307,6 +337,23 @@ export function extractAssistantText(event) {
307
337
  );
308
338
  }
309
339
 
340
+ function normalizeValidationIssue(issue) {
341
+ const raw = String(issue || '').replace(/\\s+/g, ' ').trim();
342
+ if (!raw) return '';
343
+ if (/No <cognition>/i.test(raw)) return 'missing readable cognition block';
344
+ if (/missing\\s+<applied_cognition>/i.test(raw)) return 'missing applied cognition contract';
345
+ if (/qualitative_drift/i.test(raw)) return 'qualitative drift language needs a measurable predicate';
346
+ if (/premature_task_closeout|feedback_no_premature_task_closeout|done\\|complete\\|completed\\|ready\\|verified\\|fixed/i.test(raw)) {
347
+ return 'completion/readiness claim conflicts with unresolved blocker state';
348
+ }
349
+ if (/\\(\\?:/.test(raw)) return 'doctrine matcher triggered; re-author with the named doctrine and concrete evidence';
350
+ return raw.slice(0, 600);
351
+ }
352
+
353
+ function uniqueStrings(values) {
354
+ return Array.from(new Set(values.map(normalizeValidationIssue).filter(Boolean)));
355
+ }
356
+
310
357
  export function formatValidationFailure(result) {
311
358
  const parts = [];
312
359
  if (Array.isArray(result?.validation?.violations) && result.validation.violations.length) {
@@ -318,7 +365,31 @@ export function formatValidationFailure(result) {
318
365
  if (!parts.length && typeof result?.summary === 'string' && result.summary.trim()) {
319
366
  parts.push(result.summary.trim());
320
367
  }
321
- return parts.join(' | ') || 'Aria validation failed.';
368
+ return uniqueStrings(parts).join(' | ') || 'Aria validation failed.';
369
+ }
370
+
371
+ export function isAriaControlBlock(text) {
372
+ return /^(?:ARIA CODEX RECOVERY CONTRACT|Aria runtime blocked final output for this Codex turn\\.|Aria stop gate blocked output:|Aria task\\/project ledger blocked output claim\\.|Aria stop hook failed closed:)/i.test(String(text || '').trim());
373
+ }
374
+
375
+ export function formatCodexRecoveryBlock({ surface = 'codex', reason = '', issues = [], next = '' } = {}) {
376
+ const blockers = uniqueStrings([reason, ...issues]);
377
+ return [
378
+ 'ARIA CODEX RECOVERY CONTRACT',
379
+ 'surface: ' + surface,
380
+ 'status: output held for re-authoring',
381
+ '',
382
+ 'Observed blockers:',
383
+ ...(blockers.length ? blockers.map((item) => '- ' + item) : ['- Aria validation failed.']),
384
+ '',
385
+ 'Recovery contract:',
386
+ '1. Do not retry the same blocked text.',
387
+ '2. Re-author the answer from the user request, not from this block report.',
388
+ '3. Include <cognition> and <applied_cognition> when the answer is non-trivial.',
389
+ '4. Use bounded status language when evidence is missing; do not use completion/readiness claims without proof.',
390
+ '5. Name a measurable verification predicate, or explicitly state that verification has not run.',
391
+ next || '6. Re-submit the corrected answer; if the same blocker repeats twice, escalate with this full recovery contract.',
392
+ ].join('\\n');
322
393
  }
323
394
 
324
395
  export function emitJson(payload, code = 0) {
@@ -355,9 +426,12 @@ import {
355
426
  makeEvidenceRef,
356
427
  readEventFromStdin,
357
428
  runtimePost,
429
+ recordCoachPhase,
358
430
  loadTurnState,
359
431
  saveTurnState,
360
432
  runGovernanceGate,
433
+ updateTaskProjectLedger,
434
+ formatCodexRecoveryBlock,
361
435
  emitJson,
362
436
  } from './lib/runtime-client.mjs';
363
437
 
@@ -368,8 +442,21 @@ const sessionId = inferSessionId(event);
368
442
  const userId = inferUserId(event);
369
443
  const priorState = loadTurnState(sessionId);
370
444
  const traceId = ensureTraceId(priorState);
445
+ const ledgerResult = updateTaskProjectLedger({
446
+ platform: 'codex',
447
+ phase: 'pre_prompt_injection',
448
+ source: 'codex-userprompt-hook',
449
+ event: { ...event, prompt: userText, sessionId, cwd: process.cwd() },
450
+ });
371
451
 
372
452
  try {
453
+ await recordCoachPhase('pre_turn', {
454
+ requestId: traceId,
455
+ sessionId,
456
+ text: userText,
457
+ evidenceRefs: [makeEvidenceRef('user_input', userText, { sessionId, traceId, platform: 'codex' })],
458
+ metadata: { source: 'codex-userprompt-hook', userId },
459
+ });
373
460
  const packet = await client.getHarnessPacket({
374
461
  sessionId,
375
462
  platform: 'codex',
@@ -404,11 +491,19 @@ try {
404
491
  evidenceRefs: [packetRef],
405
492
  },
406
493
  });
494
+ await recordCoachPhase('post_cognition', {
495
+ requestId: traceId,
496
+ sessionId,
497
+ text: userText,
498
+ evidenceRefs: [packetRef, makeEvidenceRef('mizan_pre_receipt', result?.receipt || null, { sessionId, traceId })],
499
+ metadata: { source: 'codex-userprompt-hook', pre_receipt_id: result?.receipt?.receiptId || null },
500
+ });
407
501
  saveTurnState(sessionId, {
408
502
  traceId,
409
503
  userId,
410
504
  userText,
411
505
  preReceiptId: result?.receipt?.receiptId || null,
506
+ taskProjectLedgerId: ledgerResult.ledger.ledgerId,
412
507
  packetTimestamp: packet?.timestamp || null,
413
508
  packetRef,
414
509
  lastEvent: 'UserPromptSubmit',
@@ -417,7 +512,11 @@ try {
417
512
  } catch (error) {
418
513
  emitJson({
419
514
  decision: 'block',
420
- reason: \`Aria cognition gate failed before turn start: \${error instanceof Error ? error.message : String(error)}\`,
515
+ reason: formatCodexRecoveryBlock({
516
+ surface: 'codex-userprompt',
517
+ reason: error instanceof Error ? error.message : String(error),
518
+ next: '6. Re-open the prompt substrate, repair the cognition gate blocker, then submit the prompt again.',
519
+ }),
421
520
  });
422
521
  }
423
522
  `;
@@ -426,20 +525,19 @@ try {
426
525
  function buildCodexPreToolHook(): string {
427
526
  return `#!/usr/bin/env node
428
527
  import {
429
- getHarnessClient,
430
528
  inferSessionId,
431
529
  classifyAction,
432
530
  summarizeTarget,
433
531
  readEventFromStdin,
434
532
  loadTurnState,
435
533
  makeEvidenceRef,
534
+ recordCoachPhase,
436
535
  saveTurnState,
437
- runGovernanceGate,
536
+ formatCodexRecoveryBlock,
438
537
  emitJson,
439
538
  } from './lib/runtime-client.mjs';
440
539
 
441
540
  const event = readEventFromStdin();
442
- const client = getHarnessClient();
443
541
  const sessionId = inferSessionId(event);
444
542
  const action = classifyAction(event);
445
543
  const target = summarizeTarget(event);
@@ -449,28 +547,34 @@ try {
449
547
  if (!state?.preReceiptId && !state?.userText) {
450
548
  emitJson({
451
549
  decision: 'block',
452
- reason: 'Aria pre-tool gate blocked action because this turn has no pre-turn Mizan receipt. Re-submit the prompt so cognition is established before tool use.',
453
- });
454
- }
455
- const actionCheck = await client.checkAction(action, target);
456
- if (actionCheck?.allowed === false) {
457
- emitJson({
458
- decision: 'block',
459
- reason: actionCheck?.reason || \`Aria denied \${action}\`,
550
+ reason: formatCodexRecoveryBlock({
551
+ surface: 'codex-pre-tool',
552
+ reason: 'this turn has no pre-turn Mizan receipt',
553
+ next: '6. Re-submit the prompt so cognition is established before tool use, then request the tool again.',
554
+ }),
460
555
  });
461
556
  }
462
557
  const toolName = String(event?.tool_name || event?.toolName || '').trim() || null;
463
- runGovernanceGate({
558
+ const requestRef = makeEvidenceRef('codex_tool_request', { action, toolName, target }, { sessionId });
559
+ const coach = await recordCoachPhase('pre_tool', {
560
+ requestId: state?.traceId || sessionId,
464
561
  sessionId,
465
- sourceRuntime: 'codex',
466
- surface: 'codex-pre-tool-use',
467
- text: JSON.stringify(event).slice(0, 8000),
562
+ text: target,
468
563
  action,
469
- toolName,
470
- isDeploy: action === 'deploy',
471
- isMutation: action === 'write' || action === 'delete',
472
- evidence: makeEvidenceRef('codex_tool_request', { action, toolName, target }, { sessionId }),
564
+ target,
565
+ evidenceRefs: [requestRef],
566
+ metadata: { source: 'codex-pre-tool-hook', toolName, requireVerify: action === 'deploy' || action === 'delete' },
473
567
  });
568
+ if (coach?.permitted === false) {
569
+ emitJson({
570
+ decision: 'block',
571
+ reason: formatCodexRecoveryBlock({
572
+ surface: 'codex-pre-tool-coach',
573
+ reason: coach.clientMessage || 'Coach Kernel denied ' + action,
574
+ next: '6. Add the required evidence/cognition contract, then request the tool again.',
575
+ }),
576
+ });
577
+ }
474
578
  const tools = Array.isArray(state?.tools) ? state.tools.slice(-24) : [];
475
579
  tools.push({
476
580
  at: new Date().toISOString(),
@@ -487,7 +591,10 @@ try {
487
591
  } catch (error) {
488
592
  emitJson({
489
593
  decision: 'block',
490
- reason: \`Aria pre-tool hook failed closed: \${error instanceof Error ? error.message : String(error)}\`,
594
+ reason: formatCodexRecoveryBlock({
595
+ surface: 'codex-pre-tool-hook',
596
+ reason: error instanceof Error ? error.message : String(error),
597
+ }),
491
598
  });
492
599
  }
493
600
  `;
@@ -500,7 +607,9 @@ import {
500
607
  readEventFromStdin,
501
608
  loadTurnState,
502
609
  makeEvidenceRef,
610
+ recordCoachPhase,
503
611
  saveTurnState,
612
+ updateTaskProjectLedger,
504
613
  } from './lib/runtime-client.mjs';
505
614
 
506
615
  const event = readEventFromStdin();
@@ -514,6 +623,20 @@ try {
514
623
  toolName: event?.tool_name || event?.toolName || null,
515
624
  });
516
625
  const toolOutputs = Array.isArray(state?.toolOutputs) ? state.toolOutputs.slice(-24) : [];
626
+ const verificationText = JSON.stringify(event).slice(0, 8000);
627
+ const verification = !event?.error && /\\b(?:npm\\s+run\\s+(?:check|test|build|lint|typecheck)|(?:npx\\s+)?(?:jest|vitest|tsc|eslint)|check:|test:|build:|passed|exit\\s*0|0\\s*failures?)\\b/i.test(verificationText);
628
+ await recordCoachPhase('post_tool', {
629
+ requestId: state?.traceId || sessionId,
630
+ sessionId,
631
+ text: verificationText,
632
+ evidenceRefs: [evidenceRef],
633
+ metadata: {
634
+ source: 'codex-post-tool-hook',
635
+ toolName: event?.tool_name || event?.toolName || null,
636
+ verification,
637
+ error: event?.error || null,
638
+ },
639
+ });
517
640
  toolOutputs.push({
518
641
  at: new Date().toISOString(),
519
642
  toolName: event?.tool_name || event?.toolName || null,
@@ -524,6 +647,17 @@ try {
524
647
  toolOutputs,
525
648
  lastEvent: 'PostToolUse',
526
649
  });
650
+ updateTaskProjectLedger({
651
+ platform: 'codex',
652
+ phase: 'post_tool',
653
+ source: 'codex-post-tool-hook',
654
+ event: { ...event, sessionId, cwd: process.cwd() },
655
+ evidence: {
656
+ outcome_ref: evidenceRef,
657
+ verification,
658
+ commandResult: verification ? 'success' : '',
659
+ },
660
+ });
527
661
  process.exit(0);
528
662
  } catch {
529
663
  process.exit(0);
@@ -538,11 +672,16 @@ import {
538
672
  extractAssistantText,
539
673
  readEventFromStdin,
540
674
  runtimePost,
675
+ recordCoachPhase,
541
676
  loadTurnState,
542
677
  makeEvidenceRef,
543
678
  clearTurnState,
544
679
  formatValidationFailure,
545
- runGovernanceGate,
680
+ formatCodexRecoveryBlock,
681
+ isAriaControlBlock,
682
+ updateTaskProjectLedger,
683
+ evaluateTaskProjectClaim,
684
+ recordBlockedTaskProjectClaim,
546
685
  emitJson,
547
686
  } from './lib/runtime-client.mjs';
548
687
 
@@ -552,19 +691,58 @@ const state = loadTurnState(sessionId);
552
691
  const text = extractAssistantText(event);
553
692
  const outputRef = makeEvidenceRef('assistant_output', text, { sessionId, traceId: state?.traceId || null });
554
693
  const toolRefs = Array.isArray(state?.toolOutputs) ? state.toolOutputs.map((entry) => entry.evidenceRef).filter(Boolean) : [];
694
+ const ledgerResult = updateTaskProjectLedger({
695
+ platform: 'codex',
696
+ phase: 'stop',
697
+ source: 'codex-stop-hook',
698
+ event: { ...event, text, sessionId, cwd: process.cwd() },
699
+ });
555
700
 
556
701
  try {
557
702
  if (!text) {
558
703
  emitJson({ continue: true });
559
704
  }
560
- runGovernanceGate({
705
+ if (isAriaControlBlock(text)) {
706
+ clearTurnState(sessionId);
707
+ emitJson({ continue: true });
708
+ }
709
+ const postGenerationCoach = await recordCoachPhase('post_generation', {
710
+ requestId: state?.traceId || sessionId,
561
711
  sessionId,
562
- sourceRuntime: 'codex',
563
- surface: 'codex-stop',
564
- text: text.slice(0, 8000),
565
- isOutputCloseout: true,
566
- evidence: outputRef,
712
+ text,
713
+ evidenceRefs: [outputRef],
714
+ metadata: { source: 'codex-stop-hook', requireCognitionBlock: false, requireAppliedCognition: false },
567
715
  });
716
+ if (postGenerationCoach?.permitted === false) {
717
+ emitJson({
718
+ decision: 'block',
719
+ reason: formatCodexRecoveryBlock({
720
+ surface: 'codex-stop-coach-post-generation',
721
+ reason: postGenerationCoach.clientMessage || 'Coach Kernel held Codex output before validation.',
722
+ }),
723
+ });
724
+ }
725
+ const ledgerClaim = evaluateTaskProjectClaim({ text, ledger: ledgerResult.ledger });
726
+ if (!ledgerClaim.ok) {
727
+ recordBlockedTaskProjectClaim({
728
+ ledger: ledgerResult.ledger,
729
+ paths: ledgerResult.paths,
730
+ text,
731
+ evaluation: ledgerClaim,
732
+ });
733
+ emitJson({
734
+ decision: 'block',
735
+ reason: formatCodexRecoveryBlock({
736
+ surface: 'codex-stop-ledger',
737
+ reason: 'task/project ledger rejected an output claim',
738
+ issues: [
739
+ \`missing readiness gates: \${ledgerClaim.missingReadinessGates.join(', ') || 'none'}\`,
740
+ \`open blockers: \${ledgerClaim.openBlockers.length}\`,
741
+ ],
742
+ next: '6. Record real verification evidence or emit bounded status without completion/readiness language, then re-submit.',
743
+ }),
744
+ });
745
+ }
568
746
  const validation = await runtimePost('/validate-output', {
569
747
  text,
570
748
  sessionId,
@@ -579,10 +757,31 @@ try {
579
757
  requireCognitionBlock: false,
580
758
  runLayer3: true,
581
759
  });
760
+ const preOutputCoach = await recordCoachPhase('pre_output', {
761
+ requestId: state?.traceId || sessionId,
762
+ sessionId,
763
+ text,
764
+ validation: validation?.validation || null,
765
+ layer3: validation?.layer3 || null,
766
+ evidenceRefs: [outputRef, makeEvidenceRef('runtime_validation', validation, { sessionId, traceId: state?.traceId || null })],
767
+ metadata: { source: 'codex-stop-hook', requireCognitionBlock: false, requireAppliedCognition: false },
768
+ });
769
+ if (preOutputCoach?.permitted === false) {
770
+ emitJson({
771
+ decision: 'block',
772
+ reason: formatCodexRecoveryBlock({
773
+ surface: 'codex-stop-coach-pre-output',
774
+ reason: preOutputCoach.clientMessage || 'Coach Kernel held Codex output before release.',
775
+ }),
776
+ });
777
+ }
582
778
  if (validation?.pass === false || validation?.validation?.passed === false || validation?.layer3?.pass === false) {
583
779
  emitJson({
584
780
  decision: 'block',
585
- reason: \`Aria stop gate blocked output: \${formatValidationFailure(validation)}\`,
781
+ reason: formatCodexRecoveryBlock({
782
+ surface: 'codex-stop-output',
783
+ reason: formatValidationFailure(validation),
784
+ }),
586
785
  });
587
786
  }
588
787
  const post = await runtimePost('/mizan/post', {
@@ -607,6 +806,18 @@ try {
607
806
  },
608
807
  parentReceiptId: state?.preReceiptId || null,
609
808
  });
809
+ await recordCoachPhase('post_output', {
810
+ requestId: state?.traceId || sessionId,
811
+ sessionId,
812
+ text,
813
+ validation: validation?.validation || null,
814
+ layer3: validation?.layer3 || null,
815
+ evidenceRefs: [
816
+ outputRef,
817
+ makeEvidenceRef('mizan_post_receipt', post?.receipt || null, { sessionId, traceId: state?.traceId || null }),
818
+ ],
819
+ metadata: { source: 'codex-stop-hook', requireCognitionBlock: false, requireAppliedCognition: false },
820
+ });
610
821
  await runtimePost('/decision/log', {
611
822
  session_id: sessionId,
612
823
  decision_type: 'operational',
@@ -643,12 +854,51 @@ try {
643
854
  },
644
855
  });
645
856
  }
857
+ updateTaskProjectLedger({
858
+ platform: 'codex',
859
+ phase: 'post_turn',
860
+ source: 'codex-stop-hook',
861
+ event: { ...event, text, sessionId, cwd: process.cwd() },
862
+ evidence: {
863
+ post_turn: true,
864
+ output_ref: outputRef,
865
+ verification: false,
866
+ },
867
+ });
868
+ const releaseCoach = await recordCoachPhase('claim_or_release', {
869
+ requestId: state?.traceId || sessionId,
870
+ sessionId,
871
+ text,
872
+ validation: validation?.validation || null,
873
+ layer3: validation?.layer3 || null,
874
+ evidenceRefs: [outputRef, ...toolRefs],
875
+ metadata: {
876
+ source: 'codex-stop-hook',
877
+ validated_output: true,
878
+ requireCognitionBlock: false,
879
+ requireAppliedCognition: false,
880
+ post_receipt_id: post?.receipt?.receiptId || null,
881
+ },
882
+ });
883
+ if (releaseCoach?.permitted === false) {
884
+ emitJson({
885
+ decision: 'block',
886
+ reason: formatCodexRecoveryBlock({
887
+ surface: 'codex-stop-coach-release',
888
+ reason: releaseCoach.clientMessage || 'Coach Kernel held the release claim.',
889
+ }),
890
+ });
891
+ }
646
892
  clearTurnState(sessionId);
647
893
  emitJson({ continue: true });
648
894
  } catch (error) {
649
895
  emitJson({
650
896
  decision: 'block',
651
- reason: \`Aria stop hook failed closed: \${error instanceof Error ? error.message : String(error)}\`,
897
+ reason: formatCodexRecoveryBlock({
898
+ surface: 'codex-stop-hook',
899
+ reason: error instanceof Error ? error.message : String(error),
900
+ next: '6. Re-open the turn substrate, repair the hook/runtime blocker, and re-submit with this recovery contract if it repeats.',
901
+ }),
652
902
  });
653
903
  }
654
904
  `;
@@ -696,6 +946,10 @@ function installCodexHooksConfig(codexDir: string, logs: string[]): void {
696
946
  function installCodexHooks(codexDir: string, logs: string[]): void {
697
947
  const hooksDir = path.join(codexDir, 'hooks');
698
948
  mkdirSync(path.join(hooksDir, 'lib'), { recursive: true, mode: 0o755 });
949
+ const ledgerHelperSrc = packageTaskProjectLedgerHelperPath();
950
+ if (!existsSync(ledgerHelperSrc)) {
951
+ throw new Error(`Task/project ledger helper missing: ${ledgerHelperSrc}`);
952
+ }
699
953
 
700
954
  const files: Array<[string, string]> = [
701
955
  [path.join(hooksDir, 'lib', 'runtime-client.mjs'), buildCodexHookRuntimeClient()],
@@ -709,6 +963,8 @@ function installCodexHooks(codexDir: string, logs: string[]): void {
709
963
  writeFileSync(filePath, content, { mode: 0o755 });
710
964
  try { chmodSync(filePath, 0o755); } catch {}
711
965
  }
966
+ copyFileSync(ledgerHelperSrc, path.join(hooksDir, 'lib', 'task-project-ledger.mjs'));
967
+ try { chmodSync(path.join(hooksDir, 'lib', 'task-project-ledger.mjs'), 0o755); } catch {}
712
968
 
713
969
  logs.push(`Installed Codex native hooks → ${hooksDir}`);
714
970
  installCodexHooksConfig(codexDir, logs);
@@ -18,6 +18,7 @@ import type { AriaConfig } from '../config.js';
18
18
  import { connectShell } from './shell.js';
19
19
  import { syncDoctrineTriggerMap } from './doctrine-trigger-map.js';
20
20
  import { buildMustReadGuide, mustReadIntro } from './must-read.js';
21
+ import { resolveHarnessToken } from '../auth.js';
21
22
 
22
23
  // ── Bundled OpenCode plugins ────────────────────────────────────────────────
23
24
  //
@@ -33,6 +34,8 @@ import { buildMustReadGuide, mustReadIntro } from './must-read.js';
33
34
  // Both live at <pkg>/opencode-plugins/<name>/. connectOpenCode copies them
34
35
  // into ~/.opencode/plugins/<name>/ and wires the absolute paths into
35
36
  // ~/.opencode/config.json's `plugin` (singular, OpenCode v2 schema) array.
37
+ // Shared hook helpers are also copied into ~/.opencode/hooks/ because the
38
+ // installed plugins resolve their gate helpers from that OpenCode-owned root.
36
39
  //
37
40
  // Compiled location of THIS file (claude-code path applies the same way):
38
41
  // <pkg>/dist/aria-connector/src/connectors/opencode.js
@@ -51,6 +54,16 @@ function packageOpenCodePluginsDir(): string {
51
54
  return found || candidates[0];
52
55
  }
53
56
 
57
+ function packageOpenCodeHooksDir(): string {
58
+ const here = path.dirname(fileURLToPath(import.meta.url));
59
+ const candidates = [
60
+ path.resolve(here, '..', '..', '..', '..', 'hooks'),
61
+ path.resolve(here, '..', '..', '..', 'assets', 'hooks'),
62
+ ];
63
+ const found = candidates.find((candidate) => existsSync(candidate));
64
+ return found || candidates[0];
65
+ }
66
+
54
67
  function copyPluginDir(srcDir: string, dstDir: string, logs: string[]): void {
55
68
  if (!existsSync(dstDir)) {
56
69
  mkdirSync(dstDir, { recursive: true, mode: 0o755 });
@@ -58,8 +71,12 @@ function copyPluginDir(srcDir: string, dstDir: string, logs: string[]): void {
58
71
  for (const name of readdirSync(srcDir)) {
59
72
  const src = path.join(srcDir, name);
60
73
  const stat = statSync(src);
61
- if (!stat.isFile()) continue;
62
74
  const dst = path.join(dstDir, name);
75
+ if (stat.isDirectory()) {
76
+ copyPluginDir(src, dst, logs);
77
+ continue;
78
+ }
79
+ if (!stat.isFile()) continue;
63
80
  copyFileSync(src, dst);
64
81
  if (name.endsWith('.mjs') || name.endsWith('.js')) {
65
82
  try {
@@ -141,11 +158,22 @@ export async function connectOpenCode(config: AriaConfig): Promise<string[]> {
141
158
  copyPluginDir(srcDir, dstDir, logs);
142
159
  installedPaths.push(dstDir);
143
160
  }
161
+
162
+ const bundledHooksDir = packageOpenCodeHooksDir();
163
+ if (existsSync(bundledHooksDir)) {
164
+ copyPluginDir(bundledHooksDir, path.join(opencodeDir, 'hooks'), logs);
165
+ } else {
166
+ logs.push(`⚠ Bundled OpenCode hook helpers missing: ${bundledHooksDir} — gate plugins may fail to load`);
167
+ }
144
168
  syncDoctrineTriggerMap(logs);
145
169
 
146
- // ── Wire ~/.opencode/config.json ──────────────────────────────────────────
147
- const configPath = path.join(opencodeDir, 'config.json');
148
- if (existsSync(configPath)) {
170
+ // ── Wire OpenCode config files ────────────────────────────────────────────
171
+ const configPaths = [
172
+ path.join(opencodeDir, 'config.json'),
173
+ path.join(homedir(), '.config', 'opencode', 'config.json'),
174
+ ];
175
+ for (const configPath of configPaths) {
176
+ if (!existsSync(configPath)) continue;
149
177
  try {
150
178
  const opencodeConfig: Record<string, unknown> = JSON.parse(
151
179
  readFileSync(configPath, 'utf-8'),
@@ -191,19 +219,14 @@ export async function connectOpenCode(config: AriaConfig): Promise<string[]> {
191
219
  logs.push(`Wired ${installedPaths.length} Aria plugin(s) into OpenCode config.plugin`);
192
220
  }
193
221
 
194
- if (!opencodeConfig.agentsMdPath) {
195
- opencodeConfig.agentsMdPath = path.join(homedir(), '.aria', 'AGENTS.md');
196
- modified = true;
197
- logs.push('Set OpenCode AGENTS.md path to ~/.aria/AGENTS.md');
198
- }
199
-
200
222
  const providerMap = opencodeConfig.provider && typeof opencodeConfig.provider === 'object'
201
223
  ? opencodeConfig.provider as Record<string, unknown>
202
224
  : {};
203
225
  const currentAriaProvider = providerMap.aria && typeof providerMap.aria === 'object'
204
226
  ? providerMap.aria as Record<string, unknown>
205
227
  : {};
206
- const localToken = resolveLocalRuntimeToken();
228
+ const resolvedLocalToken = await resolveHarnessToken({ baseUrl: LOCAL_RUNTIME_V1_URL });
229
+ const localToken = resolvedLocalToken.token || resolveLocalRuntimeToken();
207
230
  const nextAriaProvider = {
208
231
  npm: '@ai-sdk/openai-compatible',
209
232
  name: 'Aria Runtime',
@@ -252,7 +275,7 @@ export async function connectOpenCode(config: AriaConfig): Promise<string[]> {
252
275
  logs.push('OpenCode already configured for Aria');
253
276
  }
254
277
  } catch {
255
- logs.push('Failed to parse OpenCode config.json');
278
+ logs.push(`Failed to parse OpenCode config.json at ${configPath}`);
256
279
  }
257
280
  }
258
281