@aria_asi/cli 0.2.33 → 0.2.35

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 (74) hide show
  1. package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
  2. package/dist/aria-connector/src/connectors/codex.js +60 -5
  3. package/dist/aria-connector/src/connectors/codex.js.map +1 -1
  4. package/dist/assets/hooks/aria-harness-via-sdk.mjs +16 -3
  5. package/dist/assets/hooks/aria-pre-tool-gate.mjs +41 -1
  6. package/dist/assets/hooks/aria-stop-gate.mjs +42 -1
  7. package/dist/assets/hooks/doctrine_trigger_map.json +43 -0
  8. package/dist/assets/hooks/lib/skill-autoload-gate.mjs +14 -1
  9. package/dist/assets/opencode-plugins/harness-context/index.js +1 -1
  10. package/dist/assets/opencode-plugins/harness-gate/index.js +49 -9
  11. package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -1
  12. package/dist/assets/opencode-plugins/harness-stop/index.js +201 -166
  13. package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -1
  14. package/dist/runtime/codex-bridge.mjs +1 -1
  15. package/dist/runtime/discipline/CLAUDE.md +2 -2
  16. package/dist/runtime/discipline/doctrine_trigger_map.json +43 -0
  17. package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +3 -3
  18. package/dist/runtime/doctrine_trigger_map.json +43 -0
  19. package/dist/runtime/hooks/aria-agent-handoff.mjs +247 -0
  20. package/dist/runtime/hooks/aria-agent-ledger-merge.mjs +164 -0
  21. package/dist/runtime/hooks/aria-architect-fallback.mjs +267 -0
  22. package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +761 -0
  23. package/dist/runtime/hooks/aria-discovery-record.mjs +101 -0
  24. package/dist/runtime/hooks/aria-harness-via-sdk.mjs +544 -0
  25. package/dist/runtime/hooks/aria-import-resolution-gate.mjs +330 -0
  26. package/dist/runtime/hooks/aria-outcome-record.mjs +84 -0
  27. package/dist/runtime/hooks/aria-pre-emit-dryrun.mjs +329 -0
  28. package/dist/runtime/hooks/aria-pre-text-gate.mjs +112 -0
  29. package/dist/runtime/hooks/aria-pre-tool-gate.mjs +2482 -0
  30. package/dist/runtime/hooks/aria-preprompt-consult.mjs +464 -0
  31. package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +647 -0
  32. package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +429 -0
  33. package/dist/runtime/hooks/aria-stop-gate.mjs +1882 -0
  34. package/dist/runtime/hooks/aria-trigger-autolearn.mjs +229 -0
  35. package/dist/runtime/hooks/aria-userprompt-abandon-detect.mjs +192 -0
  36. package/dist/runtime/hooks/doctrine_trigger_map.json +577 -0
  37. package/dist/runtime/hooks/lib/canonical-lenses.mjs +65 -0
  38. package/dist/runtime/hooks/lib/domain-output-quality.mjs +103 -0
  39. package/dist/runtime/hooks/lib/gate-audit.mjs +43 -0
  40. package/dist/runtime/hooks/lib/gate-loop-state.mjs +50 -0
  41. package/dist/runtime/hooks/lib/hook-message-window.mjs +121 -0
  42. package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +14 -0
  43. package/dist/runtime/hooks/test-aria-preturn-memory-gate.mjs +245 -0
  44. package/dist/runtime/hooks/test-tier-lens-labeling.mjs +367 -0
  45. package/dist/runtime/manifest.json +2 -2
  46. package/dist/runtime/sdk/BUNDLED.json +2 -2
  47. package/dist/runtime/sdk/index.d.ts +39 -0
  48. package/dist/runtime/sdk/index.js +117 -0
  49. package/dist/runtime/sdk/index.js.map +1 -1
  50. package/dist/runtime/sdk/runWithGovernance.d.ts +16 -0
  51. package/dist/runtime/sdk/runWithGovernance.js +54 -0
  52. package/dist/runtime/sdk/runWithGovernance.js.map +1 -0
  53. package/dist/sdk/BUNDLED.json +2 -2
  54. package/dist/sdk/index.d.ts +39 -0
  55. package/dist/sdk/index.js +117 -0
  56. package/dist/sdk/index.js.map +1 -1
  57. package/dist/sdk/runWithGovernance.d.ts +16 -0
  58. package/dist/sdk/runWithGovernance.js +54 -0
  59. package/dist/sdk/runWithGovernance.js.map +1 -0
  60. package/hooks/aria-harness-via-sdk.mjs +16 -3
  61. package/hooks/aria-pre-tool-gate.mjs +41 -1
  62. package/hooks/aria-stop-gate.mjs +42 -1
  63. package/hooks/doctrine_trigger_map.json +43 -0
  64. package/hooks/lib/skill-autoload-gate.mjs +14 -1
  65. package/opencode-plugins/harness-context/index.js +1 -1
  66. package/opencode-plugins/harness-gate/index.js +49 -9
  67. package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -1
  68. package/opencode-plugins/harness-stop/index.js +201 -166
  69. package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -1
  70. package/package.json +12 -5
  71. package/runtime-src/codex-bridge.mjs +1 -1
  72. package/scripts/bundle-sdk.mjs +2 -0
  73. package/scripts/self-test-harness-gates.mjs +79 -0
  74. package/src/connectors/codex.ts +60 -5
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
6
6
  import { createHash } from 'node:crypto';
7
+ import { spawnSync } from 'node:child_process';
7
8
  import { homedir } from 'node:os';
8
9
  import { join } from 'node:path';
9
10
  import { evaluateSkillGate, formatSkillGateBlock } from './lib/skill-autoload-gate.js';
@@ -16,6 +17,7 @@ const SDK_CANDIDATES = [
16
17
  ];
17
18
  const OWNER_TOKEN_PATH = join(HOME, '.aria', 'owner-token');
18
19
  const LICENSE_PATH = join(HOME, '.aria', 'license.json');
20
+ const GOVERNANCE_GATE_PATH = join(HOME, '.aria', 'bin', 'aria-governance-gate');
19
21
  const RUNTIME_URL = (process.env.ARIA_RUNTIME_URL || 'http://127.0.0.1:4319').replace(/\/+$/, '');
20
22
  const RECEIPT_DIR = join(HOME, '.opencode', 'aria-mizan-receipts');
21
23
 
