@aria_asi/cli 0.2.33 → 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.
Files changed (74) hide show
  1. package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
  2. package/dist/aria-connector/src/connectors/codex.js +47 -0
  3. package/dist/aria-connector/src/connectors/codex.js.map +1 -1
  4. package/dist/assets/hooks/aria-harness-via-sdk.mjs +16 -3
  5. package/dist/assets/hooks/aria-pre-tool-gate.mjs +41 -1
  6. package/dist/assets/hooks/aria-stop-gate.mjs +42 -1
  7. package/dist/assets/hooks/doctrine_trigger_map.json +43 -0
  8. package/dist/assets/hooks/lib/skill-autoload-gate.mjs +14 -1
  9. package/dist/assets/opencode-plugins/harness-context/index.js +1 -1
  10. package/dist/assets/opencode-plugins/harness-gate/index.js +49 -9
  11. package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -1
  12. package/dist/assets/opencode-plugins/harness-stop/index.js +201 -166
  13. package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -1
  14. package/dist/runtime/codex-bridge.mjs +1 -1
  15. package/dist/runtime/discipline/CLAUDE.md +2 -2
  16. package/dist/runtime/discipline/doctrine_trigger_map.json +43 -0
  17. package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +3 -3
  18. package/dist/runtime/doctrine_trigger_map.json +43 -0
  19. package/dist/runtime/hooks/aria-agent-handoff.mjs +247 -0
  20. package/dist/runtime/hooks/aria-agent-ledger-merge.mjs +164 -0
  21. package/dist/runtime/hooks/aria-architect-fallback.mjs +267 -0
  22. package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +761 -0
  23. package/dist/runtime/hooks/aria-discovery-record.mjs +101 -0
  24. package/dist/runtime/hooks/aria-harness-via-sdk.mjs +544 -0
  25. package/dist/runtime/hooks/aria-import-resolution-gate.mjs +330 -0
  26. package/dist/runtime/hooks/aria-outcome-record.mjs +84 -0
  27. package/dist/runtime/hooks/aria-pre-emit-dryrun.mjs +329 -0
  28. package/dist/runtime/hooks/aria-pre-text-gate.mjs +112 -0
  29. package/dist/runtime/hooks/aria-pre-tool-gate.mjs +2482 -0
  30. package/dist/runtime/hooks/aria-preprompt-consult.mjs +464 -0
  31. package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +647 -0
  32. package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +429 -0
  33. package/dist/runtime/hooks/aria-stop-gate.mjs +1882 -0
  34. package/dist/runtime/hooks/aria-trigger-autolearn.mjs +229 -0
  35. package/dist/runtime/hooks/aria-userprompt-abandon-detect.mjs +192 -0
  36. package/dist/runtime/hooks/doctrine_trigger_map.json +577 -0
  37. package/dist/runtime/hooks/lib/canonical-lenses.mjs +65 -0
  38. package/dist/runtime/hooks/lib/domain-output-quality.mjs +103 -0
  39. package/dist/runtime/hooks/lib/gate-audit.mjs +43 -0
  40. package/dist/runtime/hooks/lib/gate-loop-state.mjs +50 -0
  41. package/dist/runtime/hooks/lib/hook-message-window.mjs +121 -0
  42. package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +14 -0
  43. package/dist/runtime/hooks/test-aria-preturn-memory-gate.mjs +245 -0
  44. package/dist/runtime/hooks/test-tier-lens-labeling.mjs +367 -0
  45. package/dist/runtime/manifest.json +2 -2
  46. package/dist/runtime/sdk/BUNDLED.json +2 -2
  47. package/dist/runtime/sdk/index.d.ts +39 -0
  48. package/dist/runtime/sdk/index.js +117 -0
  49. package/dist/runtime/sdk/index.js.map +1 -1
  50. package/dist/runtime/sdk/runWithGovernance.d.ts +16 -0
  51. package/dist/runtime/sdk/runWithGovernance.js +54 -0
  52. package/dist/runtime/sdk/runWithGovernance.js.map +1 -0
  53. package/dist/sdk/BUNDLED.json +2 -2
  54. package/dist/sdk/index.d.ts +39 -0
  55. package/dist/sdk/index.js +117 -0
  56. package/dist/sdk/index.js.map +1 -1
  57. package/dist/sdk/runWithGovernance.d.ts +16 -0
  58. package/dist/sdk/runWithGovernance.js +54 -0
  59. package/dist/sdk/runWithGovernance.js.map +1 -0
  60. package/hooks/aria-harness-via-sdk.mjs +16 -3
  61. package/hooks/aria-pre-tool-gate.mjs +41 -1
  62. package/hooks/aria-stop-gate.mjs +42 -1
  63. package/hooks/doctrine_trigger_map.json +43 -0
  64. package/hooks/lib/skill-autoload-gate.mjs +14 -1
  65. package/opencode-plugins/harness-context/index.js +1 -1
  66. package/opencode-plugins/harness-gate/index.js +49 -9
  67. package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -1
  68. package/opencode-plugins/harness-stop/index.js +201 -166
  69. package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -1
  70. package/package.json +12 -5
  71. package/runtime-src/codex-bridge.mjs +1 -1
  72. package/scripts/bundle-sdk.mjs +2 -0
  73. package/scripts/self-test-harness-gates.mjs +79 -0
  74. package/src/connectors/codex.ts +47 -0
