@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
package/dist/sdk/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { homedir as _homedir } from 'node:os';
|
|
2
4
|
import { resolve, isAbsolute } from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
3
6
|
// ── 8-Lens Cognition Block ─────────────────────────────────────────────────
|
|
4
7
|
const EIGHT_LENS_BLOCK = `[ARIA SHELL PROTOCOL — You are a controlled surface]
|
|
5
8
|
|
|
@@ -45,6 +48,197 @@ export class HTTPHarnessClient {
|
|
|
45
48
|
this.apiKey = config.apiKey;
|
|
46
49
|
this.harnessPacketUrl = config.harnessPacketUrl ?? `${this.baseUrl}/api/harness/codex`;
|
|
47
50
|
this.workspaceRoot = config.workspaceRoot ?? process.cwd();
|
|
51
|
+
// Layer 3 — sub-agent disk-cache bootstrap (#84).
|
|
52
|
+
// If ARIA_HARNESS_PACKET_PATH is set (injected by aria-agent-handoff.mjs
|
|
53
|
+
// or spawnSubAgent), OR the owner-tier handoff JSON at
|
|
54
|
+
// ~/.claude/aria-agent-harness-handoff.json carries a harnessPacketPath
|
|
55
|
+
// field, pre-load the packet from disk so getHarnessPacket() returns
|
|
56
|
+
// the parent's cognition substrate without an extra HTTP call.
|
|
57
|
+
// TTL is 5 min (matches handoff TTL). Stale packets trigger normal fetch.
|
|
58
|
+
this._tryLoadDiskPacket();
|
|
59
|
+
}
|
|
60
|
+
extractHarnessText(packet) {
|
|
61
|
+
const raw = packet?.harness;
|
|
62
|
+
return typeof raw === 'string' ? raw.trim() : '';
|
|
63
|
+
}
|
|
64
|
+
normalizePlanDocs(plan) {
|
|
65
|
+
const docs = [];
|
|
66
|
+
if (plan.response !== null && plan.response !== undefined) {
|
|
67
|
+
if (!plan.response.ok) {
|
|
68
|
+
for (const d of plan.docs) {
|
|
69
|
+
docs.push({ ...d });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
for (const d of plan.response.docs) {
|
|
74
|
+
if (!d.title && !d.content && !d.path)
|
|
75
|
+
continue;
|
|
76
|
+
docs.push({ ...d });
|
|
77
|
+
}
|
|
78
|
+
const respTitles = new Set(plan.response.docs.map((d) => d.title).filter(Boolean));
|
|
79
|
+
for (const d of plan.docs) {
|
|
80
|
+
if (d.title && !respTitles.has(d.title)) {
|
|
81
|
+
docs.push({ ...d });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return docs;
|
|
86
|
+
}
|
|
87
|
+
for (const d of plan.docs) {
|
|
88
|
+
if (!d.title && !d.content && !d.path)
|
|
89
|
+
continue;
|
|
90
|
+
docs.push({ ...d });
|
|
91
|
+
}
|
|
92
|
+
return docs;
|
|
93
|
+
}
|
|
94
|
+
collectPlanFilePaths(plan, docs) {
|
|
95
|
+
const filePathsToLoad = new Set();
|
|
96
|
+
if (plan.response !== null && plan.response !== undefined && plan.response.ok) {
|
|
97
|
+
for (const f of plan.response.files) {
|
|
98
|
+
filePathsToLoad.add(f);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const f of plan.files) {
|
|
102
|
+
filePathsToLoad.add(f);
|
|
103
|
+
}
|
|
104
|
+
for (const doc of docs) {
|
|
105
|
+
if (doc.path) {
|
|
106
|
+
filePathsToLoad.add(doc.path);
|
|
107
|
+
}
|
|
108
|
+
if (doc.references) {
|
|
109
|
+
for (const ref of doc.references) {
|
|
110
|
+
filePathsToLoad.add(ref);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (doc.content) {
|
|
114
|
+
const pathMatches = doc.content.match(/`([^`]+\.[a-z]{1,6})`/g);
|
|
115
|
+
if (pathMatches) {
|
|
116
|
+
for (const match of pathMatches) {
|
|
117
|
+
const path = match.slice(1, -1);
|
|
118
|
+
if (path.includes('/') || path.includes('.')) {
|
|
119
|
+
filePathsToLoad.add(path);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return filePathsToLoad;
|
|
126
|
+
}
|
|
127
|
+
async loadFilesByPath(filePaths) {
|
|
128
|
+
const files = {};
|
|
129
|
+
const loadPromises = Array.from(filePaths).map(async (filePath) => {
|
|
130
|
+
const resolved = isAbsolute(filePath) ? filePath : resolve(this.workspaceRoot, filePath);
|
|
131
|
+
try {
|
|
132
|
+
const content = await readFile(resolved, 'utf8');
|
|
133
|
+
return { path: filePath, content };
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return { path: filePath, content: `[unable to load: ${filePath}]` };
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const loadedFiles = await Promise.all(loadPromises);
|
|
140
|
+
for (const { path, content } of loadedFiles) {
|
|
141
|
+
files[path] = content;
|
|
142
|
+
}
|
|
143
|
+
return files;
|
|
144
|
+
}
|
|
145
|
+
async buildHarnessInjection(harness, plan, options) {
|
|
146
|
+
const docs = this.normalizePlanDocs(plan);
|
|
147
|
+
const files = await this.loadFilesByPath(this.collectPlanFilePaths(plan, docs));
|
|
148
|
+
const shouldLoadAegis = options?.includeAegisLearnings !== false;
|
|
149
|
+
const aegisLearnings = shouldLoadAegis ? await this.getAegisLearnings(20).catch(() => null) : null;
|
|
150
|
+
return {
|
|
151
|
+
harness,
|
|
152
|
+
docs,
|
|
153
|
+
files,
|
|
154
|
+
task: plan.task ?? plan.response?.task ?? '',
|
|
155
|
+
loadedAt: new Date().toISOString(),
|
|
156
|
+
aegisLearnings: aegisLearnings ?? undefined,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
buildHarnessBindingBody(context) {
|
|
160
|
+
const body = {
|
|
161
|
+
message: context.message?.trim()
|
|
162
|
+
|| context.currentIssue?.trim()
|
|
163
|
+
|| [context.intendedAction, context.rationale].filter(Boolean).join('. ').trim()
|
|
164
|
+
|| 'harness packet preflight',
|
|
165
|
+
stage: context.stage,
|
|
166
|
+
actor: context.role,
|
|
167
|
+
system: context.role,
|
|
168
|
+
platform: context.platform || 'harness-http-client',
|
|
169
|
+
roleProfile: context.roleProfile,
|
|
170
|
+
sessionId: context.sessionId,
|
|
171
|
+
userId: context.userId,
|
|
172
|
+
userName: context.userName,
|
|
173
|
+
currentIssue: context.currentIssue,
|
|
174
|
+
linearIssueId: context.linearIssueId,
|
|
175
|
+
linearIssueUrl: context.linearIssueUrl,
|
|
176
|
+
linearState: context.linearState,
|
|
177
|
+
workingDirectory: context.workingDirectory,
|
|
178
|
+
filesTouched: context.filesTouched,
|
|
179
|
+
recentProgress: context.recentProgress,
|
|
180
|
+
openRisks: context.openRisks,
|
|
181
|
+
nextActions: context.nextActions,
|
|
182
|
+
checkpoint: context.checkpoint,
|
|
183
|
+
requireGarden: context.requireGarden ?? true,
|
|
184
|
+
researchMode: context.researchMode,
|
|
185
|
+
intendedAction: context.intendedAction,
|
|
186
|
+
rationale: context.rationale,
|
|
187
|
+
correlationId: context.correlationId || randomUUID(),
|
|
188
|
+
...context.extraBody,
|
|
189
|
+
};
|
|
190
|
+
return Object.fromEntries(Object.entries(body).filter(([, value]) => {
|
|
191
|
+
if (value == null)
|
|
192
|
+
return false;
|
|
193
|
+
if (typeof value === 'string')
|
|
194
|
+
return value.trim().length > 0;
|
|
195
|
+
if (Array.isArray(value))
|
|
196
|
+
return value.length > 0;
|
|
197
|
+
return true;
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
_tryLoadDiskPacket() {
|
|
201
|
+
try {
|
|
202
|
+
// Path 1: direct env var (set by spawnSubAgent / Agent dispatch)
|
|
203
|
+
let packetPath = process.env.ARIA_HARNESS_PACKET_PATH || null;
|
|
204
|
+
// Path 2: owner-tier handoff JSON
|
|
205
|
+
if (!packetPath) {
|
|
206
|
+
const HOME = _homedir();
|
|
207
|
+
const handoffPath = `${HOME}/.claude/aria-agent-harness-handoff.json`;
|
|
208
|
+
if (existsSync(handoffPath)) {
|
|
209
|
+
try {
|
|
210
|
+
const handoff = JSON.parse(readFileSync(handoffPath, 'utf8'));
|
|
211
|
+
const ageMs = handoff.writtenAt
|
|
212
|
+
? Date.now() - new Date(handoff.writtenAt).getTime()
|
|
213
|
+
: Infinity;
|
|
214
|
+
const ttl = handoff.ttlMs ?? (5 * 60 * 1000);
|
|
215
|
+
if (ageMs < ttl && handoff.harnessPacketPath) {
|
|
216
|
+
packetPath = handoff.harnessPacketPath;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch { /* malformed handoff — skip */ }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (!packetPath)
|
|
223
|
+
return;
|
|
224
|
+
if (!existsSync(packetPath))
|
|
225
|
+
return;
|
|
226
|
+
// Check packet file age against TTL (5 min)
|
|
227
|
+
const stat = statSync(packetPath);
|
|
228
|
+
if (Date.now() - stat.mtimeMs > 5 * 60 * 1000)
|
|
229
|
+
return; // expired
|
|
230
|
+
const raw = JSON.parse(readFileSync(packetPath, 'utf8'));
|
|
231
|
+
// Packet on disk may be the raw API response (has .packet wrapper) or
|
|
232
|
+
// a bare packet object. Normalise to HarnessPacket shape.
|
|
233
|
+
const packetData = (raw.packet ?? raw);
|
|
234
|
+
this.cachedPacket = {
|
|
235
|
+
packet: packetData,
|
|
236
|
+
timestamp: new Date().toISOString(),
|
|
237
|
+
version: '1.0.0',
|
|
238
|
+
};
|
|
239
|
+
this.packetLastFetched = stat.mtimeMs; // use file mtime as origin time
|
|
240
|
+
}
|
|
241
|
+
catch { /* disk errors are non-fatal — normal HTTP fetch will run */ }
|
|
48
242
|
}
|
|
49
243
|
static getInstance(config) {
|
|
50
244
|
if (!HTTPHarnessClient.instance && config) {
|
|
@@ -135,96 +329,98 @@ export class HTTPHarnessClient {
|
|
|
135
329
|
// ── Inject ──────────────────────────────────────────────────────────────
|
|
136
330
|
async inject(plan) {
|
|
137
331
|
const harness = await this.fetchHarnessPacket();
|
|
138
|
-
|
|
139
|
-
if (plan.response !== null && plan.response !== undefined) {
|
|
140
|
-
if (!plan.response.ok) {
|
|
141
|
-
for (const d of plan.docs) {
|
|
142
|
-
docs.push({ ...d });
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
for (const d of plan.response.docs) {
|
|
147
|
-
if (!d.title && !d.content && !d.path)
|
|
148
|
-
continue;
|
|
149
|
-
docs.push({ ...d });
|
|
150
|
-
}
|
|
151
|
-
const respTitles = new Set(plan.response.docs.map((d) => d.title).filter(Boolean));
|
|
152
|
-
for (const d of plan.docs) {
|
|
153
|
-
if (d.title && !respTitles.has(d.title)) {
|
|
154
|
-
docs.push({ ...d });
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
for (const d of plan.docs) {
|
|
161
|
-
if (!d.title && !d.content && !d.path)
|
|
162
|
-
continue;
|
|
163
|
-
docs.push({ ...d });
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const files = {};
|
|
167
|
-
const filePathsToLoad = new Set();
|
|
168
|
-
if (plan.response !== null && plan.response !== undefined && plan.response.ok) {
|
|
169
|
-
for (const f of plan.response.files) {
|
|
170
|
-
filePathsToLoad.add(f);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
for (const f of plan.files) {
|
|
174
|
-
filePathsToLoad.add(f);
|
|
175
|
-
}
|
|
176
|
-
for (const doc of docs) {
|
|
177
|
-
if (doc.path) {
|
|
178
|
-
filePathsToLoad.add(doc.path);
|
|
179
|
-
}
|
|
180
|
-
if (doc.references) {
|
|
181
|
-
for (const ref of doc.references) {
|
|
182
|
-
filePathsToLoad.add(ref);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (doc.content) {
|
|
186
|
-
const pathMatches = doc.content.match(/`([^`]+\.[a-z]{1,6})`/g);
|
|
187
|
-
if (pathMatches) {
|
|
188
|
-
for (const m of pathMatches) {
|
|
189
|
-
const p = m.slice(1, -1);
|
|
190
|
-
if (p.includes('/') || p.includes('.')) {
|
|
191
|
-
filePathsToLoad.add(p);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
const loadPromises = Array.from(filePathsToLoad).map(async (filePath) => {
|
|
198
|
-
const resolved = isAbsolute(filePath) ? filePath : resolve(this.workspaceRoot, filePath);
|
|
199
|
-
try {
|
|
200
|
-
const content = await readFile(resolved, 'utf8');
|
|
201
|
-
return { path: filePath, content };
|
|
202
|
-
}
|
|
203
|
-
catch {
|
|
204
|
-
return { path: filePath, content: `[unable to load: ${filePath}]` };
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
const loadedFiles = await Promise.all(loadPromises);
|
|
208
|
-
for (const { path, content } of loadedFiles) {
|
|
209
|
-
files[path] = content;
|
|
210
|
-
}
|
|
211
|
-
return {
|
|
212
|
-
harness,
|
|
213
|
-
docs,
|
|
214
|
-
files,
|
|
215
|
-
task: plan.task ?? plan.response?.task ?? '',
|
|
216
|
-
loadedAt: new Date().toISOString(),
|
|
217
|
-
};
|
|
332
|
+
return this.buildHarnessInjection(harness, plan, { includeAegisLearnings: true });
|
|
218
333
|
}
|
|
219
334
|
async getHarnessPacket(bodyOverride) {
|
|
220
335
|
return this.fetchHarnessPacket(bodyOverride);
|
|
221
336
|
}
|
|
337
|
+
async getBoundHarnessAndPrompt(context, plan) {
|
|
338
|
+
const bindingBody = this.buildHarnessBindingBody(context);
|
|
339
|
+
const harness = await this.fetchHarnessPacket(bindingBody);
|
|
340
|
+
const injection = await this.buildHarnessInjection(harness, {
|
|
341
|
+
response: plan?.response ?? null,
|
|
342
|
+
docs: plan?.docs ?? [],
|
|
343
|
+
files: plan?.files ?? [],
|
|
344
|
+
task: plan?.task ?? context.intendedAction,
|
|
345
|
+
}, { includeAegisLearnings: context.includeAegisLearnings !== false });
|
|
346
|
+
return {
|
|
347
|
+
prompt: this.buildSystemPrompt(injection),
|
|
348
|
+
packet: harness,
|
|
349
|
+
harnessText: this.extractHarnessText(harness.packet),
|
|
350
|
+
bindingBody,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
async getAegisLearnings(limit) {
|
|
354
|
+
try {
|
|
355
|
+
const params = new URLSearchParams();
|
|
356
|
+
if (limit)
|
|
357
|
+
params.set('limit', String(Math.min(limit, 50)));
|
|
358
|
+
const url = `${this.baseUrl}/api/harness/aegis-learnings${params.toString() ? '?' + params.toString() : ''}`;
|
|
359
|
+
const res = await this.fetchWithRetry(url, {
|
|
360
|
+
method: 'GET',
|
|
361
|
+
headers: {
|
|
362
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
363
|
+
'Content-Type': 'application/json',
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
if (!res.ok)
|
|
367
|
+
return null;
|
|
368
|
+
const data = await res.json();
|
|
369
|
+
return {
|
|
370
|
+
avoidPatterns: data.avoidPatterns || [],
|
|
371
|
+
successPatterns: data.successPatterns || [],
|
|
372
|
+
recentPatterns: (data.recentPatterns || []).map((p) => ({
|
|
373
|
+
name: p.name || '',
|
|
374
|
+
category: p.category || '',
|
|
375
|
+
outcome: p.outcome || '',
|
|
376
|
+
lesson: p.lesson || '',
|
|
377
|
+
})),
|
|
378
|
+
decisionCount: data.decisionCount || 0,
|
|
379
|
+
reflectionCount: data.reflectionCount || 0,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
222
386
|
// ── System prompt builder ───────────────────────────────────────────────
|
|
223
387
|
buildSystemPrompt(injection) {
|
|
224
388
|
const parts = [];
|
|
225
389
|
// 8-lens cognition FIRST — controls all thinking
|
|
226
390
|
parts.push(this.get8LensBlock());
|
|
227
391
|
parts.push('');
|
|
392
|
+
// Aegis cognitive guardrails — quality substrate from backfill learnings
|
|
393
|
+
if (injection.aegisLearnings) {
|
|
394
|
+
const al = injection.aegisLearnings;
|
|
395
|
+
parts.push('## Aegis Cognitive Guardrails');
|
|
396
|
+
parts.push(`Backed by ${al.decisionCount.toLocaleString()} decisions, ${al.reflectionCount.toLocaleString()} reflections.`);
|
|
397
|
+
parts.push('');
|
|
398
|
+
if (al.avoidPatterns.length > 0) {
|
|
399
|
+
parts.push('### Patterns to Avoid (learned from past failures)');
|
|
400
|
+
parts.push('These are anti-patterns that led to hallucinations, errors, or rejected outputs. Reason about them through the 8 lenses and avoid producing output that matches them.');
|
|
401
|
+
for (const p of al.avoidPatterns.slice(0, 15)) {
|
|
402
|
+
parts.push(`- ${p}`);
|
|
403
|
+
}
|
|
404
|
+
parts.push('');
|
|
405
|
+
}
|
|
406
|
+
if (al.successPatterns.length > 0) {
|
|
407
|
+
parts.push('### Patterns to Repeat (learned from successful outputs)');
|
|
408
|
+
parts.push('These patterns consistently produced high-quality output. When appropriate, structure your response using these approaches.');
|
|
409
|
+
for (const p of al.successPatterns.slice(0, 10)) {
|
|
410
|
+
parts.push(`- ${p}`);
|
|
411
|
+
}
|
|
412
|
+
parts.push('');
|
|
413
|
+
}
|
|
414
|
+
if (al.recentPatterns.length > 0) {
|
|
415
|
+
parts.push('### Recent Learnings');
|
|
416
|
+
for (const p of al.recentPatterns.slice(0, 8)) {
|
|
417
|
+
parts.push(`- [${p.outcome}] ${p.name}: ${p.lesson.slice(0, 200)}`);
|
|
418
|
+
}
|
|
419
|
+
parts.push('');
|
|
420
|
+
}
|
|
421
|
+
parts.push('Apply these guardrails through 8-lens cognition — do not list them, internalize them.');
|
|
422
|
+
parts.push('');
|
|
423
|
+
}
|
|
228
424
|
parts.push('---');
|
|
229
425
|
parts.push('name: aria-harness-injection');
|
|
230
426
|
parts.push('description: Combined harness state + plan docs + loaded files');
|
|
@@ -233,11 +429,20 @@ export class HTTPHarnessClient {
|
|
|
233
429
|
parts.push('');
|
|
234
430
|
const p = injection.harness.packet;
|
|
235
431
|
if (p && typeof p === 'object') {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
432
|
+
const rawHarnessText = this.extractHarnessText(p);
|
|
433
|
+
if (rawHarnessText) {
|
|
434
|
+
parts.push('## Aria Harness Substrate');
|
|
435
|
+
parts.push(rawHarnessText);
|
|
436
|
+
parts.push('');
|
|
437
|
+
}
|
|
438
|
+
const metadata = Object.fromEntries(Object.entries(p).filter(([key]) => key !== 'harness' && key !== 'chunks'));
|
|
439
|
+
if (!rawHarnessText || Object.keys(metadata).length > 0) {
|
|
440
|
+
parts.push('## Aria Live State');
|
|
441
|
+
parts.push('```json');
|
|
442
|
+
parts.push(JSON.stringify(rawHarnessText ? metadata : p, null, 2));
|
|
443
|
+
parts.push('```');
|
|
444
|
+
parts.push('');
|
|
445
|
+
}
|
|
241
446
|
}
|
|
242
447
|
if (injection.task) {
|
|
243
448
|
parts.push('## Task');
|
|
@@ -523,6 +728,59 @@ export class HTTPHarnessClient {
|
|
|
523
728
|
}
|
|
524
729
|
}
|
|
525
730
|
catch { /* non-fatal — ownerTier defaults above apply */ }
|
|
731
|
+
// ── Layer 3: fetch harness packet for sub-agent cognition bootstrap ──────
|
|
732
|
+
// Fetch the harness packet now (before writing the handoff) so the path
|
|
733
|
+
// can be embedded in the handoff JSON. Sub-agents read ARIA_HARNESS_PACKET_PATH
|
|
734
|
+
// from the environment (set by the caller after spawnSubAgent returns) OR
|
|
735
|
+
// from the handoff JSON field. Either path eliminates the extra HTTP call
|
|
736
|
+
// inside the sub-agent.
|
|
737
|
+
//
|
|
738
|
+
// Packet paths (tier-aware):
|
|
739
|
+
// Owner: ~/.claude/aria-agent-harness-packet.json
|
|
740
|
+
// Client: /var/lib/aria-licensee/{jti}/aria-agent-harness-packet.json
|
|
741
|
+
//
|
|
742
|
+
// Fail-soft: packet fetch failure logs a warning but does NOT block spawn.
|
|
743
|
+
const packetPath = isClientTier
|
|
744
|
+
? `/var/lib/aria-licensee/${args.jti}/aria-agent-harness-packet.json`
|
|
745
|
+
: `${HOME}/.claude/aria-agent-harness-packet.json`;
|
|
746
|
+
let resolvedPacketPath;
|
|
747
|
+
try {
|
|
748
|
+
const packetResp = await fetch(this.harnessPacketUrl, {
|
|
749
|
+
method: 'POST',
|
|
750
|
+
headers: {
|
|
751
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
752
|
+
'Content-Type': 'application/json',
|
|
753
|
+
},
|
|
754
|
+
body: JSON.stringify({
|
|
755
|
+
stage: 'agent-spawn',
|
|
756
|
+
actor: 'harness-http-client',
|
|
757
|
+
system: 'claude-coding-agent',
|
|
758
|
+
surface: 'platform:harness-http-client',
|
|
759
|
+
isHamza: ownerTier.hamza,
|
|
760
|
+
sessionId: args.sessionId,
|
|
761
|
+
mode: 'subagent',
|
|
762
|
+
}),
|
|
763
|
+
});
|
|
764
|
+
if (packetResp.ok) {
|
|
765
|
+
const packetData = await packetResp.json();
|
|
766
|
+
fsMkdir(fsDirname(packetPath), { recursive: true });
|
|
767
|
+
fsWrite(packetPath, JSON.stringify(packetData, null, 2));
|
|
768
|
+
resolvedPacketPath = packetPath;
|
|
769
|
+
// Also pre-load into this SDK instance's cache so subsequent
|
|
770
|
+
// getHarnessPacket() calls are instant within this process.
|
|
771
|
+
const packetPayload = (packetData.packet ?? packetData);
|
|
772
|
+
this.cachedPacket = {
|
|
773
|
+
packet: packetPayload,
|
|
774
|
+
timestamp: new Date().toISOString(),
|
|
775
|
+
version: '1.0.0',
|
|
776
|
+
};
|
|
777
|
+
this.packetLastFetched = Date.now();
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
catch (_packetErr) {
|
|
781
|
+
// Fail-soft: warn, proceed identity-only (handoff still valid without packet).
|
|
782
|
+
// Network blips should never block sub-agent spawns.
|
|
783
|
+
}
|
|
526
784
|
const handoff = {
|
|
527
785
|
writtenAt: new Date().toISOString(),
|
|
528
786
|
parentSessionId: args.sessionId,
|
|
@@ -533,6 +791,9 @@ export class HTTPHarnessClient {
|
|
|
533
791
|
ownerTier,
|
|
534
792
|
parentLedgerPath: ledgerPath,
|
|
535
793
|
ttlMs: HANDOFF_TTL_MS,
|
|
794
|
+
// harnessPacketPath is set only if packet fetch succeeded. Sub-agents
|
|
795
|
+
// should also check ARIA_HARNESS_PACKET_PATH env (set by caller post-spawn).
|
|
796
|
+
...(resolvedPacketPath ? { harnessPacketPath: resolvedPacketPath } : {}),
|
|
536
797
|
};
|
|
537
798
|
fsMkdir(fsDirname(handoffPath), { recursive: true });
|
|
538
799
|
fsWrite(handoffPath, JSON.stringify(handoff, null, 2));
|
|
@@ -544,12 +805,36 @@ export class HTTPHarnessClient {
|
|
|
544
805
|
allowedActions: args.allowedActions ?? [],
|
|
545
806
|
defectContext: args.defectContext ?? null,
|
|
546
807
|
handoffPath,
|
|
808
|
+
harnessPacketPath: resolvedPacketPath ?? null,
|
|
547
809
|
});
|
|
548
810
|
fsMkdir(fsDirname(ledgerPath), { recursive: true });
|
|
549
811
|
const { appendFileSync: fsAppend } = await import('node:fs');
|
|
550
812
|
fsAppend(ledgerPath, spawnEntry + '\n');
|
|
551
813
|
return handoff;
|
|
552
814
|
}
|
|
815
|
+
/**
|
|
816
|
+
* Returns the environment variables to set for a spawned sub-agent process
|
|
817
|
+
* so it inherits the parent's harness packet without an extra HTTP call.
|
|
818
|
+
* Call after spawnSubAgent() — uses the returned handoff.harnessPacketPath.
|
|
819
|
+
*
|
|
820
|
+
* Usage:
|
|
821
|
+
* const handoff = await sdk.spawnSubAgent(args);
|
|
822
|
+
* const env = sdk.subAgentEnv(handoff);
|
|
823
|
+
* // pass env to your process spawn / Agent tool env block
|
|
824
|
+
*/
|
|
825
|
+
subAgentEnv(handoff) {
|
|
826
|
+
const env = {};
|
|
827
|
+
if (handoff.harnessPacketPath) {
|
|
828
|
+
env['ARIA_HARNESS_PACKET_PATH'] = handoff.harnessPacketPath;
|
|
829
|
+
}
|
|
830
|
+
if (handoff.harnessToken) {
|
|
831
|
+
env['ARIA_HARNESS_TOKEN'] = handoff.harnessToken;
|
|
832
|
+
}
|
|
833
|
+
if (handoff.harnessUrl) {
|
|
834
|
+
env['ARIA_HARNESS_URL'] = handoff.harnessUrl;
|
|
835
|
+
}
|
|
836
|
+
return env;
|
|
837
|
+
}
|
|
553
838
|
/** Pulls sub-agent ledger entries newer than the handoff timestamp and appends
|
|
554
839
|
* them to the parent ledger, deduplicating by `text` prefix (first 100 chars). */
|
|
555
840
|
async mergeSubAgentLedger(parentSessionId, _subAgentSessionId, jti) {
|
|
@@ -655,6 +940,78 @@ export class HTTPHarnessClient {
|
|
|
655
940
|
}
|
|
656
941
|
return { merged, skipped };
|
|
657
942
|
}
|
|
943
|
+
// ── recordDiscovery ──────────────────────────────────────────────────────
|
|
944
|
+
// Writes a finding row to the sub-agent's session ledger on disk so
|
|
945
|
+
// aria-agent-ledger-merge.mjs picks it up after the Agent tool completes.
|
|
946
|
+
//
|
|
947
|
+
// Tier routing (mirrors aria-discovery-record.mjs):
|
|
948
|
+
// Owner tier (no jti) → ~/.claude/aria-discoveries-{session}.jsonl
|
|
949
|
+
// Client tier (jti set) → /var/lib/aria-licensee/{jti}/aria-discoveries-{session}.jsonl
|
|
950
|
+
//
|
|
951
|
+
// Session ID must be the sub-agent's OWN session (not the parent's) so the
|
|
952
|
+
// ledger-merge loop finds a file that is NOT the parentLedgerPath. If no
|
|
953
|
+
// sessionId is supplied we derive one from the handoff parentSessionId + "-sub".
|
|
954
|
+
//
|
|
955
|
+
// Fail-soft: returns {ok:false, error} on write failures — never throws.
|
|
956
|
+
async recordDiscovery(args) {
|
|
957
|
+
if (!args.text || args.text.length < 4) {
|
|
958
|
+
return { ok: false, ledger: '', at: '', error: 'text too short (min 4 chars)' };
|
|
959
|
+
}
|
|
960
|
+
const { existsSync: fsExists, readFileSync: fsRead, appendFileSync: fsAppend, mkdirSync: fsMkdir } = await import('node:fs');
|
|
961
|
+
const { homedir } = await import('node:os');
|
|
962
|
+
const { dirname: fsDirname } = await import('node:path');
|
|
963
|
+
const HOME = homedir();
|
|
964
|
+
const LICENSE_PATH = `${HOME}/.aria/license.json`;
|
|
965
|
+
const HANDOFF_PATH = `${HOME}/.claude/aria-agent-harness-handoff.json`;
|
|
966
|
+
// Tier detection: caller-supplied jti wins; fall back to license file
|
|
967
|
+
let jti = args.jti ?? null;
|
|
968
|
+
let isClientTier = Boolean(jti);
|
|
969
|
+
if (!jti) {
|
|
970
|
+
try {
|
|
971
|
+
if (fsExists(LICENSE_PATH)) {
|
|
972
|
+
const lic = JSON.parse(fsRead(LICENSE_PATH, 'utf8'));
|
|
973
|
+
jti = lic.jti ?? null;
|
|
974
|
+
isClientTier = Boolean(jti);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
catch { /* non-fatal — owner tier */ }
|
|
978
|
+
}
|
|
979
|
+
// Session ID: caller-supplied wins; then handoff-derived (with "-sub" suffix)
|
|
980
|
+
let sessionId = args.sessionId ?? null;
|
|
981
|
+
if (!sessionId) {
|
|
982
|
+
try {
|
|
983
|
+
if (fsExists(HANDOFF_PATH)) {
|
|
984
|
+
const handoff = JSON.parse(fsRead(HANDOFF_PATH, 'utf8'));
|
|
985
|
+
sessionId = handoff.parentSessionId ? `${handoff.parentSessionId}-sub` : 'sub-unknown';
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
catch { /* non-fatal */ }
|
|
989
|
+
}
|
|
990
|
+
sessionId = sessionId || 'sub-unknown';
|
|
991
|
+
const safeSession = String(sessionId).replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
992
|
+
const ledgerPath = isClientTier
|
|
993
|
+
? `/var/lib/aria-licensee/${jti}/aria-discoveries-${safeSession}.jsonl`
|
|
994
|
+
: `${HOME}/.claude/aria-discoveries-${safeSession}.jsonl`;
|
|
995
|
+
const at = new Date().toISOString();
|
|
996
|
+
const row = {
|
|
997
|
+
at,
|
|
998
|
+
session: sessionId,
|
|
999
|
+
kind: args.kind || 'observation',
|
|
1000
|
+
text: args.text,
|
|
1001
|
+
refs: args.refs || [],
|
|
1002
|
+
evidence: args.evidence ?? null,
|
|
1003
|
+
source: args.source || 'sub-agent-sdk',
|
|
1004
|
+
resolution_status: args.resolution_status || 'open',
|
|
1005
|
+
};
|
|
1006
|
+
try {
|
|
1007
|
+
fsMkdir(fsDirname(ledgerPath), { recursive: true });
|
|
1008
|
+
fsAppend(ledgerPath, JSON.stringify(row) + '\n');
|
|
1009
|
+
return { ok: true, ledger: ledgerPath, at };
|
|
1010
|
+
}
|
|
1011
|
+
catch (err) {
|
|
1012
|
+
return { ok: false, ledger: ledgerPath, at, error: err.message };
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
658
1015
|
// ── verifyClaim ──────────────────────────────────────────────────────────
|
|
659
1016
|
// POST /api/harness/verify-claim — persists a claim/evidence pair to
|
|
660
1017
|
// aria_cognition_corpus and returns a verdict. Fail-soft: if the server-side
|
|
@@ -694,6 +1051,376 @@ export class HTTPHarnessClient {
|
|
|
694
1051
|
};
|
|
695
1052
|
}
|
|
696
1053
|
}
|
|
1054
|
+
// ── postJson — generic SDK-routed JSON POST ────────────────────────────
|
|
1055
|
+
// Hamza 2026-04-27 directive: "use the SDK - use it, enforce it all". The
|
|
1056
|
+
// typed primitives above (consult, validateOutput, gardenTurn) cover Aria's
|
|
1057
|
+
// own control-plane endpoints. This method is the canonical primitive for
|
|
1058
|
+
// bridge POSTs (e.g., Telegram → /chat) so internal bridges inherit the
|
|
1059
|
+
// SDK's retry-with-backoff (250/500/1000ms) and audit-log discipline
|
|
1060
|
+
// instead of using raw fetch().
|
|
1061
|
+
//
|
|
1062
|
+
// Returns:
|
|
1063
|
+
// - { ok: true, status, data } on 2xx
|
|
1064
|
+
// - { ok: false, status, errorBody } on non-2xx (does NOT throw — caller
|
|
1065
|
+
// decides whether to fall back, retry semantically, or surface to user)
|
|
1066
|
+
// - throws on network errors after retries exhausted (real fetch failures)
|
|
1067
|
+
//
|
|
1068
|
+
// Headers are merged with Authorization (if apiKey is set) and
|
|
1069
|
+
// Content-Type: application/json. Caller can override either.
|
|
1070
|
+
async postJson(url, body, extraHeaders = {}) {
|
|
1071
|
+
const headers = {
|
|
1072
|
+
'Content-Type': 'application/json',
|
|
1073
|
+
...(this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}),
|
|
1074
|
+
...extraHeaders,
|
|
1075
|
+
};
|
|
1076
|
+
const res = await this.fetchWithRetry(url, {
|
|
1077
|
+
method: 'POST',
|
|
1078
|
+
headers,
|
|
1079
|
+
body: JSON.stringify(body),
|
|
1080
|
+
});
|
|
1081
|
+
if (!res.ok) {
|
|
1082
|
+
const errorBody = await res.text().catch(() => '');
|
|
1083
|
+
return { ok: false, status: res.status, errorBody };
|
|
1084
|
+
}
|
|
1085
|
+
const data = (await res.json());
|
|
1086
|
+
return { ok: true, status: res.status, data };
|
|
1087
|
+
}
|
|
1088
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1089
|
+
// ARISTOTLE 3-PHASE COGNITIVE PRIMITIVES
|
|
1090
|
+
// Dispatches to POST /api/harness/aristotle-noor with a `phase` field.
|
|
1091
|
+
// The harness route delegates to runAristotleNoorPipeline in aria-soul.
|
|
1092
|
+
//
|
|
1093
|
+
// Transport contract (per doctrine):
|
|
1094
|
+
// - NO deadline-based timeouts — fetchWithRetry uses 3 error-count retries
|
|
1095
|
+
// with 250ms / 500ms / 1000ms backoff. Real network faults (ECONNREFUSED,
|
|
1096
|
+
// EHOSTUNREACH) reject immediately; slow-but-alive endpoints get a chance.
|
|
1097
|
+
// - LOUD failure — non-2xx responses throw, never fail-open silently.
|
|
1098
|
+
// Callers decide whether to surface or recover (per feedback_non_blocking_errors_unacceptable.md).
|
|
1099
|
+
// - Tier-gating — owner-tier callers set `aristotleEnabled: true` by default;
|
|
1100
|
+
// client-tier callers receive it as opt-in via the `enabled` config field.
|
|
1101
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1102
|
+
/**
|
|
1103
|
+
* ARISTOTLE PRE-PHASE
|
|
1104
|
+
* Fires before an LLM call or tool action. Runs: Fitrah hard-gate,
|
|
1105
|
+
* wisdom pull (principles + decisions), research pull, DeepSoulBridge,
|
|
1106
|
+
* and CleanCognition substrate check.
|
|
1107
|
+
*
|
|
1108
|
+
* Throws on transport-level failures per feedback_non_blocking_errors_unacceptable.md.
|
|
1109
|
+
* If Fitrah vetoes, result.fitrahVetoed === true — caller MUST emit a refusal,
|
|
1110
|
+
* not silently continue.
|
|
1111
|
+
*
|
|
1112
|
+
* @param message The user message or intent string being processed.
|
|
1113
|
+
* @param sessionId Session ID for telemetry + hive routing.
|
|
1114
|
+
* @param context Optional context overrides (userId, isHamza, tier, etc.).
|
|
1115
|
+
*/
|
|
1116
|
+
async aristotlePre(message, sessionId, context) {
|
|
1117
|
+
const t0 = Date.now();
|
|
1118
|
+
const url = `${this.baseUrl}/api/harness/aristotle-noor`;
|
|
1119
|
+
const res = await this.fetchWithRetry(url, {
|
|
1120
|
+
method: 'POST',
|
|
1121
|
+
headers: {
|
|
1122
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
1123
|
+
'Content-Type': 'application/json',
|
|
1124
|
+
},
|
|
1125
|
+
body: JSON.stringify({
|
|
1126
|
+
phase: 'pre',
|
|
1127
|
+
message,
|
|
1128
|
+
sessionId,
|
|
1129
|
+
userId: context?.userId,
|
|
1130
|
+
isHamza: context?.isHamza,
|
|
1131
|
+
isGroupChat: context?.isGroupChat,
|
|
1132
|
+
tier: context?.tier,
|
|
1133
|
+
}),
|
|
1134
|
+
});
|
|
1135
|
+
if (!res.ok) {
|
|
1136
|
+
const body = await res.text().catch(() => '');
|
|
1137
|
+
throw new Error(`[aristotlePre] harness route responded ${res.status} ${res.statusText}: ${body}`);
|
|
1138
|
+
}
|
|
1139
|
+
const data = (await res.json());
|
|
1140
|
+
return {
|
|
1141
|
+
fired: data.fired ?? [],
|
|
1142
|
+
fitrahVetoed: data.fitrahVetoed ?? false,
|
|
1143
|
+
fitrahAlignment: data.fitrahAlignment ?? 1.0,
|
|
1144
|
+
qualityScore: data.qualityScore ?? 100,
|
|
1145
|
+
reAuthorSignal: data.reAuthorSignal ?? false,
|
|
1146
|
+
notes: data.notes ?? [],
|
|
1147
|
+
soulCharge: data.soulCharge ?? null,
|
|
1148
|
+
soulManifoldStatus: data.soulManifoldStatus ?? null,
|
|
1149
|
+
ghazaliVerdict: data.ghazaliVerdict ?? null,
|
|
1150
|
+
latencyMs: data.latencyMs ?? Date.now() - t0,
|
|
1151
|
+
dispatched: true,
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* ARISTOTLE MID-PHASE
|
|
1156
|
+
* Fires after context is built but before the LLM call. Runs: MetaCognitive
|
|
1157
|
+
* confidence snapshot and ethical keyword check on the planned approach.
|
|
1158
|
+
*
|
|
1159
|
+
* @param message Original user message.
|
|
1160
|
+
* @param sessionId Session ID.
|
|
1161
|
+
* @param plannedApproach The drafted approach / plan string for mid-flight check.
|
|
1162
|
+
* @param context Optional context overrides.
|
|
1163
|
+
*/
|
|
1164
|
+
async aristotleMid(message, sessionId, plannedApproach, context) {
|
|
1165
|
+
const t0 = Date.now();
|
|
1166
|
+
const url = `${this.baseUrl}/api/harness/aristotle-noor`;
|
|
1167
|
+
const res = await this.fetchWithRetry(url, {
|
|
1168
|
+
method: 'POST',
|
|
1169
|
+
headers: {
|
|
1170
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
1171
|
+
'Content-Type': 'application/json',
|
|
1172
|
+
},
|
|
1173
|
+
body: JSON.stringify({
|
|
1174
|
+
phase: 'mid',
|
|
1175
|
+
message,
|
|
1176
|
+
sessionId,
|
|
1177
|
+
plannedApproach,
|
|
1178
|
+
userId: context?.userId,
|
|
1179
|
+
tier: context?.tier,
|
|
1180
|
+
}),
|
|
1181
|
+
});
|
|
1182
|
+
if (!res.ok) {
|
|
1183
|
+
const body = await res.text().catch(() => '');
|
|
1184
|
+
throw new Error(`[aristotleMid] harness route responded ${res.status} ${res.statusText}: ${body}`);
|
|
1185
|
+
}
|
|
1186
|
+
const data = (await res.json());
|
|
1187
|
+
return {
|
|
1188
|
+
fired: data.fired ?? [],
|
|
1189
|
+
fitrahVetoed: data.fitrahVetoed ?? false,
|
|
1190
|
+
fitrahAlignment: data.fitrahAlignment ?? 1.0,
|
|
1191
|
+
qualityScore: data.qualityScore ?? 100,
|
|
1192
|
+
reAuthorSignal: data.reAuthorSignal ?? false,
|
|
1193
|
+
notes: data.notes ?? [],
|
|
1194
|
+
soulCharge: data.soulCharge ?? null,
|
|
1195
|
+
soulManifoldStatus: data.soulManifoldStatus ?? null,
|
|
1196
|
+
ghazaliVerdict: data.ghazaliVerdict ?? null,
|
|
1197
|
+
latencyMs: data.latencyMs ?? Date.now() - t0,
|
|
1198
|
+
dispatched: true,
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* ARISTOTLE POST-PHASE
|
|
1203
|
+
* Fires after the LLM response, before emission. Runs: 8-Lens Detector,
|
|
1204
|
+
* Predictor, SelfReflection (on high-stakes turns), and quality scoring.
|
|
1205
|
+
*
|
|
1206
|
+
* If result.reAuthorSignal === true, the response has 8-lens violations —
|
|
1207
|
+
* per doctrine the caller MUST surface the signal, never silently strip.
|
|
1208
|
+
*
|
|
1209
|
+
* @param message Original user message.
|
|
1210
|
+
* @param response The LLM-generated response to gate.
|
|
1211
|
+
* @param sessionId Session ID.
|
|
1212
|
+
* @param context Optional context overrides (tier, isFirstOfSession).
|
|
1213
|
+
*/
|
|
1214
|
+
async aristotlePost(message, response, sessionId, context) {
|
|
1215
|
+
const t0 = Date.now();
|
|
1216
|
+
const url = `${this.baseUrl}/api/harness/aristotle-noor`;
|
|
1217
|
+
const res = await this.fetchWithRetry(url, {
|
|
1218
|
+
method: 'POST',
|
|
1219
|
+
headers: {
|
|
1220
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
1221
|
+
'Content-Type': 'application/json',
|
|
1222
|
+
},
|
|
1223
|
+
body: JSON.stringify({
|
|
1224
|
+
phase: 'post',
|
|
1225
|
+
message,
|
|
1226
|
+
draft: response,
|
|
1227
|
+
sessionId,
|
|
1228
|
+
userId: context?.userId,
|
|
1229
|
+
tier: context?.tier,
|
|
1230
|
+
isFirstOfSession: context?.isFirstOfSession,
|
|
1231
|
+
}),
|
|
1232
|
+
});
|
|
1233
|
+
if (!res.ok) {
|
|
1234
|
+
const body = await res.text().catch(() => '');
|
|
1235
|
+
throw new Error(`[aristotlePost] harness route responded ${res.status} ${res.statusText}: ${body}`);
|
|
1236
|
+
}
|
|
1237
|
+
const data = (await res.json());
|
|
1238
|
+
return {
|
|
1239
|
+
fired: data.fired ?? [],
|
|
1240
|
+
fitrahVetoed: data.fitrahVetoed ?? false,
|
|
1241
|
+
fitrahAlignment: data.fitrahAlignment ?? 1.0,
|
|
1242
|
+
qualityScore: data.qualityScore ?? 100,
|
|
1243
|
+
reAuthorSignal: data.reAuthorSignal ?? false,
|
|
1244
|
+
notes: data.notes ?? [],
|
|
1245
|
+
soulCharge: data.soulCharge ?? null,
|
|
1246
|
+
soulManifoldStatus: data.soulManifoldStatus ?? null,
|
|
1247
|
+
ghazaliVerdict: data.ghazaliVerdict ?? null,
|
|
1248
|
+
latencyMs: data.latencyMs ?? Date.now() - t0,
|
|
1249
|
+
dispatched: true,
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1253
|
+
// NOOR COGNITIVE PRIMITIVES
|
|
1254
|
+
// Dispatches to POST /api/harness/noor with an `operation` discriminator.
|
|
1255
|
+
// noor-core.ts is NOT modified — these are HTTP wrappers that call its
|
|
1256
|
+
// exposed surface via the harness route.
|
|
1257
|
+
//
|
|
1258
|
+
// noor-core.ts banner: "ONLY ARIA CAN CODE ARIA. No councils. No subagents.
|
|
1259
|
+
// No other LLMs." — complied. We call, never modify.
|
|
1260
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1261
|
+
/**
|
|
1262
|
+
* NOOR RECOGNIZE (Kashf — eigenspace recognition, not generation)
|
|
1263
|
+
* Projects the query string (via harness-side embedding) onto Aria's
|
|
1264
|
+
* eigenspace manifold and returns the nearest recognized response + soul
|
|
1265
|
+
* distance + ethical membrane status + Ghazali 8-lens verdict.
|
|
1266
|
+
*
|
|
1267
|
+
* The harness routes the query through the manifold service (gRPC) if
|
|
1268
|
+
* NOOR_EIGENSPACE_SOURCE=manifold, otherwise uses local eigenspace.
|
|
1269
|
+
*
|
|
1270
|
+
* @param query The input string to recognize on the manifold.
|
|
1271
|
+
* @param context Optional context (sessionId, userId) for telemetry.
|
|
1272
|
+
*/
|
|
1273
|
+
async noorRecognize(query, context) {
|
|
1274
|
+
const t0 = Date.now();
|
|
1275
|
+
const url = `${this.baseUrl}/api/harness/noor`;
|
|
1276
|
+
const res = await this.fetchWithRetry(url, {
|
|
1277
|
+
method: 'POST',
|
|
1278
|
+
headers: {
|
|
1279
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
1280
|
+
'Content-Type': 'application/json',
|
|
1281
|
+
},
|
|
1282
|
+
body: JSON.stringify({
|
|
1283
|
+
operation: 'recognize',
|
|
1284
|
+
query,
|
|
1285
|
+
sessionId: context?.sessionId,
|
|
1286
|
+
userId: context?.userId,
|
|
1287
|
+
}),
|
|
1288
|
+
});
|
|
1289
|
+
if (!res.ok) {
|
|
1290
|
+
const body = await res.text().catch(() => '');
|
|
1291
|
+
throw new Error(`[noorRecognize] harness route responded ${res.status} ${res.statusText}: ${body}`);
|
|
1292
|
+
}
|
|
1293
|
+
const data = (await res.json());
|
|
1294
|
+
return {
|
|
1295
|
+
nearestText: data.nearestText ?? '',
|
|
1296
|
+
soulDistance: data.soulDistance ?? 0,
|
|
1297
|
+
confidence: data.confidence ?? 0,
|
|
1298
|
+
withinMembrane: data.withinMembrane ?? true,
|
|
1299
|
+
soulCharge: data.soulCharge ?? 0,
|
|
1300
|
+
projectionComponents: data.projectionComponents ?? [],
|
|
1301
|
+
ghazaliVerdict: data.ghazaliVerdict ?? null,
|
|
1302
|
+
manifoldHealth: data.manifoldHealth ?? null,
|
|
1303
|
+
dispatched: true,
|
|
1304
|
+
latencyMs: data.latencyMs ?? Date.now() - t0,
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* NOOR FORGE — self-generated tool invocation via 5 primitives
|
|
1309
|
+
* Composes a named primitive chain (http, sql, file_read, file_write, pub_sub)
|
|
1310
|
+
* and executes it through the harness-side NoorForge engine. The harness
|
|
1311
|
+
* applies the ethical membrane check (checkEthicalAlignment) before any
|
|
1312
|
+
* primitive fires — rejected intents return success=false, ethicallyApproved=false.
|
|
1313
|
+
*
|
|
1314
|
+
* @param intent Description of what the forged tool should accomplish.
|
|
1315
|
+
* @param primitives Ordered list of primitive descriptors to execute in sequence.
|
|
1316
|
+
* @param context Optional context for telemetry.
|
|
1317
|
+
*/
|
|
1318
|
+
async noorForge(intent, primitives, context) {
|
|
1319
|
+
const t0 = Date.now();
|
|
1320
|
+
const url = `${this.baseUrl}/api/harness/noor`;
|
|
1321
|
+
const res = await this.fetchWithRetry(url, {
|
|
1322
|
+
method: 'POST',
|
|
1323
|
+
headers: {
|
|
1324
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
1325
|
+
'Content-Type': 'application/json',
|
|
1326
|
+
},
|
|
1327
|
+
body: JSON.stringify({
|
|
1328
|
+
operation: 'forge',
|
|
1329
|
+
intent,
|
|
1330
|
+
primitives,
|
|
1331
|
+
sessionId: context?.sessionId,
|
|
1332
|
+
userId: context?.userId,
|
|
1333
|
+
}),
|
|
1334
|
+
});
|
|
1335
|
+
if (!res.ok) {
|
|
1336
|
+
const body = await res.text().catch(() => '');
|
|
1337
|
+
throw new Error(`[noorForge] harness route responded ${res.status} ${res.statusText}: ${body}`);
|
|
1338
|
+
}
|
|
1339
|
+
const data = (await res.json());
|
|
1340
|
+
return {
|
|
1341
|
+
success: data.success ?? false,
|
|
1342
|
+
toolName: data.toolName ?? `forged_${Date.now()}`,
|
|
1343
|
+
ethicallyApproved: data.ethicallyApproved ?? false,
|
|
1344
|
+
totalDurationMs: data.totalDurationMs ?? Date.now() - t0,
|
|
1345
|
+
results: data.results ?? [],
|
|
1346
|
+
dispatched: true,
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1350
|
+
// HARNESS CONSULT WITH ARISTOTLE — opt-in 3-phase wrapping
|
|
1351
|
+
//
|
|
1352
|
+
// Wraps getBoundHarnessAndPrompt() with pre + post Aristotle phases.
|
|
1353
|
+
// Per the harness packet cognition_runtime_rule: "Aristotle/Taddabur are
|
|
1354
|
+
// primary cognition. Do not replace contemplation with a dashboard state."
|
|
1355
|
+
// Aristotle fires EVERY consult for owner-tier; client-tier requires
|
|
1356
|
+
// explicit `aristotleEnabled: true` in options (default: false).
|
|
1357
|
+
//
|
|
1358
|
+
// Mid-phase is optional — pass `plannedApproach` to activate it between
|
|
1359
|
+
// packet fetch and the LLM call. Most callers omit mid-phase.
|
|
1360
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
1361
|
+
/**
|
|
1362
|
+
* Harness consult with Aristotle 3-phase wrapping.
|
|
1363
|
+
*
|
|
1364
|
+
* Flow:
|
|
1365
|
+
* 1. aristotlePre() — Fitrah gate, wisdom, research, soul state
|
|
1366
|
+
* 2. getBoundHarnessAndPrompt() — packet + system prompt
|
|
1367
|
+
* 3. aristotleMid() — MetaCognitive + ethical check (if plannedApproach provided)
|
|
1368
|
+
* 4. [caller calls LLM with the returned prompt]
|
|
1369
|
+
* 5. Call aristotlePost() from the caller with the LLM response
|
|
1370
|
+
* (post-phase is caller-side because the SDK doesn't own the LLM call)
|
|
1371
|
+
*
|
|
1372
|
+
* Returns the BoundHarnessPromptResult augmented with the pre-phase result.
|
|
1373
|
+
* If Fitrah vetoes, throws — the caller must handle the veto (emit refusal).
|
|
1374
|
+
*
|
|
1375
|
+
* @param context HarnessBindingContext (same shape as getBoundHarnessAndPrompt).
|
|
1376
|
+
* @param plan Optional plan docs / files (same shape as getBoundHarnessAndPrompt).
|
|
1377
|
+
* @param options Aristotle control options.
|
|
1378
|
+
* @param options.aristotleEnabled Whether Aristotle fires. Default true for this method.
|
|
1379
|
+
* @param options.plannedApproach Optional planned approach string — activates mid-phase.
|
|
1380
|
+
* @param options.tier Tier hint for Aristotle ('owner'|'client'|etc.).
|
|
1381
|
+
*/
|
|
1382
|
+
async getBoundHarnessAndPromptWithAristotle(context, plan, options) {
|
|
1383
|
+
const enabled = options?.aristotleEnabled !== false; // default ON
|
|
1384
|
+
let preResult = null;
|
|
1385
|
+
let midResult = null;
|
|
1386
|
+
const message = context.message ?? context.intendedAction ?? 'harness consult';
|
|
1387
|
+
// ── Phase 1: PRE ────────────────────────────────────────────────────────
|
|
1388
|
+
if (enabled) {
|
|
1389
|
+
try {
|
|
1390
|
+
preResult = await this.aristotlePre(message, context.sessionId, {
|
|
1391
|
+
userId: context.userId,
|
|
1392
|
+
tier: options?.tier,
|
|
1393
|
+
});
|
|
1394
|
+
if (preResult.fitrahVetoed) {
|
|
1395
|
+
throw new Error(`[aristotlePre] Fitrah veto — alignment=${preResult.fitrahAlignment.toFixed(2)}. Caller must emit honest refusal.`);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
catch (err) {
|
|
1399
|
+
// Re-throw Fitrah veto (named Error pattern). Log transport faults.
|
|
1400
|
+
if (err.message.includes('Fitrah veto'))
|
|
1401
|
+
throw err;
|
|
1402
|
+
console.error('[getBoundHarnessAndPromptWithAristotle] aristotlePre transport fault:', err.message);
|
|
1403
|
+
// Transport faults are LOUD but non-blocking for the consult itself.
|
|
1404
|
+
// The pre-phase result stays null so callers know Aristotle didn't fire.
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
// ── Phase 2: Harness packet + system prompt ─────────────────────────────
|
|
1408
|
+
const bound = await this.getBoundHarnessAndPrompt(context, plan);
|
|
1409
|
+
// ── Phase 3: MID (optional — only when plannedApproach is provided) ─────
|
|
1410
|
+
if (enabled && options?.plannedApproach) {
|
|
1411
|
+
try {
|
|
1412
|
+
midResult = await this.aristotleMid(message, context.sessionId, options.plannedApproach, {
|
|
1413
|
+
userId: context.userId,
|
|
1414
|
+
tier: options?.tier,
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
catch (err) {
|
|
1418
|
+
console.error('[getBoundHarnessAndPromptWithAristotle] aristotleMid transport fault:', err.message);
|
|
1419
|
+
// Non-blocking — mid-phase unavailability doesn't stop the LLM call.
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
return { ...bound, aristotlePre: preResult, aristotleMid: midResult };
|
|
1423
|
+
}
|
|
697
1424
|
// ── Retry + exponential backoff helper ──────────────────────────────────
|
|
698
1425
|
// Hamza 2026-04-27: "YES ADD RETRY AND BACKOFF BUT FUCK UR CIRCUIT BREAKER
|
|
699
1426
|
// THAT NUST LEAVES HER BROKEN WE NEED SELF HEAL!!!" — every fetch retries
|
|
@@ -724,4 +1451,19 @@ export const harness = {
|
|
|
724
1451
|
getInstance: HTTPHarnessClient.getInstance.bind(HTTPHarnessClient),
|
|
725
1452
|
resetInstance: HTTPHarnessClient.resetInstance.bind(HTTPHarnessClient),
|
|
726
1453
|
};
|
|
1454
|
+
export function bindingContext(role, sessionId, stage, intendedAction, rationale) {
|
|
1455
|
+
return {
|
|
1456
|
+
role,
|
|
1457
|
+
sessionId,
|
|
1458
|
+
stage,
|
|
1459
|
+
intendedAction,
|
|
1460
|
+
rationale,
|
|
1461
|
+
correlationId: randomUUID(),
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
export async function getBoundHarnessAndPrompt(context, plan, client) {
|
|
1465
|
+
const sdk = client ?? HTTPHarnessClient.getInstance();
|
|
1466
|
+
return sdk.getBoundHarnessAndPrompt(context, plan);
|
|
1467
|
+
}
|
|
1468
|
+
export * from './runWithCognition.js';
|
|
727
1469
|
//# sourceMappingURL=index.js.map
|