@@ -94,6 +96,25 @@ function countInlineCognitionLenses(text) {
94
96
  return seen.size;
95
97
  }
96
98
 
99
+ function runUniversalGovernanceGate(payload) {
100
+ if (!existsSync(GOVERNANCE_GATE_PATH)) return null;
101
+ const child = spawnSync(GOVERNANCE_GATE_PATH, {
102
+ input: `${JSON.stringify(payload)}\n`,
103
+ encoding: 'utf8',
104
+ maxBuffer: 1024 * 1024,
105
+ });
106
+ const stdout = String(child.stdout || '').trim();
107
+ let result = null;
108
+ try { result = stdout ? JSON.parse(stdout) : null; } catch {}
109
+ if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
110
+ throw new Error(
111
+ `=== ARIA UNIVERSAL GOVERNANCE GATE BLOCK ===\n\n` +
112
+ `${stdout || child.stderr || 'aria-governance-gate blocked this action.'}`
113
+ );
114
+ }
115
+ return result;
116
+ }
117
+
97
118
  function resolveToken() {
98
119
  if (process.env.ARIA_HARNESS_TOKEN) return process.env.ARIA_HARNESS_TOKEN;
99
120
  if (process.env.ARIA_API_KEY) return process.env.ARIA_API_KEY;
@@ -184,28 +205,48 @@ export default async function HarnessGatePlugin(ctx) {
184
205
 
185
206
  return {
186
207
  'tool.execute.before': async (input, output) => {
187
- const toolName = input.tool;
208
+ const args = output?.args ?? input.args ?? {};
209
+ const rawToolName = String(input.tool || input.name || input.type || '');
210
+ const normalizedToolName = rawToolName.toLowerCase();
211
+ const toolName = normalizedToolName.includes('bash') ? 'Bash'
212
+ : normalizedToolName.includes('edit') ? 'Edit'
213
+ : normalizedToolName.includes('write') ? 'Write'
214
+ : rawToolName;
188
215
  if (!['Bash', 'Edit', 'Write', 'NotebookEdit'].includes(toolName)) return;
189
216
 
190
- const cmd = toolName === 'Bash' ? String(input.args?.command ?? '') : '';
191
- const filePath = toolName !== 'Bash' ? String(input.args?.file_path ?? input.args?.notebook_path ?? '') : '';
217
+ const cmd = toolName === 'Bash' ? String(args?.command ?? '') : '';
218
+ const filePath = toolName !== 'Bash' ? String(args?.file_path ?? args?.filePath ?? args?.notebook_path ?? args?.notebookPath ?? '') : '';
192
219
  const cmdPreview = toolName === 'Bash' ? cmd.slice(0, 80) : `${toolName} ${filePath || '(no path)'}`.slice(0, 80);
193
220
 
194
- // Trivial reads pass
195
- if (toolName === 'Bash' && TRIVIAL_BASH_RX.test(cmd) && cmd.length < 200) return;
196
- if (toolName === 'Bash' && cmd.length < SHORT_BASH_LIMIT) return;
197
221
  const destructive = DESTRUCTIVE_PATTERNS.find(({ rx }) => rx.test(cmd));
198
222
  const deploy = DEPLOY_PATTERNS.find(({ rx }) => rx.test(cmd));
199
223
  const isFileMutation = ['Edit', 'Write', 'NotebookEdit'].includes(toolName) && filePath;
200
224
 
225
+ // Trivial reads pass only after high-risk patterns are classified.
226
+ if (!destructive && !deploy && toolName === 'Bash' && TRIVIAL_BASH_RX.test(cmd) && cmd.length < 200) return;
227
+ if (!destructive && !deploy && toolName === 'Bash' && cmd.length < SHORT_BASH_LIMIT) return;
228
+
201
229
  if (!destructive && !deploy && !isFileMutation) return;
202
230
 
203
231
  // Try SDK checkAction() first — substrate-backed validation
204
232
  const client = await getClient();
205
- const sessionId = process.env.ARIA_SESSION_ID || 'opencode';
233
+ const sessionId = input.sessionID || process.env.ARIA_SESSION_ID || process.env.OPENCODE_SESSION_ID || 'opencode';
206
234
  const label = destructive?.name || deploy?.name || `${toolName}:${filePath?.split('/').pop() || ''}`;
207
235
  const action = toolName === 'Bash' ? 'bash' : 'edit';
208
236
  const target = toolName === 'Bash' ? cmd.slice(0, 200) : filePath.slice(0, 200);
237
+ const actionRef = makeEvidenceRef('opencode_tool_request', { toolName, action, target }, { sessionId, label });
238
+ runUniversalGovernanceGate({
239
+ sessionId,
240
+ sourceRuntime: 'opencode',
241
+ surface: 'opencode-harness-gate',
242
+ text: JSON.stringify({ toolName, action, target, args }).slice(0, 8000),
243
+ action: cmd,
244
+ toolName,
245
+ filePath,
246
+ isDeploy: Boolean(deploy),
247
+ isMutation: Boolean(isFileMutation),
248
+ evidence: actionRef,
249
+ });
209
250
  const skillGate = evaluateSkillGate({
210
251
  sessionId,
211
252
  surface: 'opencode-harness-gate',
@@ -224,7 +265,6 @@ export default async function HarnessGatePlugin(ctx) {
224
265
  `Required next step: call the skill loader for ${skillGate.missingSkills.join(', ')} before retrying this tool.`
225
266
  );
226
267
  }
227
- const actionRef = makeEvidenceRef('opencode_tool_request', { toolName, action, target }, { sessionId, label });
228
268
  const rationale =
229
269
  destructive ? `High-risk action ${label} requested in OpenCode and must satisfy Mizan truth, protection, and quality before execution.`
230
270
  : deploy ? `Deployment action ${label} requested in OpenCode and must satisfy Mizan survivability before execution.`
@@ -299,7 +339,7 @@ export default async function HarnessGatePlugin(ctx) {
299
339
  roleProfile: process.env.OPENCODE_ARIA_ROLE_PROFILE || process.env.ARIA_ROLE_PROFILE || null,
300
340
  files: filePath ? [filePath] : [],
301
341
  requireVerify: Boolean(destructive || deploy),
302
- verifyText: String(input.args?.verifyText || input.args?.verifyBlock || input.args?.verify || ''),
342
+ verifyText: String(args?.verifyText || args?.verifyBlock || args?.verify || ''),
303
343
  }).catch(() => client.checkAction(action, target));
304
344
  if (!check.allowed) {
305
345
  if (check.queued) {
@@ -1 +1,14 @@
1
- export * from '../../../../../ops/claude-hooks/lib/skill-autoload-gate.mjs';
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { tmpdir } from 'node:os';
4
+ const RECEIPT_ROOT = process.env.ARIA_SKILL_RECEIPT_DIR || join(tmpdir(), 'aria-skill-receipts');
5
+ const ALIASES = new Map([['deploy', 'aria-harness-deploy'], ['output', 'aria-harness-output-discipline'], ['repo', 'aria-repo-doctrine'], ['forge', 'aria-forge-guardrails']]);
6
+ const RX = { deploy: /deploy-service\.sh|kubectl\s+(?:apply|set|rollout|delete|scale)|helm\s+upgrade|terraform\s+apply|docker\s+push/i, mutationTool: /^(?:edit|write|notebookedit|patch|apply_patch)$/i, mutation: /apply_patch|write file|edit file|modify|delete file|migration|handler|route|runtime|hook|plugin|\btest\b|smoke script/i, strip: /remove|delete|strip|drop|omit|disable|bypass|skip|stub|mock|fake|placeholder|temporary|quick scaffold|band-aid/i, readiness: /production-ready|ready for production|works in general|general readiness|client packages?|npm packages?|SDKs?|runtimes?|harnesses?|release-ready|ship-ready/i, narrow: /single flow|one flow|narrow e2e|covered flow|specific path|widget flow/i, completion: /done|complete|completed|ready|verified|fixed|shipped|implemented|production-ready/i, badProof: /but|except|caveat|remaining|not yet|still|separate|later|blocked|skipped|unresolved|follow-up|failed|failing|error|red|not run|could not verify|untested|no proof|missing proof|without proof/i, advisory: /non-blocking|warning only|warn only|advisory|fall through|falls through|fail open|soft fail|logged and continue|quality gate warning/i, success: /(?:verified|passed|success|successful|green|ok)\s*[:=\-].{0,120}(?:npm|node|playwright|jest|vitest|build|test|lint|typecheck|curl|kubectl|self-test|e2e|probe|smoke)|(?:npm|node|playwright|jest|vitest|build|test|lint|typecheck|curl|kubectl).{0,120}(?:passed|success|successful|green|exit\s*0)/i, resubmit: /re-?submission|resubmit/i, rewrite: /re-?write|rewrite|fix/i, retest: /re-?test|retest|rerun/i, aria: /ARIA console|Aria console|\/chat|aria-pipeline-mcp|aria_chat|escalat(?:e|ion).{0,80}ARIA/i };
7
+ function normalizeSkillName(skill) { return ALIASES.get(String(skill || '').trim()) || String(skill || '').trim(); }
8
+ function sessionDir(sessionId) { return join(RECEIPT_ROOT, encodeURIComponent(String(sessionId || 'unknown'))); }
9
+ function readReceiptSkills(sessionId) { const dir = sessionDir(sessionId); if (!existsSync(dir)) return new Set(); const skills = new Set(); for (const name of readdirSync(dir)) { if (!name.endsWith('.json')) continue; try { const receipt = JSON.parse(readFileSync(join(dir, name), 'utf8')); if (receipt?.skill) skills.add(normalizeSkillName(receipt.skill)); } catch {} } return skills; }
10
+ function readInlineSkills(text) { const skills = new Set(); const value = String(text || ''); for (const match of value.matchAll(/<skill_content\s+name=["']([^"']+)["']/gi)) skills.add(normalizeSkillName(match[1])); return skills; }
11
+ export function recordSkillLoaded({ sessionId, skill, surface = 'unknown', metadata = {} } = {}) { const normalized = normalizeSkillName(skill); if (!normalized) throw new Error('recordSkillLoaded requires a skill name'); const dir = sessionDir(sessionId); mkdirSync(dir, { recursive: true }); const receipt = { skill: normalized, surface, metadata, recordedAt: new Date().toISOString() }; writeFileSync(join(dir, `${encodeURIComponent(normalized)}.json`), `${JSON.stringify(receipt, null, 2)}\n`); return receipt; }
12
+ export function classifyRequiredSkills({ text = '', action = '', toolName = '', filePath = '', isDeploy = false, isMutation = false, isOutputCloseout = false } = {}) { const combined = [text, action, toolName, filePath].filter(Boolean).join('\n'); const required = new Set(); const reasons = []; const recoveryMissing = []; if (isDeploy || RX.deploy.test(combined)) { required.add('aria-harness-deploy'); required.add('aria-forge-guardrails'); reasons.push('deploy/shared-infrastructure action requires fail-closed deploy and forge guardrails'); } if (isMutation || RX.mutationTool.test(toolName)) { required.add('aria-repo-doctrine'); reasons.push('repository/runtime mutation requires repo doctrine'); } if (RX.strip.test(combined)) { required.add('aria-harness-no-stripping'); reasons.push('strip/remove/bypass language requires no-stripping gate'); } if (isOutputCloseout && RX.completion.test(combined)) { required.add('aria-harness-output-discipline'); reasons.push('owner-facing completion/readiness claim requires output discipline'); if (!RX.success.test(combined)) recoveryMissing.push('successful proof from a concrete command/probe'); } if (RX.readiness.test(combined)) { required.add('architecture-decision'); required.add('testing-strategy'); required.add('aria-forge-guardrails'); required.add('aria-harness-output-discipline'); reasons.push('broad production/package/SDK/runtime readiness claim requires architecture, testing, and forge guardrails'); } if (RX.readiness.test(combined) && RX.narrow.test(combined)) { required.add('testing-strategy'); required.add('aria-forge-guardrails'); reasons.push('narrow e2e proof cannot support broad readiness claim without readiness-matrix discipline'); } if (RX.completion.test(combined) && RX.badProof.test(combined)) { required.add('aria-harness-output-discipline'); required.add('aria-forge-guardrails'); reasons.push('completion claim with unresolved or failed proof requires recovery cycle'); if (!RX.resubmit.test(combined)) recoveryMissing.push('re-submission'); if (!RX.rewrite.test(combined)) recoveryMissing.push('re-write'); if (!RX.retest.test(combined)) recoveryMissing.push('re-test'); if (!RX.aria.test(combined)) recoveryMissing.push('ARIA console escalation'); } if (RX.advisory.test(combined)) { required.add('aria-forge-guardrails'); required.add('aria-harness-output-discipline'); reasons.push('advisory/fail-open gate language requires fail-closed hardening discipline'); } return { requiredSkills: [...required].sort(), reasons, recoveryMissing }; }
13
+ export function evaluateSkillGate(options = {}) { const classified = classifyRequiredSkills(options); const text = [options.text, options.action].filter(Boolean).join('\n'); const loaded = new Set([...readReceiptSkills(options.sessionId), ...readInlineSkills(text)]); const missingSkills = classified.requiredSkills.filter((skill) => !loaded.has(skill)); const recoveryMissing = classified.recoveryMissing || []; return { ok: missingSkills.length === 0 && recoveryMissing.length === 0, surface: options.surface || 'unknown', sessionId: options.sessionId || 'unknown', requiredSkills: classified.requiredSkills, loadedSkills: [...loaded].sort(), missingSkills, recoveryMissing, reasons: classified.reasons, autoLoadAvailable: options.autoLoadAvailable === true }; }
14
+ export function formatSkillGateBlock(result = {}) { const missing = Array.isArray(result.missingSkills) ? result.missingSkills : []; const recovery = Array.isArray(result.recoveryMissing) ? result.recoveryMissing : []; const reasons = Array.isArray(result.reasons) ? result.reasons : []; return ['=== ARIA SKILL AUTOLOAD GATE BLOCK ===', `surface: ${result.surface || 'unknown'}`, `missing_skills: ${missing.length ? missing.join(', ') : '(none)'}`, `missing_recovery_cycle: ${recovery.length ? recovery.join(', ') : '(none)'}`, `required_skills: ${(result.requiredSkills || []).join(', ') || '(none)'}`, reasons.length ? `reasons: ${reasons.join(' | ')}` : 'reasons: no classifier reason recorded', 'counter_action: re-submit, re-write, re-test, and escalate through ARIA console until successful proof exists. Do not downgrade this to an advisory warning.'].join('\n'); }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
6
6
  import { createHash } from 'node:crypto';
7
+ import { spawnSync } from 'node:child_process';
7
8
  import { homedir } from 'node:os';
8
9
  import { join } from 'node:path';
9
10
  import { analyzeDomainOutputQuality, extractCodeBlocks } from './lib/domain-output-quality.js';
@@ -17,6 +18,7 @@ const SDK_CANDIDATES = [
17
18
  ];
18
19
  const OWNER_TOKEN_PATH = join(HOME, '.aria', 'owner-token');
19
20
  const LICENSE_PATH = join(HOME, '.aria', 'license.json');
21
+ const GOVERNANCE_GATE_PATH = join(HOME, '.aria', 'bin', 'aria-governance-gate');
20
22
  const RUNTIME_URL = (process.env.ARIA_RUNTIME_URL || 'http://127.0.0.1:4319').replace(/\/+$/, '');
21
23
  const RECEIPT_DIR = join(HOME, '.opencode', 'aria-mizan-receipts');
22
24
 
@@ -49,6 +51,25 @@ function isGateBlock(error) {
49
51
  return BLOCK_PREFIX_RX.test(String(error?.message || error || ''));
50
52
  }
51
53
 
54
+ function runUniversalGovernanceGate(payload) {
55
+ if (!existsSync(GOVERNANCE_GATE_PATH)) return null;
56
+ const child = spawnSync(GOVERNANCE_GATE_PATH, {
57
+ input: `${JSON.stringify(payload)}\n`,
58
+ encoding: 'utf8',
59
+ maxBuffer: 1024 * 1024,
60
+ });
61
+ const stdout = String(child.stdout || '').trim();
62
+ let result = null;
63
+ try { result = stdout ? JSON.parse(stdout) : null; } catch {}
64
+ if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
65
+ throw new Error(
66
+ `=== ARIA UNIVERSAL GOVERNANCE GATE BLOCK ===\n\n` +
67
+ `${stdout || child.stderr || 'aria-governance-gate blocked this output.'}`
68
+ );
69
+ }
70
+ return result;
71
+ }
72
+
52
73
  let _client = null;
53
74
  let _clientError = null;
54
75
  let _lastMizanReceipt = null;
@@ -233,192 +254,206 @@ function detectCognitionLenses(text) {
233
254
  export default async function HarnessStopPlugin(ctx) {
234
255
  process.stderr.write('[harness-stop] Active — SDK-backed text-emission gate\n');
235
256
 
236
- return {
237
- 'session.idle': async (event) => {
238
- process.stderr.write(' [strip gate registed — session i\n');
239
- },
240
-
241
- event: async ({ event }) => {
242
- if (event.type !== 'message.updated') return;
243
- const parts = event.properties?.parts || [];
244
- const text = parts
245
- .filter(p => p.type === 'text')
246
- .map(p => p.text || '')
247
- .join('\n');
257
+ async function validateText(text, eventContext = {}) {
258
+ if (!text || text.length < NON_TRIVIAL_MIN_CHARS) return;
259
+ if (TRIVIAL_ACK_RX.test(text.trim())) return;
248
260
 
249
- if (!text || text.length < NON_TRIVIAL_MIN_CHARS) return;
250
- if (TRIVIAL_ACK_RX.test(text.trim())) return;
251
-
252
- const cog = detectCognitionLenses(text);
253
- const sessionId = process.env.ARIA_SESSION_ID || 'opencode';
254
- const skillGate = evaluateSkillGate({
255
- sessionId,
256
- surface: 'opencode-harness-stop',
257
- text: JSON.stringify(event || {}) + '\n' + text,
258
- isOutputCloseout: true,
259
- autoLoadAvailable: false,
261
+ const cog = detectCognitionLenses(text);
262
+ const sessionId = eventContext.sessionID || process.env.ARIA_SESSION_ID || process.env.OPENCODE_SESSION_ID || 'opencode';
263
+ runUniversalGovernanceGate({
264
+ sessionId,
265
+ sourceRuntime: 'opencode',
266
+ surface: 'opencode-harness-stop',
267
+ text,
268
+ isOutputCloseout: true,
269
+ evidence: makeEvidenceRef('opencode_assistant_output_candidate', text.slice(0, 8000), { sessionId }),
270
+ });
271
+ const skillGate = evaluateSkillGate({
272
+ sessionId,
273
+ surface: 'opencode-harness-stop',
274
+ text: JSON.stringify(eventContext || {}) + '\n' + text,
275
+ isOutputCloseout: true,
276
+ autoLoadAvailable: false,
277
+ });
278
+ if (!skillGate.ok) {
279
+ throw new Error(
280
+ formatBlockReason(
281
+ '=== ARIA SKILL AUTOLOAD GATE BLOCK ===',
282
+ `${formatSkillGateBlock(skillGate)}\nRequired next step: load ${skillGate.missingSkills.join(', ')} before re-emitting this output.`,
283
+ )
284
+ );
285
+ }
286
+ const outputRef = makeEvidenceRef('opencode_assistant_output', text.slice(0, 8000), { sessionId });
287
+ try {
288
+ const mizan = await runtimeMizanPost(text.slice(0, 8000), sessionId, {
289
+ message: text.slice(0, 1000),
290
+ plannedApproach: 'OpenCode stop gate output review',
291
+ outputRef,
292
+ }, {
293
+ output_ref: outputRef,
294
+ cognition_lens_count: cog.count,
260
295
  });
261
- if (!skillGate.ok) {
296
+ _lastMizanReceipt = mizan.receipt || _lastMizanReceipt;
297
+ if (_lastMizanReceipt) {
298
+ const existing = loadReceiptState(sessionId) || {};
299
+ persistReceiptState(sessionId, {
300
+ ...existing,
301
+ updatedAt: new Date().toISOString(),
302
+ sessionId,
303
+ postReceipt: _lastMizanReceipt,
304
+ postResult: mizan.result || null,
305
+ postContract: mizan.contract || null,
306
+ postSummary: mizan.summary || null,
307
+ outputRef,
308
+ });
309
+ }
310
+ if (mizan.receipt?.blocked || mizan.result?.fitrahVetoed || mizan.result?.reAuthorSignal) {
311
+ const details = (mizan.result?.notes || ['post-phase blocked']).slice(0, 4).join(' | ');
262
312
  throw new Error(
263
- formatBlockReason(
264
- '=== ARIA SKILL AUTOLOAD GATE BLOCK ===',
265
- `${formatSkillGateBlock(skillGate)}\nRequired next step: load ${skillGate.missingSkills.join(', ')} before re-emitting this output.`,
266
- )
313
+ formatBlockReason('=== ARIA MIZAN POST BLOCK ===', details)
267
314
  );
268
315
  }
269
- const outputRef = makeEvidenceRef('opencode_assistant_output', text.slice(0, 8000), { sessionId });
316
+ } catch (e) {
317
+ if (isGateBlock(e)) throw e;
318
+ process.stderr.write(`[harness-stop] mizan/post unavailable: ${e.message}\n`);
319
+ }
320
+
321
+ const client = await getClient();
322
+ if (client) {
270
323
  try {
271
- const mizan = await runtimeMizanPost(text.slice(0, 8000), sessionId, {
272
- message: text.slice(0, 1000),
273
- plannedApproach: 'OpenCode stop gate output review',
274
- outputRef,
275
- }, {
276
- output_ref: outputRef,
277
- cognition_lens_count: cog.count,
278
- });
279
- _lastMizanReceipt = mizan.receipt || _lastMizanReceipt;
280
- if (_lastMizanReceipt) {
281
- const existing = loadReceiptState(sessionId) || {};
282
- persistReceiptState(sessionId, {
283
- ...existing,
284
- updatedAt: new Date().toISOString(),
285
- sessionId,
286
- postReceipt: _lastMizanReceipt,
287
- postResult: mizan.result || null,
288
- postContract: mizan.contract || null,
289
- postSummary: mizan.summary || null,
290
- outputRef,
291
- });
292
- }
293
- if (mizan.receipt?.blocked || mizan.result?.fitrahVetoed || mizan.result?.reAuthorSignal) {
294
- const details = (mizan.result?.notes || ['post-phase blocked']).slice(0, 4).join(' | ');
324
+ const result = await runtimeValidateOutput(
325
+ text.slice(0, 8000),
326
+ sessionId,
327
+ ).catch(() => client.validateOutput(
328
+ text.slice(0, 8000),
329
+ sessionId,
330
+ ));
331
+ if (result.severity === 'block') {
295
332
  throw new Error(
296
- formatBlockReason('=== ARIA MIZAN POST BLOCK ===', details)
333
+ formatBlockReason(
334
+ '=== ARIA OUTPUT GATE BLOCK ===',
335
+ `${result.violations.length} violations: ${result.violations.join('; ').slice(0, 500)}`,
336
+ )
337
+ );
338
+ } else if (result.severity === 'warn') {
339
+ throw new Error(
340
+ formatBlockReason(
341
+ '=== ARIA OUTPUT GATE BLOCK ===',
342
+ `SDK returned warn for ${result.violations.length} violation(s): ${(result.violations || []).join('; ').slice(0, 500)}. Warnings are fail-closed on owner-facing output.`,
343
+ )
297
344
  );
298
345
  }
346
+ if (result.gateTriggers?.length) {
347
+ process.stderr.write(`[harness-stop] SDK triggers: ${result.gateTriggers.join(', ')}\n`);
348
+ }
349
+ return;
299
350
  } catch (e) {
300
351
  if (isGateBlock(e)) throw e;
301
- process.stderr.write(`[harness-stop] mizan/post unavailable: ${e.message}\n`);
352
+ process.stderr.write(`[harness-stop] SDK validateOutput failed: ${e.message} — falling through to local gate\n`);
302
353
  }
354
+ }
303
355
 
304
- // Try SDK validateOutput() — Mizan classifier-backed validation
305
- const client = await getClient();
306
- if (client) {
307
- try {
308
- const result = await runtimeValidateOutput(
309
- text.slice(0, 8000),
310
- sessionId,
311
- ).catch(() => client.validateOutput(
312
- text.slice(0, 8000),
313
- sessionId,
314
- ));
315
- if (result.severity === 'block') {
316
- throw new Error(
317
- formatBlockReason(
318
- '=== ARIA OUTPUT GATE BLOCK ===',
319
- `${result.violations.length} violations: ${result.violations.join('; ').slice(0, 500)}`,
320
- )
321
- );
322
- } else if (result.severity === 'warn') {
323
- process.stderr.write(
324
- `[harness-stop] SDK WARN — ${result.violations.length} violations (non-blocking)\n`
325
- );
326
- }
327
- // Log gate triggers
328
- if (result.gateTriggers?.length) {
329
- process.stderr.write(`[harness-stop] SDK triggers: ${result.gateTriggers.join(', ')}\n`);
330
- }
331
- return;
332
- } catch (e) {
333
- if (isGateBlock(e)) throw e;
334
- process.stderr.write(`[harness-stop] SDK validateOutput failed: ${e.message} — falling through to local gate\n`);
356
+ const triggerMapPaths = [
357
+ `${HOME}/.aria/runtime/discipline/doctrine_trigger_map.json`,
358
+ `${HOME}/.aria/runtime/doctrine_trigger_map.json`,
359
+ `${HOME}/.opencode/doctrine_trigger_map.json`,
360
+ `${HOME}/.codex/doctrine_trigger_map.json`,
361
+ `${HOME}/.claude/hooks/doctrine_trigger_map.json`,
362
+ `${HOME}/.claude/projects/-home-hamzaibrahim1/memory/doctrine_trigger_map.json`,
363
+ ];
364
+ let driftHits = [];
365
+ try {
366
+ const triggerMapPath = triggerMapPaths.find((candidate) => existsSync(candidate));
367
+ if (triggerMapPath) {
368
+ const triggerMap = JSON.parse(readFileSync(triggerMapPath, 'utf8'));
369
+ const lower = text.toLowerCase();
370
+ for (const t of triggerMap.triggers || []) {
371
+ try {
372
+ const rx = new RegExp(t.trigger, 'i');
373
+ if (rx.test(lower)) {
374
+ const memCited = t.memory && lower.includes(t.memory.replace(/\.md$/, '').toLowerCase());
375
+ if (!memCited) driftHits.push(t.trigger);
376
+ }
377
+ } catch {}
335
378
  }
336
379
  }
380
+ } catch {}
337
381
 
338
- // Local fallback gate
339
- // Scan drift triggers
340
- const triggerMapPaths = [
341
- `${HOME}/.aria/runtime/discipline/doctrine_trigger_map.json`,
342
- `${HOME}/.aria/runtime/doctrine_trigger_map.json`,
343
- `${HOME}/.opencode/doctrine_trigger_map.json`,
344
- `${HOME}/.codex/doctrine_trigger_map.json`,
345
- `${HOME}/.claude/hooks/doctrine_trigger_map.json`,
346
- `${HOME}/.claude/projects/-home-hamzaibrahim1/memory/doctrine_trigger_map.json`,
347
- ];
348
- let driftHits = [];
349
- try {
350
- const triggerMapPath = triggerMapPaths.find((candidate) => existsSync(candidate));
351
- if (triggerMapPath) {
352
- const triggerMap = JSON.parse(readFileSync(triggerMapPath, 'utf8'));
353
- const lower = text.toLowerCase();
354
- for (const t of triggerMap.triggers || []) {
355
- try {
356
- const rx = new RegExp(t.trigger, 'i');
357
- if (rx.test(lower)) {
358
- const memCited = t.memory && lower.includes(t.memory.replace(/\.md$/, '').toLowerCase());
359
- if (!memCited) driftHits.push(t.trigger);
360
- }
361
- } catch {}
362
- }
363
- }
364
- } catch {}
382
+ if (cog.count < REQUIRED_LENSES || driftHits.length >= 2) {
383
+ throw new Error(
384
+ formatBlockReason(
385
+ '=== ARIA LOCAL OUTPUT BLOCK ===',
386
+ `cognition=${cog.count}/${REQUIRED_LENSES}; drift=${driftHits.length}`,
387
+ )
388
+ );
389
+ }
365
390
 
366
- if (cog.count < REQUIRED_LENSES || driftHits.length >= 2) {
367
- throw new Error(
368
- formatBlockReason(
369
- '=== ARIA LOCAL OUTPUT BLOCK ===',
370
- `cognition=${cog.count}/${REQUIRED_LENSES}; drift=${driftHits.length}`,
371
- )
372
- );
373
- }
391
+ if (DECISION_SIGNAL_RX.test(text) && !APPLIED_COGNITION_RX.test(text)) {
392
+ throw new Error(
393
+ formatBlockReason(
394
+ '=== ARIA LOCAL OUTPUT BLOCK ===',
395
+ 'decision-bearing output lacks required applied_cognition binding fields',
396
+ )
397
+ );
398
+ }
374
399
 
375
- if (DECISION_SIGNAL_RX.test(text) && !APPLIED_COGNITION_RX.test(text)) {
376
- throw new Error(
377
- formatBlockReason(
378
- '=== ARIA LOCAL OUTPUT BLOCK ===',
379
- 'decision-bearing output lacks required applied_cognition binding fields',
380
- )
381
- );
382
- }
400
+ const domainQuality = analyzeDomainOutputQuality(text, { codeBlocks: extractCodeBlocks(text) });
401
+ if (domainQuality.blockers.length > 0) {
402
+ throw new Error(
403
+ formatBlockReason(
404
+ '=== ARIA LOCAL OUTPUT BLOCK ===',
405
+ `domain output QA (${domainQuality.domains.join(', ') || 'general'}): ${domainQuality.blockers.join('; ')}`,
406
+ )
407
+ );
408
+ }
383
409
 
384
- const domainQuality = analyzeDomainOutputQuality(text, { codeBlocks: extractCodeBlocks(text) });
385
- if (domainQuality.blockers.length > 0) {
386
- throw new Error(
387
- formatBlockReason(
388
- '=== ARIA LOCAL OUTPUT BLOCK ===',
389
- `domain output QA (${domainQuality.domains.join(', ') || 'general'}): ${domainQuality.blockers.join('; ')}`,
390
- )
391
- );
392
- }
410
+ try {
411
+ const existing = loadReceiptState(sessionId);
412
+ await runtimeDecisionLog({
413
+ decision_type: 'turn_action',
414
+ category: 'agentic_execution',
415
+ context: `opencode stop-gate turn (chars=${text.length})`,
416
+ decision: 'turn completed',
417
+ reasoning: cog.count > 0
418
+ ? `Cognition lenses applied: ${cog.names.join(', ')}.`
419
+ : 'No explicit cognition block in turn.',
420
+ outcome: 'pending',
421
+ outcome_details: {
422
+ expected: null,
423
+ immediate_actual: null,
424
+ anchors: [],
425
+ },
426
+ expected_outcome: null,
427
+ metadata: {
428
+ pre_receipt_id: existing?.receipt?.receiptId || null,
429
+ post_receipt_id: _lastMizanReceipt?.receiptId || null,
430
+ output_ref: outputRef,
431
+ },
432
+ source: 'opencode-stop-gate-runtime',
433
+ model_used: process.env.OPENCODE_MODEL || 'opencode',
434
+ });
435
+ } catch (e) {
436
+ process.stderr.write(`[harness-stop] decision/log unavailable: ${e.message}\n`);
437
+ }
438
+ }
393
439
 
394
- try {
395
- const existing = loadReceiptState(sessionId);
396
- await runtimeDecisionLog({
397
- decision_type: 'turn_action',
398
- category: 'agentic_execution',
399
- context: `opencode stop-gate turn (chars=${text.length})`,
400
- decision: 'turn completed',
401
- reasoning: cog.count > 0
402
- ? `Cognition lenses applied: ${cog.names.join(', ')}.`
403
- : 'No explicit cognition block in turn.',
404
- outcome: 'pending',
405
- outcome_details: {
406
- expected: null,
407
- immediate_actual: null,
408
- anchors: [],
409
- },
410
- expected_outcome: null,
411
- metadata: {
412
- pre_receipt_id: existing?.receipt?.receiptId || null,
413
- post_receipt_id: _lastMizanReceipt?.receiptId || null,
414
- output_ref: outputRef,
415
- },
416
- source: 'opencode-stop-gate-runtime',
417
- model_used: process.env.OPENCODE_MODEL || 'opencode',
418
- });
419
- } catch (e) {
420
- process.stderr.write(`[harness-stop] decision/log unavailable: ${e.message}\n`);
421
- }
440
+ return {
441
+ 'session.idle': async (event) => {
442
+ process.stderr.write('[harness-stop] session idle heartbeat — text-emission gate registered\n');
443
+ },
444
+
445
+ event: async ({ event }) => {
446
+ if (event.type !== 'message.updated') return;
447
+ const parts = event.properties?.parts || [];
448
+ const text = parts
449
+ .filter(p => p.type === 'text')
450
+ .map(p => p.text || '')
451
+ .join('\n');
452
+ await validateText(text, { event });
453
+ },
454
+
455
+ 'experimental.text.complete': async (input, output) => {
456
+ await validateText(String(output?.text || ''), input || {});
422
457
  },
423
458
  };
424
459
  }
@@ -1 +1,14 @@
1
- export * from '../../../../../ops/claude-hooks/lib/skill-autoload-gate.mjs';
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { tmpdir } from 'node:os';
4
+ const RECEIPT_ROOT = process.env.ARIA_SKILL_RECEIPT_DIR || join(tmpdir(), 'aria-skill-receipts');
5
+ const ALIASES = new Map([['deploy', 'aria-harness-deploy'], ['output', 'aria-harness-output-discipline'], ['repo', 'aria-repo-doctrine'], ['forge', 'aria-forge-guardrails']]);
6
+ const RX = { deploy: /deploy-service\.sh|kubectl\s+(?:apply|set|rollout|delete|scale)|helm\s+upgrade|terraform\s+apply|docker\s+push/i, mutationTool: /^(?:edit|write|notebookedit|patch|apply_patch)$/i, mutation: /apply_patch|write file|edit file|modify|delete file|migration|handler|route|runtime|hook|plugin|\btest\b|smoke script/i, strip: /remove|delete|strip|drop|omit|disable|bypass|skip|stub|mock|fake|placeholder|temporary|quick scaffold|band-aid/i, readiness: /production-ready|ready for production|works in general|general readiness|client packages?|npm packages?|SDKs?|runtimes?|harnesses?|release-ready|ship-ready/i, narrow: /single flow|one flow|narrow e2e|covered flow|specific path|widget flow/i, completion: /done|complete|completed|ready|verified|fixed|shipped|implemented|production-ready/i, badProof: /but|except|caveat|remaining|not yet|still|separate|later|blocked|skipped|unresolved|follow-up|failed|failing|error|red|not run|could not verify|untested|no proof|missing proof|without proof/i, advisory: /non-blocking|warning only|warn only|advisory|fall through|falls through|fail open|soft fail|logged and continue|quality gate warning/i, success: /(?:verified|passed|success|successful|green|ok)\s*[:=\-].{0,120}(?:npm|node|playwright|jest|vitest|build|test|lint|typecheck|curl|kubectl|self-test|e2e|probe|smoke)|(?:npm|node|playwright|jest|vitest|build|test|lint|typecheck|curl|kubectl).{0,120}(?:passed|success|successful|green|exit\s*0)/i, resubmit: /re-?submission|resubmit/i, rewrite: /re-?write|rewrite|fix/i, retest: /re-?test|retest|rerun/i, aria: /ARIA console|Aria console|\/chat|aria-pipeline-mcp|aria_chat|escalat(?:e|ion).{0,80}ARIA/i };
7
+ function normalizeSkillName(skill) { return ALIASES.get(String(skill || '').trim()) || String(skill || '').trim(); }
8
+ function sessionDir(sessionId) { return join(RECEIPT_ROOT, encodeURIComponent(String(sessionId || 'unknown'))); }
9
+ function readReceiptSkills(sessionId) { const dir = sessionDir(sessionId); if (!existsSync(dir)) return new Set(); const skills = new Set(); for (const name of readdirSync(dir)) { if (!name.endsWith('.json')) continue; try { const receipt = JSON.parse(readFileSync(join(dir, name), 'utf8')); if (receipt?.skill) skills.add(normalizeSkillName(receipt.skill)); } catch {} } return skills; }
10
+ function readInlineSkills(text) { const skills = new Set(); const value = String(text || ''); for (const match of value.matchAll(/<skill_content\s+name=["']([^"']+)["']/gi)) skills.add(normalizeSkillName(match[1])); return skills; }
11
+ export function recordSkillLoaded({ sessionId, skill, surface = 'unknown', metadata = {} } = {}) { const normalized = normalizeSkillName(skill); if (!normalized) throw new Error('recordSkillLoaded requires a skill name'); const dir = sessionDir(sessionId); mkdirSync(dir, { recursive: true }); const receipt = { skill: normalized, surface, metadata, recordedAt: new Date().toISOString() }; writeFileSync(join(dir, `${encodeURIComponent(normalized)}.json`), `${JSON.stringify(receipt, null, 2)}\n`); return receipt; }
12
+ export function classifyRequiredSkills({ text = '', action = '', toolName = '', filePath = '', isDeploy = false, isMutation = false, isOutputCloseout = false } = {}) { const combined = [text, action, toolName, filePath].filter(Boolean).join('\n'); const required = new Set(); const reasons = []; const recoveryMissing = []; if (isDeploy || RX.deploy.test(combined)) { required.add('aria-harness-deploy'); required.add('aria-forge-guardrails'); reasons.push('deploy/shared-infrastructure action requires fail-closed deploy and forge guardrails'); } if (isMutation || RX.mutationTool.test(toolName)) { required.add('aria-repo-doctrine'); reasons.push('repository/runtime mutation requires repo doctrine'); } if (RX.strip.test(combined)) { required.add('aria-harness-no-stripping'); reasons.push('strip/remove/bypass language requires no-stripping gate'); } if (isOutputCloseout && RX.completion.test(combined)) { required.add('aria-harness-output-discipline'); reasons.push('owner-facing completion/readiness claim requires output discipline'); if (!RX.success.test(combined)) recoveryMissing.push('successful proof from a concrete command/probe'); } if (RX.readiness.test(combined)) { required.add('architecture-decision'); required.add('testing-strategy'); required.add('aria-forge-guardrails'); required.add('aria-harness-output-discipline'); reasons.push('broad production/package/SDK/runtime readiness claim requires architecture, testing, and forge guardrails'); } if (RX.readiness.test(combined) && RX.narrow.test(combined)) { required.add('testing-strategy'); required.add('aria-forge-guardrails'); reasons.push('narrow e2e proof cannot support broad readiness claim without readiness-matrix discipline'); } if (RX.completion.test(combined) && RX.badProof.test(combined)) { required.add('aria-harness-output-discipline'); required.add('aria-forge-guardrails'); reasons.push('completion claim with unresolved or failed proof requires recovery cycle'); if (!RX.resubmit.test(combined)) recoveryMissing.push('re-submission'); if (!RX.rewrite.test(combined)) recoveryMissing.push('re-write'); if (!RX.retest.test(combined)) recoveryMissing.push('re-test'); if (!RX.aria.test(combined)) recoveryMissing.push('ARIA console escalation'); } if (RX.advisory.test(combined)) { required.add('aria-forge-guardrails'); required.add('aria-harness-output-discipline'); reasons.push('advisory/fail-open gate language requires fail-closed hardening discipline'); } return { requiredSkills: [...required].sort(), reasons, recoveryMissing }; }
13
+ export function evaluateSkillGate(options = {}) { const classified = classifyRequiredSkills(options); const text = [options.text, options.action].filter(Boolean).join('\n'); const loaded = new Set([...readReceiptSkills(options.sessionId), ...readInlineSkills(text)]); const missingSkills = classified.requiredSkills.filter((skill) => !loaded.has(skill)); const recoveryMissing = classified.recoveryMissing || []; return { ok: missingSkills.length === 0 && recoveryMissing.length === 0, surface: options.surface || 'unknown', sessionId: options.sessionId || 'unknown', requiredSkills: classified.requiredSkills, loadedSkills: [...loaded].sort(), missingSkills, recoveryMissing, reasons: classified.reasons, autoLoadAvailable: options.autoLoadAvailable === true }; }
14
+ export function formatSkillGateBlock(result = {}) { const missing = Array.isArray(result.missingSkills) ? result.missingSkills : []; const recovery = Array.isArray(result.recoveryMissing) ? result.recoveryMissing : []; const reasons = Array.isArray(result.reasons) ? result.reasons : []; return ['=== ARIA SKILL AUTOLOAD GATE BLOCK ===', `surface: ${result.surface || 'unknown'}`, `missing_skills: ${missing.length ? missing.join(', ') : '(none)'}`, `missing_recovery_cycle: ${recovery.length ? recovery.join(', ') : '(none)'}`, `required_skills: ${(result.requiredSkills || []).join(', ') || '(none)'}`, reasons.length ? `reasons: ${reasons.join(' | ')}` : 'reasons: no classifier reason recorded', 'counter_action: re-submit, re-write, re-test, and escalate through ARIA console until successful proof exists. Do not downgrade this to an advisory warning.'].join('\n'); }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@aria_asi/cli",
3
- "version": "0.2.33",
4
- "description": "Aria Smart CLI \u2014 the world's first harness-powered terminal companion",
3
+ "version": "0.2.35",
4
+ "description": "Aria Smart CLI the world's first harness-powered terminal companion",
5
5
  "bin": {
6
- "aria": "./bin/aria.js"
6
+ "aria": "bin/aria.js"
7
7
  },
8
8
  "main": "./dist/aria-connector/src/index.js",
9
9
  "types": "./dist/aria-connector/src/index.d.ts",
@@ -18,7 +18,8 @@
18
18
  },
19
19
  "scripts": {
20
20
  "build": "tsc && node scripts/bundle-sdk.mjs",
21
- "check:hooks": "node scripts/validate-hook-contracts.mjs",
21
+ "check:hooks": "node scripts/validate-hook-contracts.mjs && node scripts/self-test-harness-gates.mjs",
22
+ "self-test:gates": "node scripts/self-test-harness-gates.mjs",
22
23
  "check:skills": "node scripts/validate-skill-prompts.mjs",
23
24
  "prepare": "npm run build",
24
25
  "dev": "tsc --watch",
@@ -50,5 +51,11 @@
50
51
  "node": ">=20.0.0"
51
52
  },
52
53
  "license": "UNLICENSED",
53
- "private": false
54
+ "private": false,
55
+ "keywords": [],
56
+ "author": "",
57
+ "bugs": {
58
+ "url": "https://github.com/REI-Nationwide/cowork-sandbox/issues"
59
+ },
60
+ "homepage": "https://github.com/REI-Nationwide/cowork-sandbox#readme"
54
61
  }
@@ -6,7 +6,7 @@ import { homedir } from 'node:os';
6
6
  import { delimiter, dirname, resolve } from 'node:path';
7
7
  import { spawn, spawnSync } from 'node:child_process';
8
8
  import { createRequire } from 'node:module';
9
- import { evaluateSkillGate, formatSkillGateBlock } from '../../../ops/claude-hooks/lib/skill-autoload-gate.mjs';
9
+ import { evaluateSkillGate, formatSkillGateBlock } from './hooks/lib/skill-autoload-gate.mjs';
10
10
 
11
11
  const require = createRequire(import.meta.url);
12
12
  const { WebSocketServer, WebSocket } = require('ws');