@@ -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-02T19:32:12.150Z",
3
- "sdkFiles": 6,
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",
@@ -1,5 +1,5 @@
1
1
  {
2
- "bundledAt": "2026-05-02T19:32:12.146Z",
2
+ "bundledAt": "2026-05-03T03:42:17.293Z",
3
3
  "sdkSource": "/home/hamzaibrahim1/rei-ai-brain/harness/packages/harness-http-client/dist",
4
- "files": 6
4
+ "files": 9
5
5
  }
@@ -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 {
@@ -170,6 +171,36 @@ export interface ActionCheck {
170
171
  reason?: string;
171
172
  requiredGates: string[];
172
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
+ }
173
204
  /**
174
205
  * Result shape for all three Aristotle phases.
175
206
  * Mirrors `AristotleNoorWireResult` in aria-connector's aristotle-noor-wire.ts.
@@ -270,6 +301,7 @@ export declare class HTTPHarnessClient {
270
301
  private readonly baseUrl;
271
302
  private readonly apiKey;
272
303
  private readonly harnessPacketUrl;
304
+ private readonly gardenBaseUrl?;
273
305
  private readonly workspaceRoot;
274
306
  private cachedPacket;
275
307
  private packetLastFetched;
@@ -312,6 +344,12 @@ export declare class HTTPHarnessClient {
312
344
  validateOutput(text: string, sessionId: string): Promise<ValidationResult>;
313
345
  checkAction(action: 'deploy' | 'build' | 'write' | 'delete', target: string): Promise<ActionCheck>;
314
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>;
315
353
  consult(args: {
316
354
  brief: string;
317
355
  sessionId: string;
@@ -496,3 +534,4 @@ export declare const harness: {
496
534
  export declare function bindingContext(role: string, sessionId: string, stage: string, intendedAction: string, rationale: string): HarnessBindingContext;
497
535
  export declare function getBoundHarnessAndPrompt(context: HarnessBindingContext, plan?: Partial<HarnessPlan>, client?: HTTPHarnessClient): Promise<BoundHarnessPromptResult>;
498
536
  export * from './runWithCognition.js';
537
+ export * from './runWithGovernance.js';
@@ -87,6 +87,7 @@ export class HTTPHarnessClient {
87
87
  baseUrl;
88
88
  apiKey;
89
89
  harnessPacketUrl;
90
+ gardenBaseUrl;
90
91
  workspaceRoot;
91
92
  cachedPacket = null;
92
93
  packetLastFetched = 0;
@@ -99,6 +100,7 @@ export class HTTPHarnessClient {
99
100
  this.harnessPacketUrl = config.harnessPacketUrl ?? (isMountedRuntimeBaseUrl(this.baseUrl)
100
101
  ? `${this.baseUrl}/packet`
101
102
  : `${this.baseUrl}/api/harness/codex`);
103
+ this.gardenBaseUrl = (config.gardenBaseUrl || process.env.ARIA_GARDEN_BASE_URL || '').replace(/\/+$/, '') || undefined;
102
104
  this.workspaceRoot = config.workspaceRoot ?? process.cwd();
103
105
  this.preferredBaseUrl = this.baseUrl;
104
106
  this.baseUrlCandidates = this.buildBaseUrlCandidates(config.baseUrl);
@@ -665,6 +667,120 @@ export class HTTPHarnessClient {
665
667
  throw new Error(`garden/fire failed: ${res.status} ${res.statusText}`);
666
668
  }
667
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
+ }
668
784
  // ── Consult — delegate to Aria for direction or structured plan ─────────
669
785
  // Routes through /api/harness/delegate (the architect-mode endpoint that
670
786
  // serves preprompt-consult + Aria-as-commander binding plans). Caller
@@ -1594,4 +1710,5 @@ export async function getBoundHarnessAndPrompt(context, plan, client) {
1594
1710
  return sdk.getBoundHarnessAndPrompt(context, plan);
1595
1711
  }
1596
1712
  export * from './runWithCognition.js';
1713
+ export * from './runWithGovernance.js';
1597
1714
  //# sourceMappingURL=index.js.map