@aria_asi/cli 0.2.32 → 0.2.34
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/codebase-awareness.d.ts +8 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.js +126 -71
- package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +98 -0
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +91 -24
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +26 -8
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +60 -1
- package/dist/assets/hooks/aria-stop-gate.mjs +69 -3
- package/dist/assets/hooks/doctrine_trigger_map.json +43 -0
- package/dist/assets/hooks/lib/domain-output-quality.mjs +103 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +14 -0
- package/dist/assets/opencode-plugins/harness-context/index.js +1 -1
- package/dist/assets/opencode-plugins/harness-gate/index.js +114 -10
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +39 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +234 -139
- package/dist/assets/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -0
- package/dist/runtime/codex-bridge.mjs +71 -8
- 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/harness-daemon.mjs +50 -2
- 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 +48 -0
- package/dist/runtime/sdk/index.js +140 -1
- 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/runtime/service.mjs +339 -10
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/index.d.ts +48 -0
- package/dist/sdk/index.js +140 -1
- 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 +26 -8
- package/hooks/aria-pre-tool-gate.mjs +60 -1
- package/hooks/aria-stop-gate.mjs +69 -3
- package/hooks/doctrine_trigger_map.json +43 -0
- package/hooks/lib/domain-output-quality.mjs +103 -0
- package/hooks/lib/skill-autoload-gate.mjs +14 -0
- package/opencode-plugins/harness-context/index.js +1 -1
- package/opencode-plugins/harness-gate/index.js +114 -10
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -0
- package/opencode-plugins/harness-outcome/index.js +39 -0
- package/opencode-plugins/harness-stop/index.js +234 -139
- package/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -0
- package/package.json +12 -5
- package/runtime-src/codex-bridge.mjs +71 -8
- package/runtime-src/harness-daemon.mjs +50 -2
- package/runtime-src/service.mjs +339 -10
- package/scripts/bundle-sdk.mjs +2 -0
- package/scripts/self-test-harness-gates.mjs +79 -0
- package/src/connectors/codebase-awareness.ts +141 -77
- package/src/connectors/codex.ts +98 -0
- package/src/setup-wizard.ts +105 -25
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Smoke test: Phase 11 #59 — canonical lens labeling
|
|
3
|
+
//
|
|
4
|
+
// Verifies that aria-pre-tool-gate.mjs and aria-stop-gate.mjs:
|
|
5
|
+
// 1. Show canonical Arabic lens names (nur, mizan, etc.) when the harness
|
|
6
|
+
// packet has isHamza/hamza=true (OWNER tier).
|
|
7
|
+
// 2. Preserve those same canonical labels on client-surface execution too.
|
|
8
|
+
// 3. Gate enforcement (block on insufficient cognition) fires in both
|
|
9
|
+
// tiers without renaming the lenses.
|
|
10
|
+
//
|
|
11
|
+
// Usage: node hooks/test-tier-lens-labeling.mjs
|
|
12
|
+
// Exit: 0 = all assertions passed, 1 = failure
|
|
13
|
+
|
|
14
|
+
import { spawnSync } from 'node:child_process';
|
|
15
|
+
import { writeFileSync, mkdirSync, existsSync, unlinkSync, readFileSync } from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
|
|
19
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const PRE_TOOL_HOOK = path.join(HERE, 'aria-pre-tool-gate.mjs');
|
|
21
|
+
const STOP_HOOK = path.join(HERE, 'aria-stop-gate.mjs');
|
|
22
|
+
const HOME = process.env.HOME || '/tmp';
|
|
23
|
+
const CLAUDE_DIR = `${HOME}/.claude`;
|
|
24
|
+
const PACKET_PATH = `${CLAUDE_DIR}/.aria-harness-last-packet.json`;
|
|
25
|
+
|
|
26
|
+
// ── Canonical label set ────────────────────────────────────────────────────
|
|
27
|
+
const CANONICAL = ['nur', 'mizan', 'hikma', 'tafakkur', 'tadabbur', 'ilham', 'wahi', 'firasah'];
|
|
28
|
+
|
|
29
|
+
// ── Assertion helpers ───────────────────────────────────────────────────────
|
|
30
|
+
let passed = 0;
|
|
31
|
+
let failed = 0;
|
|
32
|
+
|
|
33
|
+
function assert(label, condition, detail) {
|
|
34
|
+
if (condition) {
|
|
35
|
+
console.log(` PASS ${label}`);
|
|
36
|
+
passed++;
|
|
37
|
+
} else {
|
|
38
|
+
console.error(` FAIL ${label}`);
|
|
39
|
+
if (detail !== undefined) console.error(` detail: ${String(detail).slice(0, 300)}`);
|
|
40
|
+
failed++;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ── Packet helpers ──────────────────────────────────────────────────────────
|
|
45
|
+
// Save/restore the real packet so running this test doesn't corrupt live state.
|
|
46
|
+
let originalPacketContent = null;
|
|
47
|
+
|
|
48
|
+
function savePacket() {
|
|
49
|
+
try {
|
|
50
|
+
if (existsSync(PACKET_PATH)) {
|
|
51
|
+
originalPacketContent = readFileSync(PACKET_PATH, 'utf8');
|
|
52
|
+
} else {
|
|
53
|
+
originalPacketContent = null;
|
|
54
|
+
}
|
|
55
|
+
} catch { originalPacketContent = null; }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function restorePacket() {
|
|
59
|
+
try {
|
|
60
|
+
if (originalPacketContent !== null) {
|
|
61
|
+
writeFileSync(PACKET_PATH, originalPacketContent);
|
|
62
|
+
} else if (existsSync(PACKET_PATH)) {
|
|
63
|
+
unlinkSync(PACKET_PATH);
|
|
64
|
+
}
|
|
65
|
+
} catch {}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function writeOwnerPacket() {
|
|
69
|
+
// contractGate.signals.hamza === true → OWNER tier
|
|
70
|
+
const packet = {
|
|
71
|
+
ok: true,
|
|
72
|
+
stage: 'preflight',
|
|
73
|
+
harness: 'surface=platform:hamza group:false hamza:true',
|
|
74
|
+
contractGate: {
|
|
75
|
+
signals: { hamza: true },
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
if (!existsSync(CLAUDE_DIR)) mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
79
|
+
writeFileSync(PACKET_PATH, JSON.stringify(packet));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function writeClientPacket() {
|
|
83
|
+
// contractGate.signals.hamza === "false" (string) → CLIENT tier
|
|
84
|
+
const packet = {
|
|
85
|
+
ok: true,
|
|
86
|
+
stage: 'preflight',
|
|
87
|
+
harness: 'surface=platform:client group:false hamza:false',
|
|
88
|
+
contractGate: {
|
|
89
|
+
signals: { hamza: 'false' },
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
if (!existsSync(CLAUDE_DIR)) mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
93
|
+
writeFileSync(PACKET_PATH, JSON.stringify(packet));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── Transcript helpers ──────────────────────────────────────────────────────
|
|
97
|
+
// Write a minimal transcript where the most recent assistant turn has NO
|
|
98
|
+
// cognition block — triggering a block decision.
|
|
99
|
+
function writeEmptyTranscript(transcriptPath) {
|
|
100
|
+
const entries = [
|
|
101
|
+
// User message
|
|
102
|
+
JSON.stringify({
|
|
103
|
+
message: { role: 'user', content: [{ type: 'text', text: 'Run a build command' }] },
|
|
104
|
+
}),
|
|
105
|
+
// Assistant text with no cognition
|
|
106
|
+
JSON.stringify({
|
|
107
|
+
message: {
|
|
108
|
+
role: 'assistant',
|
|
109
|
+
content: [{ type: 'text', text: 'I will run the build.' }],
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
];
|
|
113
|
+
writeFileSync(transcriptPath, entries.join('\n'));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Write a transcript with a Stop-gate-triggering assistant response (long,
|
|
117
|
+
// decision-signal, but no cognition).
|
|
118
|
+
function writeNoCognitionStopTranscript(transcriptPath) {
|
|
119
|
+
const longText = 'I recommend shipping this feature immediately because the test suite is green and the build passed. Let me proceed with the deployment now. ' +
|
|
120
|
+
'The plan is as follows: first we build, then we deploy, then we verify. I would suggest we move forward without delay.';
|
|
121
|
+
const entries = [
|
|
122
|
+
JSON.stringify({
|
|
123
|
+
message: { role: 'user', content: [{ type: 'text', text: 'Should I ship?' }] },
|
|
124
|
+
}),
|
|
125
|
+
JSON.stringify({
|
|
126
|
+
message: {
|
|
127
|
+
role: 'assistant',
|
|
128
|
+
content: [{ type: 'text', text: longText }],
|
|
129
|
+
},
|
|
130
|
+
}),
|
|
131
|
+
];
|
|
132
|
+
writeFileSync(transcriptPath, entries.join('\n'));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ── Run hook helpers ────────────────────────────────────────────────────────
|
|
136
|
+
// Use a non-destructive but non-trivial command that skips the verify path
|
|
137
|
+
// and goes straight to cognition-missing, where lens labels appear.
|
|
138
|
+
function runPreToolGate(transcriptPath, command = 'npm run build --workspace=packages/aria-connector') {
|
|
139
|
+
const event = JSON.stringify({
|
|
140
|
+
tool_name: 'Bash',
|
|
141
|
+
tool_input: { command },
|
|
142
|
+
transcript_path: transcriptPath,
|
|
143
|
+
session_id: `test-tier-${Date.now()}`,
|
|
144
|
+
});
|
|
145
|
+
return spawnSync(process.execPath, [PRE_TOOL_HOOK], {
|
|
146
|
+
input: event,
|
|
147
|
+
encoding: 'utf8',
|
|
148
|
+
timeout: 10000,
|
|
149
|
+
env: {
|
|
150
|
+
...process.env,
|
|
151
|
+
HOME,
|
|
152
|
+
ARIA_COGNITION_PUSH: 'off', // silence network push
|
|
153
|
+
ARIA_HARNESS_TOKEN: '', // no outbound harness calls
|
|
154
|
+
ARIA_BINDING_ENABLED: 'false', // disable binding gate — isolate cognition test
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function runStopGate(transcriptPath) {
|
|
160
|
+
const event = JSON.stringify({
|
|
161
|
+
tool_name: 'Stop',
|
|
162
|
+
transcript_path: transcriptPath,
|
|
163
|
+
session_id: `test-tier-${Date.now()}`,
|
|
164
|
+
});
|
|
165
|
+
return spawnSync(process.execPath, [STOP_HOOK], {
|
|
166
|
+
input: event,
|
|
167
|
+
encoding: 'utf8',
|
|
168
|
+
timeout: 15000,
|
|
169
|
+
env: {
|
|
170
|
+
...process.env,
|
|
171
|
+
HOME,
|
|
172
|
+
ARIA_COGNITION_PUSH: 'off',
|
|
173
|
+
ARIA_HARNESS_TOKEN: '',
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Test utilities ──────────────────────────────────────────────────────────
|
|
179
|
+
const tmpTranscript = `/tmp/test-tier-transcript-${Date.now()}.jsonl`;
|
|
180
|
+
const tmpTranscriptStop = `/tmp/test-tier-stop-transcript-${Date.now()}.jsonl`;
|
|
181
|
+
|
|
182
|
+
function cleanup() {
|
|
183
|
+
[tmpTranscript, tmpTranscriptStop].forEach((p) => {
|
|
184
|
+
try { if (existsSync(p)) unlinkSync(p); } catch {}
|
|
185
|
+
});
|
|
186
|
+
restorePacket();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ── Suite ───────────────────────────────────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
console.log('\n=== Phase 11 #59 — Tier-aware lens labeling smoke tests ===\n');
|
|
192
|
+
|
|
193
|
+
// Save existing packet so we can restore after test run.
|
|
194
|
+
savePacket();
|
|
195
|
+
|
|
196
|
+
// ── Test 1: pre-tool-gate, OWNER tier → canonical labels in block reason ──
|
|
197
|
+
console.log('Test 1: aria-pre-tool-gate — OWNER tier shows canonical lens names');
|
|
198
|
+
{
|
|
199
|
+
writeOwnerPacket();
|
|
200
|
+
writeEmptyTranscript(tmpTranscript);
|
|
201
|
+
const result = runPreToolGate(tmpTranscript);
|
|
202
|
+
|
|
203
|
+
// Gate should block (exit 2) — no cognition in transcript
|
|
204
|
+
assert(
|
|
205
|
+
'T1: gate blocks (exit 2)',
|
|
206
|
+
result.status === 2,
|
|
207
|
+
`exit=${result.status} stderr=${result.stderr?.slice(0, 200)}`,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
let blockReason = '';
|
|
211
|
+
try {
|
|
212
|
+
const parsed = JSON.parse(result.stdout);
|
|
213
|
+
blockReason = parsed.reason || '';
|
|
214
|
+
} catch {
|
|
215
|
+
blockReason = result.stdout || '';
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Must mention at least one canonical label
|
|
219
|
+
const hasCanonical = CANONICAL.some((name) => blockReason.includes(`${name}:`));
|
|
220
|
+
assert(
|
|
221
|
+
'T1: block reason mentions canonical label (e.g. nur:)',
|
|
222
|
+
hasCanonical,
|
|
223
|
+
blockReason.slice(0, 400),
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// The first visible lens label must be canonical.
|
|
227
|
+
const firstCanonicalIdx = blockReason.indexOf(`${CANONICAL[0]}:`);
|
|
228
|
+
assert(
|
|
229
|
+
'T1: first lens label is canonical (nur:)',
|
|
230
|
+
firstCanonicalIdx >= 0,
|
|
231
|
+
`firstCanonicalIdx=${firstCanonicalIdx}`,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ── Test 2: pre-tool-gate, CLIENT tier → canonical labels in block reason ──
|
|
236
|
+
console.log('\nTest 2: aria-pre-tool-gate — CLIENT tier keeps canonical lens labels');
|
|
237
|
+
{
|
|
238
|
+
writeClientPacket();
|
|
239
|
+
writeEmptyTranscript(tmpTranscript);
|
|
240
|
+
const result = runPreToolGate(tmpTranscript);
|
|
241
|
+
|
|
242
|
+
assert(
|
|
243
|
+
'T2: gate blocks (exit 2)',
|
|
244
|
+
result.status === 2,
|
|
245
|
+
`exit=${result.status} stderr=${result.stderr?.slice(0, 200)}`,
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
let blockReason = '';
|
|
249
|
+
try {
|
|
250
|
+
const parsed = JSON.parse(result.stdout);
|
|
251
|
+
blockReason = parsed.reason || '';
|
|
252
|
+
} catch {
|
|
253
|
+
blockReason = result.stdout || '';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const hasCanonical = CANONICAL.some((name) => blockReason.includes(`${name}:`));
|
|
257
|
+
assert(
|
|
258
|
+
'T2: block reason mentions canonical label (e.g. nur:)',
|
|
259
|
+
hasCanonical,
|
|
260
|
+
blockReason.slice(0, 400),
|
|
261
|
+
);
|
|
262
|
+
assert(
|
|
263
|
+
'T2: first visible lens label is canonical (nur:)',
|
|
264
|
+
blockReason.includes(`${CANONICAL[0]}:`),
|
|
265
|
+
blockReason.slice(0, 400),
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ── Test 3: stop-gate, OWNER tier → canonical labels ──
|
|
270
|
+
console.log('\nTest 3: aria-stop-gate — OWNER tier shows canonical lens names');
|
|
271
|
+
{
|
|
272
|
+
writeOwnerPacket();
|
|
273
|
+
writeNoCognitionStopTranscript(tmpTranscriptStop);
|
|
274
|
+
const result = runStopGate(tmpTranscriptStop);
|
|
275
|
+
|
|
276
|
+
assert(
|
|
277
|
+
'T3: stop-gate blocks (exit 2)',
|
|
278
|
+
result.status === 2,
|
|
279
|
+
`exit=${result.status} stderr=${result.stderr?.slice(0, 200)}`,
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
let blockReason = '';
|
|
283
|
+
try {
|
|
284
|
+
const parsed = JSON.parse(result.stdout);
|
|
285
|
+
blockReason = parsed.reason || '';
|
|
286
|
+
} catch {
|
|
287
|
+
blockReason = result.stdout || '';
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const hasCanonical = CANONICAL.some((name) => blockReason.includes(`${name}:`));
|
|
291
|
+
assert(
|
|
292
|
+
'T3: stop-gate block reason mentions canonical label',
|
|
293
|
+
hasCanonical,
|
|
294
|
+
blockReason.slice(0, 400),
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// ── Test 4: stop-gate, CLIENT tier → canonical labels ──────────────────────
|
|
299
|
+
console.log('\nTest 4: aria-stop-gate — CLIENT tier keeps canonical lens labels');
|
|
300
|
+
{
|
|
301
|
+
writeClientPacket();
|
|
302
|
+
writeNoCognitionStopTranscript(tmpTranscriptStop);
|
|
303
|
+
const result = runStopGate(tmpTranscriptStop);
|
|
304
|
+
|
|
305
|
+
assert(
|
|
306
|
+
'T4: stop-gate blocks (exit 2)',
|
|
307
|
+
result.status === 2,
|
|
308
|
+
`exit=${result.status} stderr=${result.stderr?.slice(0, 200)}`,
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
let blockReason = '';
|
|
312
|
+
try {
|
|
313
|
+
const parsed = JSON.parse(result.stdout);
|
|
314
|
+
blockReason = parsed.reason || '';
|
|
315
|
+
} catch {
|
|
316
|
+
blockReason = result.stdout || '';
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const hasCanonical = CANONICAL.some((name) => blockReason.includes(`${name}:`));
|
|
320
|
+
assert(
|
|
321
|
+
'T4: stop-gate block reason mentions canonical label',
|
|
322
|
+
hasCanonical,
|
|
323
|
+
blockReason.slice(0, 400),
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ── Test 5: packet missing → defaults to canonical labels (fail-safe) ─────
|
|
328
|
+
console.log('\nTest 5: missing packet cache → defaults to canonical labels');
|
|
329
|
+
{
|
|
330
|
+
// Remove the packet cache
|
|
331
|
+
try { unlinkSync(PACKET_PATH); } catch {}
|
|
332
|
+
writeEmptyTranscript(tmpTranscript);
|
|
333
|
+
const result = runPreToolGate(tmpTranscript);
|
|
334
|
+
|
|
335
|
+
assert(
|
|
336
|
+
'T5: gate blocks (exit 2) with no packet',
|
|
337
|
+
result.status === 2,
|
|
338
|
+
`exit=${result.status}`,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
let blockReason = '';
|
|
342
|
+
try {
|
|
343
|
+
const parsed = JSON.parse(result.stdout);
|
|
344
|
+
blockReason = parsed.reason || '';
|
|
345
|
+
} catch {
|
|
346
|
+
blockReason = result.stdout || '';
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const hasCanonical = CANONICAL.some((name) => blockReason.includes(`${name}:`));
|
|
350
|
+
assert(
|
|
351
|
+
'T5: defaults to canonical labels when packet is absent',
|
|
352
|
+
hasCanonical,
|
|
353
|
+
`canonical=${hasCanonical} reason=${blockReason.slice(0, 300)}`,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ── Summary ─────────────────────────────────────────────────────────────────
|
|
358
|
+
cleanup();
|
|
359
|
+
console.log(`\n${'─'.repeat(60)}`);
|
|
360
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
361
|
+
if (failed > 0) {
|
|
362
|
+
console.error('\nSome tests FAILED — see FAIL lines above.');
|
|
363
|
+
process.exit(1);
|
|
364
|
+
} else {
|
|
365
|
+
console.log('\nAll tests PASSED.');
|
|
366
|
+
process.exit(0);
|
|
367
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"bundledAt": "2026-05-
|
|
3
|
-
"sdkFiles":
|
|
2
|
+
"bundledAt": "2026-05-03T03:42:17.303Z",
|
|
3
|
+
"sdkFiles": 9,
|
|
4
4
|
"runtimeTemplate": "/home/hamzaibrahim1/rei-ai-brain/packages/aria-connector/runtime-src",
|
|
5
5
|
"gateRuntimeSource": "/home/hamzaibrahim1/rei-ai-brain/packages/aria-gate-runtime/dist",
|
|
6
6
|
"sdkGuideSource": "/home/hamzaibrahim1/rei-ai-brain/harness/packages/harness-http-client/CLAUDE.md",
|
|
@@ -2,6 +2,7 @@ export interface HarnessClientConfig {
|
|
|
2
2
|
baseUrl: string;
|
|
3
3
|
apiKey: string;
|
|
4
4
|
harnessPacketUrl?: string;
|
|
5
|
+
gardenBaseUrl?: string;
|
|
5
6
|
workspaceRoot?: string;
|
|
6
7
|
}
|
|
7
8
|
export interface OwnerTier {
|
|
@@ -103,12 +104,21 @@ export interface HarnessBindingContext {
|
|
|
103
104
|
includeAegisLearnings?: boolean;
|
|
104
105
|
extraBody?: Record<string, unknown>;
|
|
105
106
|
}
|
|
107
|
+
export interface HarnessEvidenceRef {
|
|
108
|
+
evidenceId: string;
|
|
109
|
+
kind: string;
|
|
110
|
+
at: string;
|
|
111
|
+
sha256: string;
|
|
112
|
+
preview: string;
|
|
113
|
+
metadata?: Record<string, unknown>;
|
|
114
|
+
}
|
|
106
115
|
export interface BoundHarnessPromptResult {
|
|
107
116
|
prompt: string;
|
|
108
117
|
packet: HarnessPacket;
|
|
109
118
|
harnessText: string;
|
|
110
119
|
bindingBody: Record<string, unknown>;
|
|
111
120
|
}
|
|
121
|
+
export declare function createHarnessEvidenceRef(kind: string, value: unknown, metadata?: Record<string, unknown>): HarnessEvidenceRef;
|
|
112
122
|
export interface RecordDiscoveryArgs {
|
|
113
123
|
/** Finding text (min 4 chars). */
|
|
114
124
|
text: string;
|
|
@@ -161,6 +171,36 @@ export interface ActionCheck {
|
|
|
161
171
|
reason?: string;
|
|
162
172
|
requiredGates: string[];
|
|
163
173
|
}
|
|
174
|
+
export interface GardenContinuitySnapshot {
|
|
175
|
+
hydrated: boolean;
|
|
176
|
+
sessionId: string;
|
|
177
|
+
userId?: string;
|
|
178
|
+
query: string;
|
|
179
|
+
contextBlock: string;
|
|
180
|
+
memoryCount: number;
|
|
181
|
+
threadCount: number;
|
|
182
|
+
pulseCount: number;
|
|
183
|
+
snapshotMs: number;
|
|
184
|
+
postgresBound?: boolean;
|
|
185
|
+
qdrantBound?: boolean;
|
|
186
|
+
pulseLoopAlive?: boolean;
|
|
187
|
+
}
|
|
188
|
+
export interface GovernanceOutcomeInput {
|
|
189
|
+
sessionId: string;
|
|
190
|
+
userId?: string;
|
|
191
|
+
sourceRuntime: string;
|
|
192
|
+
action?: string;
|
|
193
|
+
outcome: string;
|
|
194
|
+
evidence?: unknown;
|
|
195
|
+
obligationId?: string;
|
|
196
|
+
}
|
|
197
|
+
export interface GovernanceOutcomeResult {
|
|
198
|
+
ok: boolean;
|
|
199
|
+
pulseId?: string;
|
|
200
|
+
ledgerId?: string;
|
|
201
|
+
threadId?: string;
|
|
202
|
+
message?: string;
|
|
203
|
+
}
|
|
164
204
|
/**
|
|
165
205
|
* Result shape for all three Aristotle phases.
|
|
166
206
|
* Mirrors `AristotleNoorWireResult` in aria-connector's aristotle-noor-wire.ts.
|
|
@@ -261,6 +301,7 @@ export declare class HTTPHarnessClient {
|
|
|
261
301
|
private readonly baseUrl;
|
|
262
302
|
private readonly apiKey;
|
|
263
303
|
private readonly harnessPacketUrl;
|
|
304
|
+
private readonly gardenBaseUrl?;
|
|
264
305
|
private readonly workspaceRoot;
|
|
265
306
|
private cachedPacket;
|
|
266
307
|
private packetLastFetched;
|
|
@@ -303,6 +344,12 @@ export declare class HTTPHarnessClient {
|
|
|
303
344
|
validateOutput(text: string, sessionId: string): Promise<ValidationResult>;
|
|
304
345
|
checkAction(action: 'deploy' | 'build' | 'write' | 'delete', target: string): Promise<ActionCheck>;
|
|
305
346
|
gardenTurn(sessionId: string, message: string, response: string, userId?: string): Promise<void>;
|
|
347
|
+
hydrateGardenContinuity(sessionId: string, query: string, limits?: {
|
|
348
|
+
threadLimit?: number;
|
|
349
|
+
pulseLimit?: number;
|
|
350
|
+
userId?: string;
|
|
351
|
+
}): Promise<GardenContinuitySnapshot>;
|
|
352
|
+
persistGovernanceOutcome(input: GovernanceOutcomeInput): Promise<GovernanceOutcomeResult>;
|
|
306
353
|
consult(args: {
|
|
307
354
|
brief: string;
|
|
308
355
|
sessionId: string;
|
|
@@ -487,3 +534,4 @@ export declare const harness: {
|
|
|
487
534
|
export declare function bindingContext(role: string, sessionId: string, stage: string, intendedAction: string, rationale: string): HarnessBindingContext;
|
|
488
535
|
export declare function getBoundHarnessAndPrompt(context: HarnessBindingContext, plan?: Partial<HarnessPlan>, client?: HTTPHarnessClient): Promise<BoundHarnessPromptResult>;
|
|
489
536
|
export * from './runWithCognition.js';
|
|
537
|
+
export * from './runWithGovernance.js';
|
|
@@ -2,7 +2,7 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import { homedir as _homedir } from 'node:os';
|
|
4
4
|
import { resolve, isAbsolute } from 'node:path';
|
|
5
|
-
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
6
6
|
const CLOUD_RUN_SOUL_URL = 'https://arias-soul-6zp3gtk2ca-uc.a.run.app';
|
|
7
7
|
const PUBLIC_HARNESS_URL = 'https://harness.ariasos.com';
|
|
8
8
|
const LOCAL_HARNESS_CANDIDATES = [
|
|
@@ -29,6 +29,28 @@ function normalizeHarnessPacketPayload(payload) {
|
|
|
29
29
|
? current
|
|
30
30
|
: {};
|
|
31
31
|
}
|
|
32
|
+
function stableEvidenceString(value) {
|
|
33
|
+
if (typeof value === 'string')
|
|
34
|
+
return value;
|
|
35
|
+
try {
|
|
36
|
+
return JSON.stringify(value);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return String(value);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function createHarnessEvidenceRef(kind, value, metadata) {
|
|
43
|
+
const raw = stableEvidenceString(value);
|
|
44
|
+
const sha256 = createHash('sha256').update(raw).digest('hex');
|
|
45
|
+
return {
|
|
46
|
+
evidenceId: `ev_${sha256.slice(0, 16)}`,
|
|
47
|
+
kind,
|
|
48
|
+
at: new Date().toISOString(),
|
|
49
|
+
sha256,
|
|
50
|
+
preview: raw.slice(0, 500),
|
|
51
|
+
...(metadata && Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
32
54
|
// ── 8-Lens Cognition Block ─────────────────────────────────────────────────
|
|
33
55
|
const EIGHT_LENS_BLOCK = `[ARIA SHELL PROTOCOL — You are a controlled surface]
|
|
34
56
|
|
|
@@ -65,6 +87,7 @@ export class HTTPHarnessClient {
|
|
|
65
87
|
baseUrl;
|
|
66
88
|
apiKey;
|
|
67
89
|
harnessPacketUrl;
|
|
90
|
+
gardenBaseUrl;
|
|
68
91
|
workspaceRoot;
|
|
69
92
|
cachedPacket = null;
|
|
70
93
|
packetLastFetched = 0;
|
|
@@ -77,6 +100,7 @@ export class HTTPHarnessClient {
|
|
|
77
100
|
this.harnessPacketUrl = config.harnessPacketUrl ?? (isMountedRuntimeBaseUrl(this.baseUrl)
|
|
78
101
|
? `${this.baseUrl}/packet`
|
|
79
102
|
: `${this.baseUrl}/api/harness/codex`);
|
|
103
|
+
this.gardenBaseUrl = (config.gardenBaseUrl || process.env.ARIA_GARDEN_BASE_URL || '').replace(/\/+$/, '') || undefined;
|
|
80
104
|
this.workspaceRoot = config.workspaceRoot ?? process.cwd();
|
|
81
105
|
this.preferredBaseUrl = this.baseUrl;
|
|
82
106
|
this.baseUrlCandidates = this.buildBaseUrlCandidates(config.baseUrl);
|
|
@@ -643,6 +667,120 @@ export class HTTPHarnessClient {
|
|
|
643
667
|
throw new Error(`garden/fire failed: ${res.status} ${res.statusText}`);
|
|
644
668
|
}
|
|
645
669
|
}
|
|
670
|
+
async hydrateGardenContinuity(sessionId, query, limits = {}) {
|
|
671
|
+
if (this.gardenBaseUrl) {
|
|
672
|
+
const params = new URLSearchParams({
|
|
673
|
+
session_id: sessionId,
|
|
674
|
+
user_id: limits.userId || '',
|
|
675
|
+
query,
|
|
676
|
+
thread_limit: String(limits.threadLimit ?? 5),
|
|
677
|
+
pulse_limit: String(limits.pulseLimit ?? 12),
|
|
678
|
+
});
|
|
679
|
+
const res = await this.fetchWithRetry(`${this.gardenBaseUrl}/continuity?${params}`, {
|
|
680
|
+
method: 'GET',
|
|
681
|
+
headers: {
|
|
682
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
683
|
+
'Content-Type': 'application/json',
|
|
684
|
+
},
|
|
685
|
+
});
|
|
686
|
+
if (res.ok) {
|
|
687
|
+
const data = (await res.json());
|
|
688
|
+
const activeThreads = Array.isArray(data.activeThreads) ? data.activeThreads : [];
|
|
689
|
+
const recentPulses = Array.isArray(data.recentPulses) ? data.recentPulses : [];
|
|
690
|
+
const contextBlock = String(data.continuityBlock || data.continuity_block || data.gardenContextBlock || '');
|
|
691
|
+
return {
|
|
692
|
+
hydrated: Boolean(data.ok) && (contextBlock.length > 0 || activeThreads.length > 0 || recentPulses.length > 0),
|
|
693
|
+
sessionId: String(data.sessionId || data.session_id || sessionId),
|
|
694
|
+
userId: String(data.userId || data.user_id || limits.userId || ''),
|
|
695
|
+
query,
|
|
696
|
+
contextBlock,
|
|
697
|
+
memoryCount: recentPulses.length,
|
|
698
|
+
threadCount: activeThreads.length,
|
|
699
|
+
pulseCount: recentPulses.length,
|
|
700
|
+
snapshotMs: Number(data.snapshotMs || data.snapshot_ms || Date.now()),
|
|
701
|
+
postgresBound: Boolean(data.postgresBound ?? data.postgres_bound),
|
|
702
|
+
qdrantBound: Boolean(data.qdrantBound ?? data.qdrant_bound),
|
|
703
|
+
pulseLoopAlive: Boolean(data.pulseLoopAlive ?? data.pulse_loop_alive),
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
if (![404, 405, 501].includes(res.status)) {
|
|
707
|
+
throw new Error(`garden continuity failed: ${res.status} ${res.statusText}`);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
const params = new URLSearchParams({
|
|
711
|
+
session_id: sessionId,
|
|
712
|
+
query,
|
|
713
|
+
thread_limit: String(limits.threadLimit ?? 5),
|
|
714
|
+
pulse_limit: String(limits.pulseLimit ?? 12),
|
|
715
|
+
});
|
|
716
|
+
const res = await this.fetchWithRetry(`${this.baseUrl}/api/garden/living?${params}`, {
|
|
717
|
+
method: 'GET',
|
|
718
|
+
headers: {
|
|
719
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
720
|
+
'Content-Type': 'application/json',
|
|
721
|
+
},
|
|
722
|
+
});
|
|
723
|
+
if (!res.ok) {
|
|
724
|
+
throw new Error(`garden/living failed: ${res.status} ${res.statusText}`);
|
|
725
|
+
}
|
|
726
|
+
const data = (await res.json());
|
|
727
|
+
const activeThreads = Array.isArray(data.activeThreads) ? data.activeThreads : [];
|
|
728
|
+
const recentPulses = Array.isArray(data.recentPulses) ? data.recentPulses : Array.isArray(data.pulses) ? data.pulses : [];
|
|
729
|
+
const contextBlock = String(data.gardenContextBlock || data.garden_context_block || data.contextBlock || '');
|
|
730
|
+
return {
|
|
731
|
+
hydrated: contextBlock.length > 0 || activeThreads.length > 0 || recentPulses.length > 0,
|
|
732
|
+
sessionId,
|
|
733
|
+
userId: limits.userId,
|
|
734
|
+
query,
|
|
735
|
+
contextBlock,
|
|
736
|
+
memoryCount: recentPulses.length,
|
|
737
|
+
threadCount: activeThreads.length,
|
|
738
|
+
pulseCount: recentPulses.length,
|
|
739
|
+
snapshotMs: Number(data.snapshotMs || data.snapshot_ms || Date.now()),
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
async persistGovernanceOutcome(input) {
|
|
743
|
+
if (!input.sessionId || !input.sourceRuntime || !input.outcome) {
|
|
744
|
+
throw new Error('persistGovernanceOutcome requires sessionId, sourceRuntime, and outcome');
|
|
745
|
+
}
|
|
746
|
+
const body = {
|
|
747
|
+
session_id: input.sessionId,
|
|
748
|
+
user_id: input.userId,
|
|
749
|
+
source_runtime: input.sourceRuntime,
|
|
750
|
+
action: input.action || '',
|
|
751
|
+
outcome: input.outcome,
|
|
752
|
+
evidence: input.evidence ?? null,
|
|
753
|
+
obligation_id: input.obligationId || '',
|
|
754
|
+
};
|
|
755
|
+
const targets = this.gardenBaseUrl
|
|
756
|
+
? [`${this.gardenBaseUrl}/governance-outcome`, `${this.baseUrl}/api/garden/governance-outcome`]
|
|
757
|
+
: [`${this.baseUrl}/api/garden/governance-outcome`];
|
|
758
|
+
let lastStatus = '';
|
|
759
|
+
for (const url of targets) {
|
|
760
|
+
const res = await this.fetchWithRetry(url, {
|
|
761
|
+
method: 'POST',
|
|
762
|
+
headers: {
|
|
763
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
764
|
+
'Content-Type': 'application/json',
|
|
765
|
+
},
|
|
766
|
+
body: JSON.stringify(body),
|
|
767
|
+
});
|
|
768
|
+
if (res.ok) {
|
|
769
|
+
const data = (await res.json());
|
|
770
|
+
return {
|
|
771
|
+
ok: Boolean(data.ok),
|
|
772
|
+
pulseId: String(data.pulseId || data.pulse_id || ''),
|
|
773
|
+
ledgerId: String(data.ledgerId || data.ledger_id || ''),
|
|
774
|
+
threadId: String(data.threadId || data.thread_id || ''),
|
|
775
|
+
message: typeof data.message === 'string' ? data.message : undefined,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
lastStatus = `${res.status} ${res.statusText}`;
|
|
779
|
+
if (![404, 405, 501].includes(res.status))
|
|
780
|
+
break;
|
|
781
|
+
}
|
|
782
|
+
throw new Error(`persistGovernanceOutcome failed: ${lastStatus || 'no target available'}`);
|
|
783
|
+
}
|
|
646
784
|
// ── Consult — delegate to Aria for direction or structured plan ─────────
|
|
647
785
|
// Routes through /api/harness/delegate (the architect-mode endpoint that
|
|
648
786
|
// serves preprompt-consult + Aria-as-commander binding plans). Caller
|
|
@@ -1572,4 +1710,5 @@ export async function getBoundHarnessAndPrompt(context, plan, client) {
|
|
|
1572
1710
|
return sdk.getBoundHarnessAndPrompt(context, plan);
|
|
1573
1711
|
}
|
|
1574
1712
|
export * from './runWithCognition.js';
|
|
1713
|
+
export * from './runWithGovernance.js';
|
|
1575
1714
|
//# sourceMappingURL=index.js.map
|