@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.
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +60 -5
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +16 -3
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +41 -1
- package/dist/assets/hooks/aria-stop-gate.mjs +42 -1
- package/dist/assets/hooks/doctrine_trigger_map.json +43 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +14 -1
- package/dist/assets/opencode-plugins/harness-context/index.js +1 -1
- package/dist/assets/opencode-plugins/harness-gate/index.js +49 -9
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -1
- package/dist/assets/opencode-plugins/harness-stop/index.js +201 -166
- package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -1
- package/dist/runtime/codex-bridge.mjs +1 -1
- package/dist/runtime/discipline/CLAUDE.md +2 -2
- package/dist/runtime/discipline/doctrine_trigger_map.json +43 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +3 -3
- package/dist/runtime/doctrine_trigger_map.json +43 -0
- package/dist/runtime/hooks/aria-agent-handoff.mjs +247 -0
- package/dist/runtime/hooks/aria-agent-ledger-merge.mjs +164 -0
- package/dist/runtime/hooks/aria-architect-fallback.mjs +267 -0
- package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +761 -0
- package/dist/runtime/hooks/aria-discovery-record.mjs +101 -0
- package/dist/runtime/hooks/aria-harness-via-sdk.mjs +544 -0
- package/dist/runtime/hooks/aria-import-resolution-gate.mjs +330 -0
- package/dist/runtime/hooks/aria-outcome-record.mjs +84 -0
- package/dist/runtime/hooks/aria-pre-emit-dryrun.mjs +329 -0
- package/dist/runtime/hooks/aria-pre-text-gate.mjs +112 -0
- package/dist/runtime/hooks/aria-pre-tool-gate.mjs +2482 -0
- package/dist/runtime/hooks/aria-preprompt-consult.mjs +464 -0
- package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +647 -0
- package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +429 -0
- package/dist/runtime/hooks/aria-stop-gate.mjs +1882 -0
- package/dist/runtime/hooks/aria-trigger-autolearn.mjs +229 -0
- package/dist/runtime/hooks/aria-userprompt-abandon-detect.mjs +192 -0
- package/dist/runtime/hooks/doctrine_trigger_map.json +577 -0
- package/dist/runtime/hooks/lib/canonical-lenses.mjs +65 -0
- package/dist/runtime/hooks/lib/domain-output-quality.mjs +103 -0
- package/dist/runtime/hooks/lib/gate-audit.mjs +43 -0
- package/dist/runtime/hooks/lib/gate-loop-state.mjs +50 -0
- package/dist/runtime/hooks/lib/hook-message-window.mjs +121 -0
- package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +14 -0
- package/dist/runtime/hooks/test-aria-preturn-memory-gate.mjs +245 -0
- package/dist/runtime/hooks/test-tier-lens-labeling.mjs +367 -0
- package/dist/runtime/manifest.json +2 -2
- package/dist/runtime/sdk/BUNDLED.json +2 -2
- package/dist/runtime/sdk/index.d.ts +39 -0
- package/dist/runtime/sdk/index.js +117 -0
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/sdk/runWithGovernance.d.ts +16 -0
- package/dist/runtime/sdk/runWithGovernance.js +54 -0
- package/dist/runtime/sdk/runWithGovernance.js.map +1 -0
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/index.d.ts +39 -0
- package/dist/sdk/index.js +117 -0
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/runWithGovernance.d.ts +16 -0
- package/dist/sdk/runWithGovernance.js +54 -0
- package/dist/sdk/runWithGovernance.js.map +1 -0
- package/hooks/aria-harness-via-sdk.mjs +16 -3
- package/hooks/aria-pre-tool-gate.mjs +41 -1
- package/hooks/aria-stop-gate.mjs +42 -1
- package/hooks/doctrine_trigger_map.json +43 -0
- package/hooks/lib/skill-autoload-gate.mjs +14 -1
- package/opencode-plugins/harness-context/index.js +1 -1
- package/opencode-plugins/harness-gate/index.js +49 -9
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -1
- package/opencode-plugins/harness-stop/index.js +201 -166
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -1
- package/package.json +12 -5
- package/runtime-src/codex-bridge.mjs +1 -1
- package/scripts/bundle-sdk.mjs +2 -0
- package/scripts/self-test-harness-gates.mjs +79 -0
- package/src/connectors/codex.ts +60 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../../src/connectors/codex.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../../src/connectors/codex.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA+3B/C,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkBxE"}
|
|
@@ -68,6 +68,7 @@ function tomlString(value) {
|
|
|
68
68
|
}
|
|
69
69
|
function buildCodexHookRuntimeClient() {
|
|
70
70
|
return `import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
71
|
+
import { spawnSync } from 'node:child_process';
|
|
71
72
|
import { createHash, randomUUID } from 'node:crypto';
|
|
72
73
|
import { homedir } from 'node:os';
|
|
73
74
|
import path from 'node:path';
|
|
@@ -76,6 +77,7 @@ import { HTTPHarnessClient } from '@aria_asi/harness-http-client';
|
|
|
76
77
|
const HOME = homedir();
|
|
77
78
|
const DEFAULT_RUNTIME_URL = (process.env.ARIA_RUNTIME_URL || 'http://127.0.0.1:4319').replace(/\\/+$/, '');
|
|
78
79
|
const TURN_STATE_DIR = path.join(HOME, '.codex', 'tmp', 'aria-hook-turn-state');
|
|
80
|
+
const GOVERNANCE_GATE_PATH = path.join(HOME, '.aria', 'bin', 'aria-governance-gate');
|
|
79
81
|
|
|
80
82
|
function readToken() {
|
|
81
83
|
const envToken = process.env.ARIA_API_KEY || process.env.ARIA_MASTER_TOKEN || process.env.OPENAI_API_KEY;
|
|
@@ -301,6 +303,22 @@ export function emitJson(payload, code = 0) {
|
|
|
301
303
|
process.stdout.write(\`\${JSON.stringify(payload)}\\n\`);
|
|
302
304
|
process.exit(code);
|
|
303
305
|
}
|
|
306
|
+
|
|
307
|
+
export function runGovernanceGate(payload = {}) {
|
|
308
|
+
if (!existsSync(GOVERNANCE_GATE_PATH)) return null;
|
|
309
|
+
const child = spawnSync(GOVERNANCE_GATE_PATH, {
|
|
310
|
+
input: \`\${JSON.stringify(payload)}\\n\`,
|
|
311
|
+
encoding: 'utf8',
|
|
312
|
+
maxBuffer: 1024 * 1024,
|
|
313
|
+
});
|
|
314
|
+
const stdout = String(child.stdout || '').trim();
|
|
315
|
+
let result = null;
|
|
316
|
+
try { result = stdout ? JSON.parse(stdout) : null; } catch {}
|
|
317
|
+
if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
|
|
318
|
+
throw new Error(stdout || child.stderr || 'aria-governance-gate blocked this Codex hook.');
|
|
319
|
+
}
|
|
320
|
+
return result;
|
|
321
|
+
}
|
|
304
322
|
`;
|
|
305
323
|
}
|
|
306
324
|
function buildCodexUserPromptHook() {
|
|
@@ -316,6 +334,7 @@ import {
|
|
|
316
334
|
runtimePost,
|
|
317
335
|
loadTurnState,
|
|
318
336
|
saveTurnState,
|
|
337
|
+
runGovernanceGate,
|
|
319
338
|
emitJson,
|
|
320
339
|
} from './lib/runtime-client.mjs';
|
|
321
340
|
|
|
@@ -334,6 +353,13 @@ try {
|
|
|
334
353
|
message: userText || 'codex turn start',
|
|
335
354
|
});
|
|
336
355
|
const packetRef = makeEvidenceRef('harness_packet', packet, { sessionId, platform: 'codex' });
|
|
356
|
+
runGovernanceGate({
|
|
357
|
+
sessionId,
|
|
358
|
+
sourceRuntime: 'codex',
|
|
359
|
+
surface: 'codex-userprompt-submit',
|
|
360
|
+
text: userText.slice(0, 8000),
|
|
361
|
+
evidence: packetRef,
|
|
362
|
+
});
|
|
337
363
|
const result = await runtimePost('/mizan/pre', {
|
|
338
364
|
sessionId,
|
|
339
365
|
packet,
|
|
@@ -376,7 +402,6 @@ try {
|
|
|
376
402
|
function buildCodexPreToolHook() {
|
|
377
403
|
return `#!/usr/bin/env node
|
|
378
404
|
import {
|
|
379
|
-
getHarnessClient,
|
|
380
405
|
inferSessionId,
|
|
381
406
|
classifyAction,
|
|
382
407
|
summarizeTarget,
|
|
@@ -384,11 +409,11 @@ import {
|
|
|
384
409
|
loadTurnState,
|
|
385
410
|
makeEvidenceRef,
|
|
386
411
|
saveTurnState,
|
|
412
|
+
runGovernanceGate,
|
|
387
413
|
emitJson,
|
|
388
414
|
} from './lib/runtime-client.mjs';
|
|
389
415
|
|
|
390
416
|
const event = readEventFromStdin();
|
|
391
|
-
const client = getHarnessClient();
|
|
392
417
|
const sessionId = inferSessionId(event);
|
|
393
418
|
const action = classifyAction(event);
|
|
394
419
|
const target = summarizeTarget(event);
|
|
@@ -409,6 +434,17 @@ try {
|
|
|
409
434
|
});
|
|
410
435
|
}
|
|
411
436
|
const toolName = String(event?.tool_name || event?.toolName || '').trim() || null;
|
|
437
|
+
runGovernanceGate({
|
|
438
|
+
sessionId,
|
|
439
|
+
sourceRuntime: 'codex',
|
|
440
|
+
surface: 'codex-pre-tool-use',
|
|
441
|
+
text: JSON.stringify(event).slice(0, 8000),
|
|
442
|
+
action,
|
|
443
|
+
toolName,
|
|
444
|
+
isDeploy: action === 'deploy',
|
|
445
|
+
isMutation: action === 'write' || action === 'delete',
|
|
446
|
+
evidence: makeEvidenceRef('codex_tool_request', { action, toolName, target }, { sessionId }),
|
|
447
|
+
});
|
|
412
448
|
const tools = Array.isArray(state?.tools) ? state.tools.slice(-24) : [];
|
|
413
449
|
tools.push({
|
|
414
450
|
at: new Date().toISOString(),
|
|
@@ -470,7 +506,6 @@ try {
|
|
|
470
506
|
function buildCodexStopHook() {
|
|
471
507
|
return `#!/usr/bin/env node
|
|
472
508
|
import {
|
|
473
|
-
getHarnessClient,
|
|
474
509
|
inferSessionId,
|
|
475
510
|
extractAssistantText,
|
|
476
511
|
readEventFromStdin,
|
|
@@ -479,11 +514,11 @@ import {
|
|
|
479
514
|
makeEvidenceRef,
|
|
480
515
|
clearTurnState,
|
|
481
516
|
formatValidationFailure,
|
|
517
|
+
runGovernanceGate,
|
|
482
518
|
emitJson,
|
|
483
519
|
} from './lib/runtime-client.mjs';
|
|
484
520
|
|
|
485
521
|
const event = readEventFromStdin();
|
|
486
|
-
const client = getHarnessClient();
|
|
487
522
|
const sessionId = inferSessionId(event);
|
|
488
523
|
const state = loadTurnState(sessionId);
|
|
489
524
|
const text = extractAssistantText(event);
|
|
@@ -494,6 +529,14 @@ try {
|
|
|
494
529
|
if (!text) {
|
|
495
530
|
emitJson({ continue: true });
|
|
496
531
|
}
|
|
532
|
+
runGovernanceGate({
|
|
533
|
+
sessionId,
|
|
534
|
+
sourceRuntime: 'codex',
|
|
535
|
+
surface: 'codex-stop',
|
|
536
|
+
text: text.slice(0, 8000),
|
|
537
|
+
isOutputCloseout: true,
|
|
538
|
+
evidence: outputRef,
|
|
539
|
+
});
|
|
497
540
|
const validation = await runtimePost('/validate-output', {
|
|
498
541
|
text,
|
|
499
542
|
sessionId,
|
|
@@ -558,7 +601,19 @@ try {
|
|
|
558
601
|
},
|
|
559
602
|
});
|
|
560
603
|
if (typeof state?.userText === 'string' && state.userText.trim()) {
|
|
561
|
-
await
|
|
604
|
+
await runtimePost('/garden/turn', {
|
|
605
|
+
sessionId,
|
|
606
|
+
message: state.userText,
|
|
607
|
+
response: text,
|
|
608
|
+
userId: state?.userId || undefined,
|
|
609
|
+
requireCognitionBlock: false,
|
|
610
|
+
metadata: {
|
|
611
|
+
decision_type: 'codex-stop-garden-turn',
|
|
612
|
+
decision_category: 'codex-hooks',
|
|
613
|
+
trace_id: state?.traceId || null,
|
|
614
|
+
output_ref: outputRef,
|
|
615
|
+
},
|
|
616
|
+
});
|
|
562
617
|
}
|
|
563
618
|
clearTurnState(sessionId);
|
|
564
619
|
emitJson({ continue: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../../src/connectors/codex.ts"],"names":[],"mappings":"AAAA,8HAA8H;AAE9H,OAAO,EACL,UAAU,EACV,SAAS,EACT,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,aAAa,EACb,YAAY,GACb,MAAM,IAAI,CAAC;AACZ,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEnE,SAAS,aAAa;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,UAAU,CAAC,QAAgB,EAAE,IAAc;IAClD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,yBAAyB,MAAM,sBAAsB,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE;YAAE,SAAS;QACtC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3C,MAAM,EAAE,CAAC;IACX,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,uBAAuB,MAAM,aAAa,MAAM,EAAE,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB,EAAE,IAAc;IAC1D,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO;IAEhC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,qBAAqB,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5C,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEtD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE;YAAE,SAAS;QACtC,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,cAAc;YAAE,SAAS;QACjE,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,aAAa,CACX,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,EAClC,IAAI,CAAC,SAAS,CAAC;QACb,IAAI,EAAE,+BAA+B;QACrC,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,qDAAqD;QAClE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,mBAAmB;QAC1B,OAAO,EAAE;YACP,GAAG,EAAE;gBACH,KAAK,EAAE,mBAAmB;gBAC1B,MAAM,EAAE,iBAAiB;aAC1B;SACF;QACD,OAAO,EAAE,KAAK;KACf,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAClB,EAAE,IAAI,EAAE,KAAK,EAAE,CAChB,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,kCAAkC,OAAO,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,2BAA2B;IAClC,OAAO
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../../src/connectors/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Aria harness fetch — via the canonical @
|
|
2
|
+
// Aria harness fetch — via the canonical @aria_asi/harness-http-client SDK.
|
|
3
3
|
//
|
|
4
4
|
// Why this exists: doctrine says "use harness http client to be Aria's
|
|
5
5
|
// control plane so you don't mess up". The earlier hook (aria-harness-fetch.sh)
|
|
@@ -245,6 +245,10 @@ function sanitizeSessionId(sessionId) {
|
|
|
245
245
|
return String(sessionId || 'claude-code').replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
function currentHookSessionId() {
|
|
249
|
+
return HOOK_EVENT?.session_id || HOOK_EVENT?.sessionId || 'claude-code';
|
|
250
|
+
}
|
|
251
|
+
|
|
248
252
|
function lastUserMessageFromEvent() {
|
|
249
253
|
const messages = Array.isArray(HOOK_EVENT?.messages) ? HOOK_EVENT.messages : [];
|
|
250
254
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
@@ -278,7 +282,7 @@ function persistMizanReceipt(sessionId, payload) {
|
|
|
278
282
|
|
|
279
283
|
async function runMizanPre(apiKey, packet, sourceLabel) {
|
|
280
284
|
if (!isTurn) return null;
|
|
281
|
-
const sessionId =
|
|
285
|
+
const sessionId = currentHookSessionId();
|
|
282
286
|
const packetHash = createHash('sha256').update(JSON.stringify(packet || {})).digest('hex');
|
|
283
287
|
const response = await fetch(`${DEFAULT_RUNTIME_URL.replace(/\/+$/, '')}/mizan/pre`, {
|
|
284
288
|
method: 'POST',
|
|
@@ -342,12 +346,17 @@ async function tryViaSdk(baseUrl, apiKey) {
|
|
|
342
346
|
// identifies owner tier from the Bearer token (isMasterTokenRequest).
|
|
343
347
|
// Hardcoding isHamza:false in the body would override that server-side
|
|
344
348
|
// signal and produce hamza:false in the packet even for master-token callers.
|
|
349
|
+
const sessionId = currentHookSessionId();
|
|
345
350
|
const bodyOverride = {
|
|
346
351
|
message: isTurn ? 'Claude turn refresh — harness via SDK' : 'Claude session start — harness via SDK',
|
|
347
352
|
stage: isTurn ? 'checkpoint' : 'preflight',
|
|
353
|
+
sessionId,
|
|
348
354
|
actor: 'claude-code',
|
|
349
355
|
system: 'claude-coding-agent',
|
|
350
|
-
platform: '
|
|
356
|
+
platform: 'claude-code',
|
|
357
|
+
deliverySurface: 'claude_code_session',
|
|
358
|
+
userId: 'hamza',
|
|
359
|
+
isHamza: true,
|
|
351
360
|
// Bonus #74: forward conversation history so codex handler can report
|
|
352
361
|
// a non-zero conversation_history_count in the packet.
|
|
353
362
|
...(HOOK_EVENT_MESSAGES ? { messages: HOOK_EVENT_MESSAGES } : {}),
|
|
@@ -372,10 +381,14 @@ async function tryViaSdk(baseUrl, apiKey) {
|
|
|
372
381
|
body: JSON.stringify({
|
|
373
382
|
message: isTurn ? 'Claude turn refresh — harness via SDK' : 'Claude session start — harness via SDK',
|
|
374
383
|
stage: isTurn ? 'checkpoint' : 'preflight',
|
|
384
|
+
sessionId: currentHookSessionId(),
|
|
375
385
|
actor: 'claude-code',
|
|
376
386
|
system: 'claude-coding-agent',
|
|
377
387
|
roleProfile: 'general_worker',
|
|
388
|
+
platform: 'claude-code',
|
|
378
389
|
deliverySurface: 'claude_code_session',
|
|
390
|
+
userId: 'hamza',
|
|
391
|
+
isHamza: true,
|
|
379
392
|
// Bonus #74: forward conversation history (same field as SDK path above).
|
|
380
393
|
...(HOOK_EVENT_MESSAGES ? { messages: HOOK_EVENT_MESSAGES } : {}),
|
|
381
394
|
}),
|
|
@@ -58,6 +58,24 @@ const HOME = process.env.HOME || '/tmp';
|
|
|
58
58
|
const LOG = `${HOME}/.claude/aria-pre-tool-gate.log`;
|
|
59
59
|
const HEARTBEAT = `${HOME}/.claude/aria-pre-tool-gate-heartbeat.jsonl`;
|
|
60
60
|
const GATE_LOOP_STATE_PATH = `${HOME}/.claude/.aria-gate-loop-state.json`;
|
|
61
|
+
const GOVERNANCE_GATE_PATH = `${HOME}/.aria/bin/aria-governance-gate`;
|
|
62
|
+
|
|
63
|
+
function runUniversalGovernanceGate(payload) {
|
|
64
|
+
if (!existsSync(GOVERNANCE_GATE_PATH)) return null;
|
|
65
|
+
const child = spawnSync(GOVERNANCE_GATE_PATH, {
|
|
66
|
+
input: `${JSON.stringify(payload)}\n`,
|
|
67
|
+
encoding: 'utf8',
|
|
68
|
+
maxBuffer: 1024 * 1024,
|
|
69
|
+
});
|
|
70
|
+
const stdout = String(child.stdout || '').trim();
|
|
71
|
+
let result = null;
|
|
72
|
+
try { result = stdout ? JSON.parse(stdout) : null; } catch {}
|
|
73
|
+
if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
|
|
74
|
+
const reason = stdout || child.stderr || 'aria-governance-gate blocked this action.';
|
|
75
|
+
throw new Error(`=== ARIA UNIVERSAL GOVERNANCE GATE BLOCK ===\n\n${reason}`);
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
61
79
|
|
|
62
80
|
// ── Heartbeat OUTSIDE the crash boundary (doctrine #123) ───────────────
|
|
63
81
|
// Per feedback_ledger_writes_outside_crash_boundary.md + doctrine #124
|
|
@@ -1305,6 +1323,25 @@ if (!skillGate.ok) {
|
|
|
1305
1323
|
emitBlock(reason, { source: 'pre-tool/skill-autoload', tool: toolName, lensCount, requiredLenses: REQUIRED_LENSES });
|
|
1306
1324
|
process.exit(2);
|
|
1307
1325
|
}
|
|
1326
|
+
try {
|
|
1327
|
+
runUniversalGovernanceGate({
|
|
1328
|
+
sessionId,
|
|
1329
|
+
sourceRuntime: 'claude-code',
|
|
1330
|
+
surface: 'claude-pre-tool-gate',
|
|
1331
|
+
text: [unionText, JSON.stringify(toolInput || {})].join('\n').slice(0, 8000),
|
|
1332
|
+
action: cmd,
|
|
1333
|
+
toolName,
|
|
1334
|
+
filePath,
|
|
1335
|
+
isDeploy: Boolean(deployMatched),
|
|
1336
|
+
isMutation: toolName !== 'Bash',
|
|
1337
|
+
loadedSkills: skillGate.loadedSkills,
|
|
1338
|
+
evidence: { lensCount, hasVerify, hasCognition, hasSubstrateCite },
|
|
1339
|
+
});
|
|
1340
|
+
} catch (err) {
|
|
1341
|
+
audit('block-universal-governance', `${err instanceof Error ? err.message : String(err)}`.slice(0, 500));
|
|
1342
|
+
emitBlock(err instanceof Error ? err.message : String(err), { source: 'pre-tool/universal-governance', tool: toolName, lensCount, requiredLenses: REQUIRED_LENSES });
|
|
1343
|
+
process.exit(2);
|
|
1344
|
+
}
|
|
1308
1345
|
|
|
1309
1346
|
function pushDecision(decision, reasonText) {
|
|
1310
1347
|
pushCognitionEvent({
|
|
@@ -1459,6 +1496,7 @@ if (deployMatched) {
|
|
|
1459
1496
|
// reads the same file and computes the same HMAC.
|
|
1460
1497
|
try {
|
|
1461
1498
|
const justificationPath = `${HOME}/.claude/.aria-deploy-justification.json`;
|
|
1499
|
+
const runtimeAgnosticJustificationPath = `${HOME}/.aria/.aria-deploy-justification.json`;
|
|
1462
1500
|
const secretPath = `${HOME}/.claude/.aria-gate-secret`;
|
|
1463
1501
|
|
|
1464
1502
|
// Lazy-generate per-installation secret if absent.
|
|
@@ -1500,6 +1538,8 @@ if (deployMatched) {
|
|
|
1500
1538
|
signatureAlgo: 'HMAC-SHA256',
|
|
1501
1539
|
};
|
|
1502
1540
|
writeFileSync(justificationPath, JSON.stringify(justification, null, 2));
|
|
1541
|
+
mkdirSync(dirname(runtimeAgnosticJustificationPath), { recursive: true });
|
|
1542
|
+
writeFileSync(runtimeAgnosticJustificationPath, JSON.stringify(justification, null, 2), { mode: 0o600 });
|
|
1503
1543
|
} catch (writeErr) {
|
|
1504
1544
|
// Write failure is non-fatal for the gate decision (the gate itself
|
|
1505
1545
|
// is the structural enforcement); log loudly per
|
|
@@ -2177,7 +2217,7 @@ Claude must either: (a) reframe action to fit allowedActions, OR (b) emit [PLAN_
|
|
|
2177
2217
|
// every tool when substrate is down would brick the orchestrator, but the
|
|
2178
2218
|
// failure is logged for telemetry.
|
|
2179
2219
|
try {
|
|
2180
|
-
const { HTTPHarnessClient } = await import('@
|
|
2220
|
+
const { HTTPHarnessClient } = await import('@aria_asi/harness-http-client');
|
|
2181
2221
|
const { readFileSync: __fsRead, existsSync: __fsExists } = await import('node:fs');
|
|
2182
2222
|
const { homedir: __homedir } = await import('node:os');
|
|
2183
2223
|
const __home = __homedir();
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
|
|
50
50
|
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
51
51
|
import { dirname } from 'node:path';
|
|
52
|
+
import { spawnSync } from 'node:child_process';
|
|
52
53
|
import { appendGateAudit } from './lib/gate-audit.mjs';
|
|
53
54
|
import {
|
|
54
55
|
ALL_LENS_NAMES,
|
|
@@ -69,6 +70,24 @@ const LOG = `${HOME}/.claude/aria-stop-gate.log`;
|
|
|
69
70
|
const AUDIT_PATH = `${HOME}/.claude/aria-stop-gate-audit.jsonl`;
|
|
70
71
|
const GATE_LOOP_STATE_PATH = `${HOME}/.claude/.aria-gate-loop-state.json`;
|
|
71
72
|
const MIZAN_RECEIPT_DIR = `${HOME}/.claude/.aria-mizan-receipts`;
|
|
73
|
+
const GOVERNANCE_GATE_PATH = `${HOME}/.aria/bin/aria-governance-gate`;
|
|
74
|
+
|
|
75
|
+
function runUniversalGovernanceGate(payload) {
|
|
76
|
+
if (!existsSync(GOVERNANCE_GATE_PATH)) return null;
|
|
77
|
+
const child = spawnSync(GOVERNANCE_GATE_PATH, {
|
|
78
|
+
input: `${JSON.stringify(payload)}\n`,
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
maxBuffer: 1024 * 1024,
|
|
81
|
+
});
|
|
82
|
+
const stdout = String(child.stdout || '').trim();
|
|
83
|
+
let result = null;
|
|
84
|
+
try { result = stdout ? JSON.parse(stdout) : null; } catch {}
|
|
85
|
+
if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
|
|
86
|
+
const reason = stdout || child.stderr || 'aria-governance-gate blocked this output.';
|
|
87
|
+
throw new Error(`=== ARIA UNIVERSAL GOVERNANCE GATE BLOCK ===\n\n${reason}`);
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
72
91
|
|
|
73
92
|
// SDK loader — bundled at ~/.aria/sdk by `aria connect`, with client-local
|
|
74
93
|
// fallbacks preserved for resilience.
|
|
@@ -640,6 +659,28 @@ if (!stopSkillGate.ok) {
|
|
|
640
659
|
console.log(JSON.stringify({ decision: 'block', reason }));
|
|
641
660
|
process.exit(2);
|
|
642
661
|
}
|
|
662
|
+
try {
|
|
663
|
+
runUniversalGovernanceGate({
|
|
664
|
+
sessionId: event.session_id || 'claude-code',
|
|
665
|
+
sourceRuntime: 'claude-code',
|
|
666
|
+
surface: 'claude-stop-gate',
|
|
667
|
+
text: assistantText.slice(0, 8000),
|
|
668
|
+
isOutputCloseout: true,
|
|
669
|
+
loadedSkills: stopSkillGate.loadedSkills,
|
|
670
|
+
evidence: { chars: assistantText.length, hasDecisionSignal, isLong },
|
|
671
|
+
});
|
|
672
|
+
} catch (err) {
|
|
673
|
+
audit('block-universal-governance', `${err instanceof Error ? err.message : String(err)}`.slice(0, 500));
|
|
674
|
+
const reason = withLoopDirective(buildForceReauthorReason({
|
|
675
|
+
source: 'stop/universal-governance',
|
|
676
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
677
|
+
violations: ['Universal governance gate blocked this output.'],
|
|
678
|
+
lensCount: 0,
|
|
679
|
+
requiredLenses: REQUIRED_LENSES,
|
|
680
|
+
}), 'stop:universal-governance', gateSessionId);
|
|
681
|
+
console.log(JSON.stringify({ decision: 'block', reason }));
|
|
682
|
+
process.exit(2);
|
|
683
|
+
}
|
|
643
684
|
|
|
644
685
|
// Non-trivial response — require substantive cognition.
|
|
645
686
|
const cog = detectCognitionLenses(assistantText);
|
|
@@ -1398,7 +1439,7 @@ if (cog.count >= REQUIRED_LENSES) {
|
|
|
1398
1439
|
let substrateViolations = [];
|
|
1399
1440
|
let substrateGateTriggers = [];
|
|
1400
1441
|
try {
|
|
1401
|
-
const { HTTPHarnessClient } = await import('@
|
|
1442
|
+
const { HTTPHarnessClient } = await import('@aria_asi/harness-http-client');
|
|
1402
1443
|
const tokenPath = `${HOME}/.aria/owner-token`;
|
|
1403
1444
|
// Tier-aware resolution: ARIA_HARNESS_TOKEN env first (both tiers).
|
|
1404
1445
|
// ONLY on owner tier, fall back to master/api-key env or owner-token
|
|
@@ -508,6 +508,49 @@
|
|
|
508
508
|
"counter_action": "Create or reuse one turn substrate object containing embedding, perturb snapshot, ProjectAllDomains result, awakenAria Garden block, DeepSoul/Noor/shards/Mizan signals; pass it downstream.",
|
|
509
509
|
"message": "Duplicate projection path detected. Replace with one per-turn cognition packet and shared consumption."
|
|
510
510
|
},
|
|
511
|
+
{
|
|
512
|
+
"trigger_id": "premature_task_closeout",
|
|
513
|
+
"trigger": "(?:done|complete|completed|ready|verified|fixed).{0,120}(?:but|except|caveat|remaining|not yet|still|separate|later|blocked|skipped)",
|
|
514
|
+
"rx": "(?:done|complete|completed|ready|verified|fixed).{0,120}(?:but|except|caveat|remaining|not yet|still|separate|later|blocked|skipped)",
|
|
515
|
+
"doctrine": "memory:feedback_no_premature_task_closeout.md",
|
|
516
|
+
"memory": "feedback_no_premature_task_closeout.md",
|
|
517
|
+
"severity": "block",
|
|
518
|
+
"teaching": "A task is not complete while material blockers remain. Completion claims must match the verified scope.",
|
|
519
|
+
"counter_action": "Do not close the task. Fix the blocker now, or create an owner-visible durable task with the exact failing surface and verification gap.",
|
|
520
|
+
"message": "Premature closeout detected: completion language coexists with unresolved blockers. Fix or durably track before emitting."
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
"trigger_id": "narrow_e2e_overclaim",
|
|
524
|
+
"trigger": "(?:production-ready|ready for production|works in general|client packages?|npm packages?|SDKs?|runtimes?|harnesses?).{0,220}(?:deal|single flow|one flow|widget|one service|specific path|covered flow)",
|
|
525
|
+
"rx": "(?:production-ready|ready for production|works in general|client packages?|npm packages?|SDKs?|runtimes?|harnesses?).{0,220}(?:deal|single flow|one flow|widget|one service|specific path|covered flow)",
|
|
526
|
+
"doctrine": "memory:feedback_narrow_e2e_overclaim.md",
|
|
527
|
+
"memory": "feedback_narrow_e2e_overclaim.md",
|
|
528
|
+
"severity": "block",
|
|
529
|
+
"teaching": "A narrow e2e does not prove general production readiness for SDKs, npm packages, runtimes, clients, or harnesses.",
|
|
530
|
+
"counter_action": "Run the general readiness matrix or explicitly limit the claim to the verified surface. Do not imply general readiness from one app flow.",
|
|
531
|
+
"message": "Narrow proof overclaim detected. General readiness requires the client/package/runtime/harness matrix."
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
"trigger_id": "advisory_gate_not_gate",
|
|
535
|
+
"trigger": "(?:non-blocking|warn(?:ing)? only|advisory|falls? through|fail open|soft fail|log(?:ged)? and continue|quality gate warning)",
|
|
536
|
+
"rx": "(?:non-blocking|warn(?:ing)? only|advisory|falls? through|fail open|soft fail|log(?:ged)? and continue|quality gate warning)",
|
|
537
|
+
"doctrine": "memory:feedback_advisory_gate_is_not_gate.md",
|
|
538
|
+
"memory": "feedback_advisory_gate_is_not_gate.md",
|
|
539
|
+
"severity": "block",
|
|
540
|
+
"teaching": "A gate that only warns or falls through is not a gate. Enforcement must fail closed where quality or doctrine is required.",
|
|
541
|
+
"counter_action": "Convert advisory paths to blocking errors, add a self-test that proves rejection, and install the hardened gate into each consumer surface.",
|
|
542
|
+
"message": "Advisory gate bypass detected. Convert to fail-closed enforcement and prove it with a blocking self-test."
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
"trigger_id": "start_new_session_as_gate_fix",
|
|
546
|
+
"trigger": "(?:start|open|begin).{0,40}(?:new|fresh).{0,30}session.{0,120}(?:fix|gate|harness|enforcement)",
|
|
547
|
+
"rx": "(?:start|open|begin).{0,40}(?:new|fresh).{0,30}session.{0,120}(?:fix|gate|harness|enforcement)",
|
|
548
|
+
"doctrine": "memory:feedback_advisory_gate_is_not_gate.md",
|
|
549
|
+
"memory": "feedback_advisory_gate_is_not_gate.md",
|
|
550
|
+
"severity": "block",
|
|
551
|
+
"teaching": "A new session is not an enforcement fix. It only reloads whatever gate contract exists; broken gates remain broken.",
|
|
552
|
+
"counter_action": "Fix the runtime/plugin/hook contract, reinstall it, and run a live bad-action/bad-output self-test that proves blocking."
|
|
553
|
+
},
|
|
511
554
|
{
|
|
512
555
|
"trigger_id": "registry_image_drift",
|
|
513
556
|
"trigger": "image.?pull|ErrImageNeverPull|ImagePullBackOff|registry gc|image.*missing|image.*not.*found",
|
|
@@ -1 +1,14 @@
|
|
|
1
|
-
|
|
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'); }
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Aria Harness Context Plugin for OpenCode.
|
|
3
3
|
*
|
|
4
4
|
* Injects the live harness packet into OpenCode's system prompt on every
|
|
5
|
-
* session start. Routes through the canonical @
|
|
5
|
+
* session start. Routes through the canonical @aria_asi/harness-http-client SDK
|
|
6
6
|
* via the inject-context.mjs script that ships alongside this plugin.
|
|
7
7
|
*
|
|
8
8
|
* Distribution: this dir is installed by `aria connect` (via connectors/
|
|
@@ -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
|
|
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(
|
|
191
|
-
const filePath = toolName !== 'Bash' ? String(
|
|
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(
|
|
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
|
-
|
|
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'); }
|