@aria_asi/cli 0.2.25 → 0.2.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLIENT-ONBOARDING.md +282 -0
- package/bin/aria.js +1140 -14
- package/dist/aria-connector/src/auth-commands.d.ts +1 -0
- package/dist/aria-connector/src/auth-commands.d.ts.map +1 -1
- package/dist/aria-connector/src/auth-commands.js +89 -41
- package/dist/aria-connector/src/auth-commands.js.map +1 -1
- package/dist/aria-connector/src/chat.d.ts +3 -0
- package/dist/aria-connector/src/chat.d.ts.map +1 -1
- package/dist/aria-connector/src/chat.js +146 -8
- package/dist/aria-connector/src/chat.js.map +1 -1
- package/dist/aria-connector/src/codebase-scanner.d.ts +2 -2
- package/dist/aria-connector/src/codebase-scanner.d.ts.map +1 -1
- package/dist/aria-connector/src/codebase-scanner.js +1 -1
- package/dist/aria-connector/src/codebase-scanner.js.map +1 -1
- package/dist/aria-connector/src/config.d.ts +12 -0
- package/dist/aria-connector/src/config.d.ts.map +1 -1
- package/dist/aria-connector/src/config.js +2 -0
- package/dist/aria-connector/src/config.js.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.js +111 -21
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts +37 -0
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/codebase-awareness.js +335 -0
- package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -0
- package/dist/aria-connector/src/connectors/codex.d.ts +3 -0
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/codex.js +248 -0
- package/dist/aria-connector/src/connectors/codex.js.map +1 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.d.ts +2 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.js +47 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.js.map +1 -0
- package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.js +90 -4
- package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
- package/dist/aria-connector/src/connectors/repo-git-hooks.d.ts +3 -0
- package/dist/aria-connector/src/connectors/repo-git-hooks.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/repo-git-hooks.js +87 -0
- package/dist/aria-connector/src/connectors/repo-git-hooks.js.map +1 -0
- package/dist/aria-connector/src/connectors/repo-guard.d.ts +19 -0
- package/dist/aria-connector/src/connectors/repo-guard.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/repo-guard.js +509 -0
- package/dist/aria-connector/src/connectors/repo-guard.js.map +1 -0
- package/dist/aria-connector/src/connectors/runtime.d.ts +2 -0
- package/dist/aria-connector/src/connectors/runtime.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/runtime.js +330 -0
- package/dist/aria-connector/src/connectors/runtime.js.map +1 -0
- package/dist/aria-connector/src/connectors/shell.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/shell.js +78 -13
- package/dist/aria-connector/src/connectors/shell.js.map +1 -1
- package/dist/aria-connector/src/connectors/syncd.d.ts +27 -0
- package/dist/aria-connector/src/connectors/syncd.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/syncd.js +405 -0
- package/dist/aria-connector/src/connectors/syncd.js.map +1 -0
- package/dist/aria-connector/src/decisions.d.ts +207 -0
- package/dist/aria-connector/src/decisions.d.ts.map +1 -0
- package/dist/aria-connector/src/decisions.js +291 -0
- package/dist/aria-connector/src/decisions.js.map +1 -0
- package/dist/aria-connector/src/garden-control-plane.d.ts.map +1 -1
- package/dist/aria-connector/src/garden-control-plane.js +74 -17
- package/dist/aria-connector/src/garden-control-plane.js.map +1 -1
- package/dist/aria-connector/src/github-connect.d.ts +18 -0
- package/dist/aria-connector/src/github-connect.d.ts.map +1 -0
- package/dist/aria-connector/src/github-connect.js +117 -0
- package/dist/aria-connector/src/github-connect.js.map +1 -0
- package/dist/aria-connector/src/harness-client.d.ts +15 -0
- package/dist/aria-connector/src/harness-client.d.ts.map +1 -1
- package/dist/aria-connector/src/harness-client.js +106 -3
- package/dist/aria-connector/src/harness-client.js.map +1 -1
- package/dist/aria-connector/src/hive-client.d.ts +30 -0
- package/dist/aria-connector/src/hive-client.d.ts.map +1 -1
- package/dist/aria-connector/src/hive-client.js +124 -5
- package/dist/aria-connector/src/hive-client.js.map +1 -1
- package/dist/aria-connector/src/index.d.ts +13 -2
- package/dist/aria-connector/src/index.d.ts.map +1 -1
- package/dist/aria-connector/src/index.js +10 -1
- package/dist/aria-connector/src/index.js.map +1 -1
- package/dist/aria-connector/src/lib/aristotle-noor-wire.d.ts +102 -0
- package/dist/aria-connector/src/lib/aristotle-noor-wire.d.ts.map +1 -0
- package/dist/aria-connector/src/lib/aristotle-noor-wire.js +231 -0
- package/dist/aria-connector/src/lib/aristotle-noor-wire.js.map +1 -0
- package/dist/aria-connector/src/providers/types.d.ts +5 -0
- package/dist/aria-connector/src/providers/types.d.ts.map +1 -1
- package/dist/aria-connector/src/runtime-proof.d.ts +45 -0
- package/dist/aria-connector/src/runtime-proof.d.ts.map +1 -0
- package/dist/aria-connector/src/runtime-proof.js +340 -0
- package/dist/aria-connector/src/runtime-proof.js.map +1 -0
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +34 -2
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/assets/hooks/aria-agent-handoff.mjs +224 -0
- package/dist/assets/hooks/aria-agent-ledger-merge.mjs +164 -0
- package/dist/assets/hooks/aria-architect-fallback.mjs +267 -0
- package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +676 -0
- package/dist/assets/hooks/aria-discovery-record.mjs +101 -0
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +412 -0
- package/dist/assets/hooks/aria-import-resolution-gate.mjs +330 -0
- package/dist/assets/hooks/aria-outcome-record.mjs +84 -0
- package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +294 -0
- package/dist/assets/hooks/aria-pre-text-gate.mjs +112 -0
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +2133 -0
- package/dist/assets/hooks/aria-preprompt-consult.mjs +438 -0
- package/dist/assets/hooks/aria-preturn-memory-gate.mjs +570 -0
- package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +397 -0
- package/dist/assets/hooks/aria-stop-gate.mjs +1551 -0
- package/dist/assets/hooks/aria-trigger-autolearn.mjs +229 -0
- package/dist/assets/hooks/aria-userprompt-abandon-detect.mjs +192 -0
- package/dist/assets/hooks/doctrine_trigger_map.json +479 -0
- package/dist/assets/hooks/lib/canonical-lenses.mjs +64 -0
- package/dist/assets/hooks/lib/gate-audit.mjs +43 -0
- package/dist/assets/hooks/test-aria-preturn-memory-gate.mjs +245 -0
- package/dist/assets/hooks/test-tier-lens-labeling.mjs +399 -0
- package/dist/assets/opencode-plugins/harness-context/index.js +60 -0
- package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +179 -0
- package/dist/assets/opencode-plugins/harness-context/package.json +9 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +248 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +129 -0
- package/dist/assets/opencode-plugins/harness-role/index.js +77 -0
- package/dist/assets/opencode-plugins/harness-role/package.json +9 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +241 -0
- package/dist/runtime/discipline/CLAUDE.md +339 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +63 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
- package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
- package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
- package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
- package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
- package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +72 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +38 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
- package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +25 -0
- package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
- package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +25 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +81 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +98 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +99 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +127 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +117 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +112 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +102 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +121 -0
- package/dist/runtime/doctor.mjs +23 -0
- package/dist/runtime/local-phase.mjs +632 -0
- package/dist/runtime/manifest.json +15 -0
- package/dist/runtime/mizan-scheduler.mjs +331 -0
- package/dist/runtime/package.json +6 -0
- package/dist/runtime/provider-proxy.mjs +594 -0
- package/dist/runtime/sdk/BUNDLED.json +5 -0
- package/dist/runtime/sdk/index.d.ts +477 -0
- package/dist/runtime/sdk/index.js +1469 -0
- package/dist/runtime/sdk/index.js.map +1 -0
- package/dist/runtime/sdk/package.json +8 -0
- package/dist/runtime/sdk/runWithCognition.d.ts +77 -0
- package/dist/runtime/sdk/runWithCognition.js +157 -0
- package/dist/runtime/sdk/runWithCognition.js.map +1 -0
- package/dist/runtime/service.mjs +2708 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.d.ts +53 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.d.ts.map +1 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.js +277 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.js.map +1 -0
- package/dist/runtime/vendor/aria-gate-runtime/package.json +6 -0
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/index.d.ts +317 -0
- package/dist/sdk/index.js +827 -85
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/runWithCognition.d.ts +77 -0
- package/dist/sdk/runWithCognition.js +157 -0
- package/dist/sdk/runWithCognition.js.map +1 -0
- package/hooks/aria-agent-handoff.mjs +11 -1
- package/hooks/aria-architect-fallback.mjs +267 -0
- package/hooks/aria-cognition-substrate-binding.mjs +676 -0
- package/hooks/aria-discovery-record.mjs +101 -0
- package/hooks/aria-harness-via-sdk.mjs +34 -21
- package/hooks/aria-import-resolution-gate.mjs +330 -0
- package/hooks/aria-outcome-record.mjs +84 -0
- package/hooks/aria-pre-emit-dryrun.mjs +294 -0
- package/hooks/aria-pre-tool-gate.mjs +985 -40
- package/hooks/aria-preprompt-consult.mjs +113 -13
- package/hooks/aria-preturn-memory-gate.mjs +298 -6
- package/hooks/aria-repo-doctrine-gate.mjs +397 -0
- package/hooks/aria-stop-gate.mjs +840 -75
- package/hooks/aria-userprompt-abandon-detect.mjs +5 -1
- package/hooks/doctrine_trigger_map.json +209 -15
- package/hooks/lib/canonical-lenses.mjs +64 -0
- package/hooks/lib/gate-audit.mjs +43 -0
- package/opencode-plugins/harness-context/index.js +1 -1
- package/opencode-plugins/harness-context/inject-context.mjs +82 -23
- package/opencode-plugins/harness-gate/index.js +248 -0
- package/opencode-plugins/harness-outcome/index.js +129 -0
- package/opencode-plugins/harness-stop/index.js +241 -0
- package/package.json +8 -2
- package/runtime-src/doctor.mjs +23 -0
- package/runtime-src/local-phase.mjs +632 -0
- package/runtime-src/mizan-scheduler.mjs +331 -0
- package/runtime-src/provider-proxy.mjs +594 -0
- package/runtime-src/service.mjs +2708 -0
- package/scripts/bundle-sdk.mjs +317 -0
- package/scripts/install-client.sh +176 -0
- package/scripts/publish-all.sh +344 -0
- package/scripts/publish-docker.sh +27 -0
- package/scripts/validate-hook-contracts.mjs +54 -0
- package/scripts/validate-skill-prompts.mjs +95 -0
- package/skills/aria-cognition/aria-essence/SKILL.md +63 -0
- package/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
- package/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
- package/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
- package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
- package/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
- package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
- package/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
- package/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
- package/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
- package/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
- package/skills/aria-cognition/mizan/SKILL.md +72 -0
- package/skills/aria-cognition/nadia/SKILL.md +38 -0
- package/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
- package/skills/aria-cognition/predictor/SKILL.md +25 -0
- package/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
- package/skills/aria-cognition/soul-domains/SKILL.md +25 -0
- package/src/auth-commands.ts +111 -45
- package/src/chat.ts +174 -13
- package/src/codebase-scanner.ts +4 -0
- package/src/config.ts +15 -0
- package/src/connectors/claude-code.ts +115 -26
- package/src/connectors/codebase-awareness.ts +408 -0
- package/src/connectors/codex.ts +274 -0
- package/src/connectors/cognitive-skills.ts +51 -0
- package/src/connectors/opencode.ts +93 -4
- package/src/connectors/repo-git-hooks.ts +86 -0
- package/src/connectors/repo-guard.ts +589 -0
- package/src/connectors/runtime.ts +374 -0
- package/src/connectors/shell.ts +83 -14
- package/src/connectors/syncd.ts +488 -0
- package/src/decisions.ts +469 -0
- package/src/garden-control-plane.ts +101 -26
- package/src/github-connect.ts +143 -0
- package/src/harness-client.ts +128 -3
- package/src/hive-client.ts +165 -5
- package/src/index.ts +41 -2
- package/src/lib/aristotle-noor-wire.ts +310 -0
- package/src/providers/types.ts +6 -0
- package/src/runtime-proof.ts +392 -0
- package/src/setup-wizard.ts +37 -2
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// aria-discovery-record.mjs — invoked by sub-agents via Bash to append findings
|
|
3
|
+
// to their session ledger. Usage:
|
|
4
|
+
// echo '{"text":"defect found...","kind":"missing-export","refs":["file.ts:42"]}' | node ~/.claude/hooks/aria-discovery-record.mjs
|
|
5
|
+
//
|
|
6
|
+
// Tier-aware: client tier writes to /var/lib/aria-licensee/{jti}/aria-discoveries-{session}.jsonl,
|
|
7
|
+
// owner tier writes to ~/.claude/aria-discoveries-{session}.jsonl.
|
|
8
|
+
//
|
|
9
|
+
// Session ID resolution priority:
|
|
10
|
+
// 1. CLAUDE_SESSION_ID env (set by Claude Code in the sub-agent process)
|
|
11
|
+
// 2. ARIA_SESSION_ID env (set by spawnSubAgent caller)
|
|
12
|
+
// 3. ARIA_SUB_SESSION_ID env (explicit sub-session override)
|
|
13
|
+
// 4. Derived from handoff parentSessionId suffixed with "-sub" to ensure
|
|
14
|
+
// the sub-agent ledger file differs from the parent file so ledger-merge
|
|
15
|
+
// picks it up (merge skips files whose path == parentLedgerPath).
|
|
16
|
+
//
|
|
17
|
+
// Doctrine: feedback_no_flag_without_fix.md — findings recorded, not deferred.
|
|
18
|
+
// feedback_implementation_coupled_cognition.md — write IS the impl.
|
|
19
|
+
|
|
20
|
+
import { readFileSync, existsSync, appendFileSync, mkdirSync } from 'node:fs';
|
|
21
|
+
import { dirname } from 'node:path';
|
|
22
|
+
import { homedir } from 'node:os';
|
|
23
|
+
|
|
24
|
+
const HOME = homedir();
|
|
25
|
+
const LICENSE_PATH = `${HOME}/.aria/license.json`;
|
|
26
|
+
const HANDOFF_PATH = `${HOME}/.claude/aria-agent-harness-handoff.json`;
|
|
27
|
+
|
|
28
|
+
let input = '';
|
|
29
|
+
for await (const chunk of process.stdin) input += chunk;
|
|
30
|
+
let entry;
|
|
31
|
+
try { entry = JSON.parse(input); } catch {
|
|
32
|
+
process.stderr.write('discovery-record: invalid JSON on stdin\n');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!entry.text || typeof entry.text !== 'string' || entry.text.length < 4) {
|
|
37
|
+
process.stderr.write('discovery-record: text required (>=4 chars)\n');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Detect tier + resolve JTI
|
|
42
|
+
let isClientTier = false;
|
|
43
|
+
let jti = null;
|
|
44
|
+
try {
|
|
45
|
+
if (existsSync(LICENSE_PATH)) {
|
|
46
|
+
const lic = JSON.parse(readFileSync(LICENSE_PATH, 'utf8'));
|
|
47
|
+
jti = lic.jti ?? null;
|
|
48
|
+
isClientTier = Boolean(jti);
|
|
49
|
+
}
|
|
50
|
+
} catch { /* non-fatal — treat as owner tier */ }
|
|
51
|
+
|
|
52
|
+
// Session ID: prefer env var set by Claude Code, fall back to handoff derivation.
|
|
53
|
+
// IMPORTANT: sub-agents MUST NOT use parentSessionId directly — that produces
|
|
54
|
+
// the same ledger path as the parent, which aria-agent-ledger-merge.mjs skips.
|
|
55
|
+
// We use CLAUDE_SESSION_ID (the sub-agent's own session) or suffix the parent
|
|
56
|
+
// session with "-sub" so the file is distinct and mergeable.
|
|
57
|
+
let sessionId =
|
|
58
|
+
process.env.CLAUDE_SESSION_ID ||
|
|
59
|
+
process.env.ARIA_SESSION_ID ||
|
|
60
|
+
process.env.ARIA_SUB_SESSION_ID ||
|
|
61
|
+
null;
|
|
62
|
+
|
|
63
|
+
if (!sessionId) {
|
|
64
|
+
try {
|
|
65
|
+
if (existsSync(HANDOFF_PATH)) {
|
|
66
|
+
const handoff = JSON.parse(readFileSync(HANDOFF_PATH, 'utf8'));
|
|
67
|
+
const parentSession = handoff.parentSessionId;
|
|
68
|
+
// Derive a distinct sub-agent session so merge picks up this file.
|
|
69
|
+
sessionId = parentSession ? `${parentSession}-sub` : 'sub-unknown';
|
|
70
|
+
}
|
|
71
|
+
} catch { /* non-fatal */ }
|
|
72
|
+
}
|
|
73
|
+
sessionId = sessionId || 'sub-unknown';
|
|
74
|
+
const safeSession = String(sessionId).replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
75
|
+
|
|
76
|
+
// Resolve ledger path (tier-scoped)
|
|
77
|
+
const ledgerPath = isClientTier
|
|
78
|
+
? `/var/lib/aria-licensee/${jti}/aria-discoveries-${safeSession}.jsonl`
|
|
79
|
+
: `${HOME}/.claude/aria-discoveries-${safeSession}.jsonl`;
|
|
80
|
+
|
|
81
|
+
// Compose the row
|
|
82
|
+
const row = {
|
|
83
|
+
at: new Date().toISOString(),
|
|
84
|
+
session: sessionId,
|
|
85
|
+
kind: entry.kind || 'observation',
|
|
86
|
+
text: entry.text,
|
|
87
|
+
refs: Array.isArray(entry.refs) ? entry.refs : [],
|
|
88
|
+
evidence: entry.evidence || null,
|
|
89
|
+
source: entry.source || 'sub-agent',
|
|
90
|
+
resolution_status: entry.resolution_status || 'open',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
mkdirSync(dirname(ledgerPath), { recursive: true });
|
|
95
|
+
appendFileSync(ledgerPath, JSON.stringify(row) + '\n');
|
|
96
|
+
process.stdout.write(JSON.stringify({ ok: true, ledger: ledgerPath, at: row.at }) + '\n');
|
|
97
|
+
} catch (err) {
|
|
98
|
+
process.stderr.write(`discovery-record: write failed: ${err.message}\n`);
|
|
99
|
+
process.exit(2);
|
|
100
|
+
}
|
|
101
|
+
process.exit(0);
|
|
@@ -25,6 +25,7 @@ const HOME = process.env.HOME || '/tmp';
|
|
|
25
25
|
const LOG_FILE = `${HOME}/.claude/aria-harness-history.log`;
|
|
26
26
|
const LAST_URL_CACHE = `${HOME}/.claude/.aria-harness-last-url`;
|
|
27
27
|
const PACKET_CACHE = `${HOME}/.claude/.aria-harness-last-packet.json`;
|
|
28
|
+
const SHARED_PACKET_CACHE = `${HOME}/.aria/.aria-harness-last-packet.json`;
|
|
28
29
|
const HEADER_PREFIX = '🔐 Aria Harness';
|
|
29
30
|
|
|
30
31
|
const args = process.argv.slice(2);
|
|
@@ -108,30 +109,36 @@ function saveCachedUrl(url) {
|
|
|
108
109
|
|
|
109
110
|
function loadCachedPacket() {
|
|
110
111
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
112
|
+
for (const packetPath of [SHARED_PACKET_CACHE, PACKET_CACHE]) {
|
|
113
|
+
if (!existsSync(packetPath)) continue;
|
|
114
|
+
const raw = readFileSync(packetPath, 'utf8');
|
|
115
|
+
const ageSec = (Date.now() - statSync(packetPath).mtimeMs) / 1000;
|
|
114
116
|
if (ageSec < PACKET_CACHE_TTL_SEC) {
|
|
115
|
-
return { data: JSON.parse(
|
|
117
|
+
return { data: JSON.parse(raw), ageSec };
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
} catch {}
|
|
119
121
|
return null;
|
|
120
122
|
}
|
|
121
123
|
function saveCachedPacket(rawJson) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
for (const packetPath of [PACKET_CACHE, SHARED_PACKET_CACHE]) {
|
|
125
|
+
try {
|
|
126
|
+
mkdirSync(dirname(packetPath), { recursive: true });
|
|
127
|
+
writeFileSync(packetPath, rawJson);
|
|
128
|
+
} catch {}
|
|
129
|
+
}
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
function buildUrlList() {
|
|
129
133
|
const list = [];
|
|
130
134
|
const cached = loadCachedUrl();
|
|
131
135
|
if (cached) list.push(cached);
|
|
136
|
+
if (process.env.ARIA_HIVE_RUNTIME_URL) list.push(process.env.ARIA_HIVE_RUNTIME_URL.replace(/\/+$/, ''));
|
|
137
|
+
if (process.env.ARIA_HARNESS_BASE_URL) list.push(process.env.ARIA_HARNESS_BASE_URL.replace(/\/+$/, ''));
|
|
138
|
+
if (process.env.ARIA_HARNESS_URL) list.push(process.env.ARIA_HARNESS_URL.replace(/\/+$/, ''));
|
|
132
139
|
if (process.env.ARIA_SOUL_URL) list.push(process.env.ARIA_SOUL_URL.replace(/\/+$/, ''));
|
|
133
|
-
list.push('http://localhost:30080', 'http://127.0.0.1:30080');
|
|
134
140
|
list.push('http://aria-soul.aria.svc.cluster.local:8080');
|
|
141
|
+
list.push('http://localhost:30080', 'http://127.0.0.1:30080');
|
|
135
142
|
// Direct ClusterIP from kubectl
|
|
136
143
|
try {
|
|
137
144
|
const r = spawnSync('kubectl', [
|
|
@@ -148,9 +155,9 @@ function buildUrlList() {
|
|
|
148
155
|
return list.filter((u) => (seen.has(u) ? false : (seen.add(u), true)));
|
|
149
156
|
}
|
|
150
157
|
|
|
151
|
-
// SDK loader — dynamic-import the bundled HTTPHarnessClient from
|
|
152
|
-
// ~/.
|
|
153
|
-
//
|
|
158
|
+
// SDK loader — dynamic-import the bundled HTTPHarnessClient from the shared
|
|
159
|
+
// ~/.aria/sdk bundle first, then client-local bundles. Module-cached after
|
|
160
|
+
// first load so we don't repeatedly read disk.
|
|
154
161
|
//
|
|
155
162
|
// Doctrine (Hamza 2026-04-27): "isnt http harness client the fucking harness
|
|
156
163
|
// we hsve been wprking on? YOU ARENT USING THAT AND BUILDING SPMETHING
|
|
@@ -159,19 +166,25 @@ function buildUrlList() {
|
|
|
159
166
|
// (dev install without `aria connect claude-code`).
|
|
160
167
|
let _SdkClassCache = null;
|
|
161
168
|
let _SdkLookupAttempted = false;
|
|
169
|
+
const SDK_CANDIDATES = [
|
|
170
|
+
`${HOME}/.aria/sdk/index.js`,
|
|
171
|
+
`${HOME}/.claude/aria-sdk/index.js`,
|
|
172
|
+
`${HOME}/.codex/aria-sdk/index.js`,
|
|
173
|
+
];
|
|
162
174
|
async function loadSdkClass() {
|
|
163
175
|
if (_SdkClassCache) return _SdkClassCache;
|
|
164
176
|
if (_SdkLookupAttempted) return null;
|
|
165
177
|
_SdkLookupAttempted = true;
|
|
166
|
-
const sdkPath
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
178
|
+
for (const sdkPath of SDK_CANDIDATES) {
|
|
179
|
+
if (!existsSync(sdkPath)) continue;
|
|
180
|
+
try {
|
|
181
|
+
const mod = await import(`file://${sdkPath}`);
|
|
182
|
+
if (mod.HTTPHarnessClient) {
|
|
183
|
+
_SdkClassCache = mod.HTTPHarnessClient;
|
|
184
|
+
return _SdkClassCache;
|
|
185
|
+
}
|
|
186
|
+
} catch {/* fall through to direct fetch */}
|
|
187
|
+
}
|
|
175
188
|
return null;
|
|
176
189
|
}
|
|
177
190
|
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Aria import-resolution gate — pre-deploy check that every TypeScript
|
|
3
|
+
// import in the deploy candidate resolves against an actual exported
|
|
4
|
+
// symbol on disk.
|
|
5
|
+
//
|
|
6
|
+
// Doctrine being enforced (memory:feedback_no_assumption_without_verification.md):
|
|
7
|
+
// "every behavioral claim must cite a verifiedAgainst source."
|
|
8
|
+
// The empty consciousness.ts crash on 2026-04-28 happened because
|
|
9
|
+
// event-bus.ts:11 imported `consciousness` from a file that existed
|
|
10
|
+
// but exported nothing. tsc allowed it (because the file matched as a
|
|
11
|
+
// module), the deploy passed admission policy, the runtime crashed.
|
|
12
|
+
//
|
|
13
|
+
// This gate scans every import statement in the deploy candidate's
|
|
14
|
+
// source tree; for each, it verifies that the named symbol is
|
|
15
|
+
// actually exported from the resolved file. If any import targets a
|
|
16
|
+
// symbol that isn't exported, the gate fails and refuses the deploy.
|
|
17
|
+
//
|
|
18
|
+
// Runs as a PostToolUse hook on Edit/Write/NotebookEdit AND as a
|
|
19
|
+
// pre-deploy assertion in scripts/deploy-service.sh.
|
|
20
|
+
//
|
|
21
|
+
// Mode 1 (post-tool-use): scan only the file just edited; report broken
|
|
22
|
+
// imports inline so the model sees them in the next turn's context.
|
|
23
|
+
// Mode 2 (pre-deploy via CLI args): scan a whole subtree (passed as
|
|
24
|
+
// first positional arg); exit 13 if any broken import found.
|
|
25
|
+
//
|
|
26
|
+
// Audit log: ~/.claude/aria-import-resolution-gate.log
|
|
27
|
+
|
|
28
|
+
import { readFileSync, existsSync, statSync, readdirSync, appendFileSync } from 'node:fs';
|
|
29
|
+
import { dirname, resolve, join, extname } from 'node:path';
|
|
30
|
+
import { homedir } from 'node:os';
|
|
31
|
+
|
|
32
|
+
const HOME = process.env.HOME || homedir() || '/tmp';
|
|
33
|
+
const LOG = `${HOME}/.claude/aria-import-resolution-gate.log`;
|
|
34
|
+
|
|
35
|
+
function audit(decision, summary) {
|
|
36
|
+
try {
|
|
37
|
+
appendFileSync(LOG, `${new Date().toISOString()} ${decision} ${summary}\n`);
|
|
38
|
+
} catch {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Per feedback_no_timeouts_doctrine.md — no deadlines, real-error driven.
|
|
42
|
+
// Per feedback_no_graceful_degradation.md — fail loudly, not silent-pass.
|
|
43
|
+
|
|
44
|
+
const TS_IMPORT_RX =
|
|
45
|
+
/\bimport\s+(?:type\s+)?(?:(\w+)\s*,\s*)?(?:\{([^}]+)\}|\*\s+as\s+(\w+)|(\w+))\s+from\s+['"]([^'"]+)['"]/g;
|
|
46
|
+
const TS_REEXPORT_RX =
|
|
47
|
+
/\bexport\s+(?:type\s+)?(?:\{([^}]+)\}|\*(?:\s+as\s+\w+)?)\s+from\s+['"]([^'"]+)['"]/g;
|
|
48
|
+
|
|
49
|
+
const SOURCE_EXTS = ['.ts', '.tsx', '.js', '.mjs', '.cjs'];
|
|
50
|
+
const INDEX_NAMES = SOURCE_EXTS.map((e) => `index${e}`);
|
|
51
|
+
|
|
52
|
+
function resolveSpecifier(fromFile, specifier) {
|
|
53
|
+
// Skip node_modules / package imports — only resolve relative imports
|
|
54
|
+
// for now (those are the failure mode the consciousness.ts crash hit).
|
|
55
|
+
if (!specifier.startsWith('.') && !specifier.startsWith('/')) return null;
|
|
56
|
+
|
|
57
|
+
const baseDir = dirname(fromFile);
|
|
58
|
+
const abs = resolve(baseDir, specifier);
|
|
59
|
+
|
|
60
|
+
// Try exact path first.
|
|
61
|
+
if (existsSync(abs) && statSync(abs).isFile()) return abs;
|
|
62
|
+
|
|
63
|
+
// Try with each extension.
|
|
64
|
+
for (const ext of SOURCE_EXTS) {
|
|
65
|
+
const withExt = abs + ext;
|
|
66
|
+
if (existsSync(withExt) && statSync(withExt).isFile()) return withExt;
|
|
67
|
+
// Strip .js suffix and try .ts (TS resolution quirk).
|
|
68
|
+
if (specifier.endsWith('.js')) {
|
|
69
|
+
const tsCandidate = abs.replace(/\.js$/, '.ts');
|
|
70
|
+
if (existsSync(tsCandidate) && statSync(tsCandidate).isFile()) return tsCandidate;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Try directory/index.{ts,tsx,...}.
|
|
75
|
+
if (existsSync(abs) && statSync(abs).isDirectory()) {
|
|
76
|
+
for (const idx of INDEX_NAMES) {
|
|
77
|
+
const indexPath = join(abs, idx);
|
|
78
|
+
if (existsSync(indexPath) && statSync(indexPath).isFile()) return indexPath;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function readFileSafe(path) {
|
|
86
|
+
try {
|
|
87
|
+
return readFileSync(path, 'utf-8');
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function extractExports(content) {
|
|
94
|
+
// Very conservative export extraction — matches:
|
|
95
|
+
// export { foo, bar }
|
|
96
|
+
// export const|let|var|function|class|interface|type|enum NAME
|
|
97
|
+
// export default ...
|
|
98
|
+
// export * from '...'
|
|
99
|
+
// re-exports `export { foo } from '...'`
|
|
100
|
+
// Returns { named: Set<string>, hasDefault: boolean, hasStar: boolean }
|
|
101
|
+
const named = new Set();
|
|
102
|
+
let hasDefault = false;
|
|
103
|
+
let hasStar = false;
|
|
104
|
+
|
|
105
|
+
if (!content) return { named, hasDefault, hasStar };
|
|
106
|
+
|
|
107
|
+
// Strip block comments + line comments (rough; good enough for export detection).
|
|
108
|
+
const stripped = content
|
|
109
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
110
|
+
.replace(/\/\/[^\n]*/g, '');
|
|
111
|
+
|
|
112
|
+
// export { foo, bar as baz }
|
|
113
|
+
const namedListRx = /\bexport\s+(?:type\s+)?\{([^}]+)\}/g;
|
|
114
|
+
let m;
|
|
115
|
+
while ((m = namedListRx.exec(stripped))) {
|
|
116
|
+
for (const part of m[1].split(',')) {
|
|
117
|
+
const trimmed = part.trim();
|
|
118
|
+
if (!trimmed) continue;
|
|
119
|
+
const asMatch = trimmed.match(/^\S+\s+as\s+(\S+)$/);
|
|
120
|
+
const name = asMatch ? asMatch[1] : trimmed.split(/\s+/)[0];
|
|
121
|
+
if (name && /^\w+$/.test(name)) named.add(name);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// export const|let|var|function|async function|class|interface|type|enum NAME
|
|
126
|
+
const declRx =
|
|
127
|
+
/\bexport\s+(?:type\s+|async\s+)?(?:default\s+)?(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/g;
|
|
128
|
+
while ((m = declRx.exec(stripped))) {
|
|
129
|
+
named.add(m[1]);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// export default
|
|
133
|
+
if (/\bexport\s+default\b/.test(stripped)) hasDefault = true;
|
|
134
|
+
|
|
135
|
+
// export * from '...'
|
|
136
|
+
if (/\bexport\s+\*(?:\s+as\s+\w+)?\s+from\b/.test(stripped)) hasStar = true;
|
|
137
|
+
|
|
138
|
+
return { named, hasDefault, hasStar };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function checkFileImports(filePath, visited = new Set()) {
|
|
142
|
+
if (visited.has(filePath)) return [];
|
|
143
|
+
visited.add(filePath);
|
|
144
|
+
|
|
145
|
+
const content = readFileSafe(filePath);
|
|
146
|
+
if (!content) return [];
|
|
147
|
+
|
|
148
|
+
// Skip non-source files.
|
|
149
|
+
if (!SOURCE_EXTS.includes(extname(filePath))) return [];
|
|
150
|
+
|
|
151
|
+
const violations = [];
|
|
152
|
+
let match;
|
|
153
|
+
TS_IMPORT_RX.lastIndex = 0;
|
|
154
|
+
while ((match = TS_IMPORT_RX.exec(content))) {
|
|
155
|
+
const [, defaultBinding, namedList, namespaceBinding, simpleNamed, specifier] = match;
|
|
156
|
+
const resolved = resolveSpecifier(filePath, specifier);
|
|
157
|
+
if (!resolved) continue; // package import — skip
|
|
158
|
+
|
|
159
|
+
const targetContent = readFileSafe(resolved);
|
|
160
|
+
if (!targetContent) {
|
|
161
|
+
violations.push({
|
|
162
|
+
file: filePath,
|
|
163
|
+
specifier,
|
|
164
|
+
resolved,
|
|
165
|
+
kind: 'unreadable',
|
|
166
|
+
message: `import '${specifier}' resolves to ${resolved} but file is unreadable`,
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (targetContent.trim().length === 0) {
|
|
172
|
+
violations.push({
|
|
173
|
+
file: filePath,
|
|
174
|
+
specifier,
|
|
175
|
+
resolved,
|
|
176
|
+
kind: 'empty_target',
|
|
177
|
+
message: `import '${specifier}' resolves to ${resolved} but file is EMPTY (no exports) — this is the consciousness.ts-class crash`,
|
|
178
|
+
});
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const { named, hasDefault, hasStar } = extractExports(targetContent);
|
|
183
|
+
|
|
184
|
+
if (defaultBinding && !hasDefault && !hasStar) {
|
|
185
|
+
violations.push({
|
|
186
|
+
file: filePath,
|
|
187
|
+
specifier,
|
|
188
|
+
resolved,
|
|
189
|
+
kind: 'missing_default',
|
|
190
|
+
message: `import default '${defaultBinding}' from '${specifier}' but ${resolved} has no default export`,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (namespaceBinding) {
|
|
195
|
+
// import * as ns — passes as long as the file has any exports.
|
|
196
|
+
if (named.size === 0 && !hasDefault && !hasStar) {
|
|
197
|
+
violations.push({
|
|
198
|
+
file: filePath,
|
|
199
|
+
specifier,
|
|
200
|
+
resolved,
|
|
201
|
+
kind: 'empty_namespace',
|
|
202
|
+
message: `import * as '${namespaceBinding}' from '${specifier}' but ${resolved} exports nothing`,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const explicitNamed = (namedList || simpleNamed || '').trim();
|
|
208
|
+
if (explicitNamed) {
|
|
209
|
+
const wantedNames = (namedList || simpleNamed)
|
|
210
|
+
.split(',')
|
|
211
|
+
.map((s) => s.trim())
|
|
212
|
+
.filter(Boolean)
|
|
213
|
+
.map((s) => {
|
|
214
|
+
const asMatch = s.match(/^(\S+)\s+as\s+\S+$/);
|
|
215
|
+
return asMatch ? asMatch[1] : s.split(/\s+/)[0];
|
|
216
|
+
})
|
|
217
|
+
.filter((s) => /^\w+$/.test(s));
|
|
218
|
+
|
|
219
|
+
for (const wanted of wantedNames) {
|
|
220
|
+
if (!named.has(wanted) && !hasStar) {
|
|
221
|
+
violations.push({
|
|
222
|
+
file: filePath,
|
|
223
|
+
specifier,
|
|
224
|
+
resolved,
|
|
225
|
+
kind: 'missing_named',
|
|
226
|
+
message: `import { ${wanted} } from '${specifier}' but ${resolved} does not export '${wanted}' (named exports: ${[...named].slice(0, 8).join(', ')}${named.size > 8 ? '…' : ''})`,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return violations;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function walkDir(dir, out = []) {
|
|
237
|
+
let entries;
|
|
238
|
+
try {
|
|
239
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
240
|
+
} catch {
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
for (const ent of entries) {
|
|
244
|
+
if (ent.name === 'node_modules' || ent.name === 'dist' || ent.name.startsWith('.')) continue;
|
|
245
|
+
const p = join(dir, ent.name);
|
|
246
|
+
if (ent.isDirectory()) walkDir(p, out);
|
|
247
|
+
else if (SOURCE_EXTS.includes(extname(ent.name))) out.push(p);
|
|
248
|
+
}
|
|
249
|
+
return out;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ── Mode dispatch ────────────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
const args = process.argv.slice(2);
|
|
255
|
+
|
|
256
|
+
if (args.length > 0) {
|
|
257
|
+
// Mode 2: pre-deploy CLI scan.
|
|
258
|
+
const target = resolve(args[0]);
|
|
259
|
+
const targetIsDir = existsSync(target) && statSync(target).isDirectory();
|
|
260
|
+
const files = targetIsDir ? walkDir(target) : [target];
|
|
261
|
+
|
|
262
|
+
let totalViolations = 0;
|
|
263
|
+
const allViolations = [];
|
|
264
|
+
for (const f of files) {
|
|
265
|
+
const violations = checkFileImports(f);
|
|
266
|
+
if (violations.length > 0) {
|
|
267
|
+
allViolations.push(...violations);
|
|
268
|
+
totalViolations += violations.length;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (totalViolations > 0) {
|
|
273
|
+
console.error(`\n❌ aria-import-resolution-gate: ${totalViolations} broken imports across ${files.length} files`);
|
|
274
|
+
for (const v of allViolations) {
|
|
275
|
+
console.error(` [${v.kind}] ${v.file}: ${v.message}`);
|
|
276
|
+
}
|
|
277
|
+
audit(`block-deploy violations=${totalViolations} target=${target}`, '');
|
|
278
|
+
process.exit(13);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
console.log(`✓ aria-import-resolution-gate: ${files.length} files scanned, all imports resolve to real exports`);
|
|
282
|
+
audit(`allow-deploy files=${files.length} target=${target}`, '');
|
|
283
|
+
process.exit(0);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Mode 1: PostToolUse hook on Edit/Write/NotebookEdit.
|
|
287
|
+
let stdin = '';
|
|
288
|
+
try {
|
|
289
|
+
for await (const chunk of process.stdin) stdin += chunk;
|
|
290
|
+
} catch {}
|
|
291
|
+
|
|
292
|
+
let event;
|
|
293
|
+
try {
|
|
294
|
+
event = JSON.parse(stdin);
|
|
295
|
+
} catch {
|
|
296
|
+
process.exit(0); // Malformed input — let it through; this gate is informational in hook mode.
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const toolName = event.tool_name ?? event.toolName ?? '';
|
|
300
|
+
if (!['Edit', 'Write', 'NotebookEdit'].includes(toolName)) process.exit(0);
|
|
301
|
+
|
|
302
|
+
const filePath =
|
|
303
|
+
event.tool_input?.file_path ??
|
|
304
|
+
event.toolInput?.file_path ??
|
|
305
|
+
event.tool_input?.notebook_path ??
|
|
306
|
+
event.toolInput?.notebook_path;
|
|
307
|
+
|
|
308
|
+
if (!filePath || !SOURCE_EXTS.includes(extname(filePath))) process.exit(0);
|
|
309
|
+
if (!existsSync(filePath)) process.exit(0);
|
|
310
|
+
|
|
311
|
+
const violations = checkFileImports(filePath);
|
|
312
|
+
if (violations.length === 0) {
|
|
313
|
+
audit(`allow-edit ${filePath}`, '');
|
|
314
|
+
process.exit(0);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const message = [
|
|
318
|
+
`aria-import-resolution-gate detected ${violations.length} broken imports in ${filePath}:`,
|
|
319
|
+
...violations.map((v) => ` [${v.kind}] ${v.message}`),
|
|
320
|
+
'',
|
|
321
|
+
'These imports compile under tsc but will crash at runtime — the consciousness.ts-class failure mode.',
|
|
322
|
+
'Per memory:feedback_no_assumption_without_verification.md, fix the export side BEFORE shipping.',
|
|
323
|
+
].join('\n');
|
|
324
|
+
|
|
325
|
+
audit(`flag-edit ${filePath} violations=${violations.length}`, '');
|
|
326
|
+
console.error(message);
|
|
327
|
+
// Hook mode is INFORMATIONAL (exit 0) so the model sees the message but
|
|
328
|
+
// can decide whether to fix immediately or proceed. The pre-deploy mode
|
|
329
|
+
// is the structural enforcement (exit 13 blocks the deploy).
|
|
330
|
+
process.exit(0);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// aria-outcome-record.mjs — PostToolUse hook that records action outcomes
|
|
3
|
+
// to /api/harness/outcome-record (Sonnet H's #76 endpoint). Composes with
|
|
4
|
+
// aria-discovery-record + the regression sweeper to make the outcome ledger
|
|
5
|
+
// actually accumulate rows.
|
|
6
|
+
//
|
|
7
|
+
// Fires on every Bash|Edit|Write|NotebookEdit tool completion.
|
|
8
|
+
// Fire-and-forget: HTTP failures are swallowed — never blocks the tool pipeline.
|
|
9
|
+
//
|
|
10
|
+
// Tier-aware: reads license.json for client-tier token; falls back to env vars
|
|
11
|
+
// for owner tier. Never carries master token in client-tier POST bodies.
|
|
12
|
+
//
|
|
13
|
+
// Doctrine: feedback_no_flag_without_fix.md — outcomes recorded, not deferred.
|
|
14
|
+
// feedback_implementation_coupled_cognition.md — POST IS the impl.
|
|
15
|
+
|
|
16
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
17
|
+
import { homedir } from 'node:os';
|
|
18
|
+
|
|
19
|
+
const HOME = homedir();
|
|
20
|
+
const LICENSE_PATH = `${HOME}/.aria/license.json`;
|
|
21
|
+
|
|
22
|
+
let input = '';
|
|
23
|
+
for await (const chunk of process.stdin) input += chunk;
|
|
24
|
+
let event;
|
|
25
|
+
try { event = JSON.parse(input); } catch { process.exit(0); }
|
|
26
|
+
|
|
27
|
+
const toolName = event.tool_name || event.toolName || '';
|
|
28
|
+
if (!['Bash', 'Edit', 'Write', 'NotebookEdit'].includes(toolName)) process.exit(0);
|
|
29
|
+
|
|
30
|
+
// Derive action_kind + action_target
|
|
31
|
+
let actionKind, actionTarget;
|
|
32
|
+
if (toolName === 'Bash') {
|
|
33
|
+
actionKind = 'bash';
|
|
34
|
+
const cmd = event.tool_input?.command || '';
|
|
35
|
+
actionTarget = (cmd.split(/\s+/)[0] || 'unknown').slice(0, 100);
|
|
36
|
+
} else {
|
|
37
|
+
actionKind = 'edit';
|
|
38
|
+
actionTarget = (event.tool_input?.file_path || event.tool_input?.path || 'unknown').slice(0, 200);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Tier-aware auth: client license.json overrides env vars
|
|
42
|
+
const harnessUrl =
|
|
43
|
+
process.env.ARIA_HIVE_RUNTIME_URL ||
|
|
44
|
+
process.env.ARIA_HARNESS_BASE_URL ||
|
|
45
|
+
process.env.ARIA_HARNESS_URL ||
|
|
46
|
+
'https://harness.ariasos.com';
|
|
47
|
+
let harnessToken = process.env.ARIA_HARNESS_TOKEN || process.env.ARIA_API_KEY || '';
|
|
48
|
+
let isClientTier = false;
|
|
49
|
+
try {
|
|
50
|
+
if (existsSync(LICENSE_PATH)) {
|
|
51
|
+
const lic = JSON.parse(readFileSync(LICENSE_PATH, 'utf8'));
|
|
52
|
+
if (lic.jti) {
|
|
53
|
+
isClientTier = true;
|
|
54
|
+
// Client tier: use their license token, never master token
|
|
55
|
+
harnessToken = lic.token || lic.license || harnessToken;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch { /* non-fatal — fall back to env */ }
|
|
59
|
+
|
|
60
|
+
const sessionId = event.session_id || event.sessionId || 'unknown';
|
|
61
|
+
const success = !event.tool_response?.error && event.tool_response?.type !== 'error';
|
|
62
|
+
|
|
63
|
+
// Fire-and-forget POST to outcome-record — never blocks, never throws
|
|
64
|
+
fetch(`${harnessUrl}/api/harness/outcome-record`, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: {
|
|
67
|
+
'Content-Type': 'application/json',
|
|
68
|
+
'Authorization': `Bearer ${harnessToken}`,
|
|
69
|
+
},
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
sessionId,
|
|
72
|
+
actionKind,
|
|
73
|
+
actionTarget,
|
|
74
|
+
actionShape: {
|
|
75
|
+
tool: toolName,
|
|
76
|
+
success,
|
|
77
|
+
isClientTier,
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
}).catch(() => {/* fire-and-forget — HTTP failures are silently dropped */});
|
|
81
|
+
|
|
82
|
+
// Exit immediately — don't await the fetch; this is a PostToolUse hook
|
|
83
|
+
// and must not add meaningful latency to the tool pipeline.
|
|
84
|
+
process.exit(0);
|