@cgh567/agent 2.4.1 → 2.4.3
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/bin/helios +0 -0
- package/bin/helios-rpc-node-wrapper.cjs +0 -0
- package/bin/helios-rpc-wrapper.sh +0 -0
- package/daemon/adapters/helios-rpc-adapter.js +47 -25
- package/daemon/adapters/tui_wakeup.js +8 -0
- package/daemon/config/com.familiar.helios-daemon.plist +5 -0
- package/daemon/config/helios-daemon.service +4 -0
- package/daemon/context-enrichment.js +59 -21
- package/daemon/daemon-manager.js +1 -1
- package/daemon/db/email-infrastructure-migrate.js +192 -0
- package/daemon/db/hbo-core-migrate.js +189 -0
- package/daemon/helios-api.js +723 -57
- package/daemon/helios-company-daemon.js +616 -134
- package/daemon/lib/harada/cascade-judge.js +12 -50
- package/daemon/lib/harada/mandala.js +20 -0
- package/daemon/lib/harada/pillar-dispatcher.js +1 -1
- package/daemon/lib/harada/project-factory.js +7 -2
- package/daemon/lib/hbo-bridge.js +32 -13
- package/daemon/lib/hed-engine.js +10 -292
- package/daemon/lib/helios-hitl-host.js +15 -2
- package/daemon/lib/hitl-interaction-service.js +0 -0
- package/daemon/lib/memgraph-verify.js +38 -33
- package/daemon/lib/project-drift-detector.js +7 -17
- package/daemon/lib/project-semantic-updater.js +1 -14
- package/daemon/lib/task-completion-processor.js +11 -0
- package/daemon/lib/wizard-engine.js +57 -6
- package/daemon/routes/channels.js +10 -5
- package/daemon/routes/harada-map.js +11 -48
- package/daemon/routes/hbo.js +342 -75
- package/daemon/routes/hitl.js +0 -0
- package/daemon/routes/project.js +194 -62
- package/daemon/routes/routines.js +14 -0
- package/daemon/routes/tasks.js +15 -1
- package/daemon/routes/wizard.js +11 -4
- package/daemon/schema-apply.js +174 -0
- package/daemon/schema-definitions.js +423 -0
- package/daemon/schema-migrations-hbo.js +10 -0
- package/daemon/schema-migrations-hed.js +18 -0
- package/daemon/schema-migrations-hitl.js +0 -0
- package/daemon/schema-migrations-proj.js +131 -0
- package/extensions/001-tool-output-cap.ts +0 -0
- package/extensions/context-compaction.ts +45 -26
- package/extensions/cortex/activation-bridge.ts +5 -0
- package/extensions/cortex/learn.ts +26 -0
- package/extensions/cortex/wal-replay.ts +91 -0
- package/extensions/email/backfill.ts +0 -0
- package/extensions/helios-governance/analysis/ambiguity.ts +0 -0
- package/extensions/helios-governance/analysis/compliance.ts +0 -0
- package/extensions/helios-governance/analysis/long-task-detector.ts +0 -0
- package/extensions/helios-governance/analysis/output-contract.ts +0 -0
- package/extensions/helios-governance/analysis/patterns.ts +0 -0
- package/extensions/helios-governance/analysis/preflight.ts +0 -0
- package/extensions/helios-governance/analysis/recurring-violations.ts +0 -0
- package/extensions/helios-governance/analysis/task-classification.ts +0 -0
- package/extensions/helios-governance/analysis/task-intent.ts +0 -0
- package/extensions/helios-governance/gates/high-impact.ts +1 -1
- package/extensions/helios-governance/handlers/_jiti-require.ts +15 -8
- package/extensions/helios-governance/handlers/proxy-test-detector.ts +0 -0
- package/extensions/hema-dispatch-v3/graph-memory.ts +10 -0
- package/extensions/hema-dispatch-v3/index.ts +72 -47
- package/extensions/lib/elo-engine.js +0 -0
- package/extensions/lib/elo-engine.test.js +0 -0
- package/extensions/memgraph-autostart.ts +13 -0
- package/extensions/neuroplastic-eval.ts +0 -0
- package/extensions/shadow-loop/index.ts +0 -0
- package/extensions/warm-tick/warm-tick-maintenance.ts +8 -0
- package/lib/__tests__/hbo-core-store.test.js +238 -0
- package/lib/brain-v2-budget.js +0 -0
- package/lib/brain-v2-circuit-breaker.js +0 -0
- package/lib/brain-v2.js +0 -0
- package/lib/broker/adaptive-throttle.js +0 -0
- package/lib/broker/batch-coalescer.js +0 -0
- package/lib/broker/bulkhead.js +0 -0
- package/lib/broker/channel-registry.js +0 -0
- package/lib/broker/circuit-breaker.js +0 -0
- package/lib/broker/evidence-cache.js +0 -0
- package/lib/broker/health-monitor.js +0 -0
- package/lib/broker/mage-queue.js +0 -0
- package/lib/broker/priority-queue.js +0 -0
- package/lib/broker/server.js.bak-error2-fix +0 -0
- package/lib/broker/session-registry.js +0 -0
- package/lib/broker/singleton-timers.js +0 -0
- package/lib/broker/types.d.ts +0 -0
- package/lib/broker/vegas-limit.js +0 -0
- package/lib/compression/dist/ccr-store.js +74 -0
- package/lib/compression/dist/content-router.js +115 -0
- package/lib/compression/dist/pipeline.js +113 -0
- package/lib/compression/dist/server.js +265 -0
- package/lib/compression/dist/smart-crusher.js +251 -0
- package/lib/context-budget.ts +0 -0
- package/lib/context-firewall.js +0 -0
- package/lib/crm/integration/triage-bridge.js +0 -0
- package/lib/email-utils.ts +0 -0
- package/lib/eval/__tests__/preflight-checker.test.ts +0 -0
- package/lib/eval/__tests__/task-instruction-parser.test.ts +0 -0
- package/lib/eval/__tests__/verifier-runner.test.ts +0 -0
- package/lib/eval/index.ts +0 -0
- package/lib/eval/preflight-checker.ts +0 -0
- package/lib/eval/task-domain-classifier.ts +0 -0
- package/lib/eval/task-instruction-parser.ts +0 -0
- package/lib/eval/verifier-runner.ts +0 -0
- package/lib/event-bus.d.ts +0 -0
- package/lib/event-bus.mts +1 -1
- package/lib/governance-context-selector.ts +0 -0
- package/lib/graph/generate-extension-embeddings.js +0 -0
- package/lib/graph/generate-static-embeddings.js +0 -0
- package/lib/graph/lib/utils.js +1 -1
- package/lib/graph-audit.d.ts +0 -0
- package/lib/graph-availability.js +62 -0
- package/lib/hbo-core-store.compiled.js +834 -0
- package/lib/hbo-core-store.js +124 -0
- package/lib/hbo-core-store.ts +908 -0
- package/lib/mesh-circuit-breaker.js +0 -0
- package/lib/mission-loop/lesson-extractor.ts +0 -0
- package/lib/mission-loop/mental-model-scorer.ts +0 -0
- package/lib/mission-loop/occ-detector.ts +0 -0
- package/lib/mission-loop/query-variants.ts +0 -0
- package/lib/mission-loop/verifier-check.ts +0 -0
- package/lib/skill-reference-builder.ts +0 -0
- package/lib/telemetry/token-breakdown.ts +0 -0
- package/lib/tool-compressor.ts +0 -0
- package/lib/triage-core/classifier.ts +3 -2
- package/lib/triage-core/graph/schema.cypher +10 -0
- package/lib/triage-core/legal-routing.ts +0 -0
- package/lib/triage-core/mental-model/dunbar-classifier.ts +0 -0
- package/lib/triage-core/mental-model/enrich-all.ts +0 -0
- package/lib/triage-core/mental-model/identity-resolver.ts +0 -0
- package/lib/triage-core/mental-model/key-facts.ts +1 -2
- package/lib/triage-core/mental-model/model-assembler.ts +0 -0
- package/lib/triage-core/orchestrator.ts +4 -11
- package/lib/triage-core/orchestrator.ts.bak-r005-r006-r008 +0 -0
- package/package.json +18 -8
- package/skills/helios-business-operator/services/signals/upwork-signals.js +0 -0
- package/skills/talisman-ceo/SKILL.md +23 -25
- package/skills/talisman-comms/SKILL.md +5 -5
- package/skills/talisman-engineering/SKILL.md +5 -5
- package/skills/talisman-finance/SKILL.md +10 -8
- package/skills/talisman-marketing/SKILL.md +10 -10
- package/skills/talisman-sales/SKILL.md +12 -15
- package/skills/talisman-support/SKILL.md +5 -5
- package/agents/business/talisman-ceo.md +0 -183
- package/agents/business/talisman-comms.md +0 -257
- package/agents/business/talisman-cto.md +0 -153
- package/agents/business/talisman-finance.md +0 -246
- package/agents/business/talisman-marketing.md +0 -240
- package/agents/business/talisman-sales.md +0 -242
- package/agents/business/talisman-support.md +0 -236
- package/daemon/lib/approval-expiry.js +0 -162
- package/daemon/lib/blast-radius-analyzer.js +0 -75
- package/daemon/lib/domain-bootstrap-orchestrator.js +0 -267
- package/daemon/lib/forensic-log.js +0 -113
- package/daemon/lib/goal-research-pipeline.js +0 -644
- package/daemon/lib/harada/cascade-research-dispatcher.js +0 -261
- package/daemon/lib/headroom-middleware.js +0 -167
- package/daemon/lib/headroom-proxy-manager.js +0 -623
- package/daemon/lib/mental-model-cache.js +0 -96
- package/daemon/lib/project-factory.js +0 -47
- package/daemon/lib/session-log-reader.js +0 -93
- package/daemon/routes/hed.js +0 -133
- package/lib/graph/learning/headroom-learn-bridge.js +0 -215
- package/skills/helios-bookkeeping/SKILL.md +0 -321
- package/skills/helios-briefer/SKILL.md +0 -44
- package/skills/helios-client-relations/SKILL.md +0 -322
- package/skills/helios-personal-triager/SKILL.md +0 -45
- package/skills/helios-recruitment/SKILL.md +0 -317
- package/skills/helios-relationship-nudger/SKILL.md +0 -77
- package/skills/helios-researcher/SKILL.md +0 -44
- package/skills/helios-scheduler/SKILL.md +0 -58
- package/skills/helios-tax-analyst/SKILL.md +0 -280
|
@@ -345,35 +345,55 @@ export default function contextCompaction(pi: ExtensionAPI): void {
|
|
|
345
345
|
metrics.compactionTriggered++;
|
|
346
346
|
metrics.lastCompactionAt = Date.now();
|
|
347
347
|
|
|
348
|
-
// ──
|
|
349
|
-
//
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
// per content type (JSON arrays → SmartCrusher, prose → Kompress-base).
|
|
353
|
-
// CCR stores originals locally so the agent can retrieve them on demand.
|
|
348
|
+
// ── Helios Compression (L1 + L2 replacement) ────────────────────────
|
|
349
|
+
// Calls the Helios Compression Server (lib/compression/server.ts) via
|
|
350
|
+
// HTTP. The server runs as a sidecar process managed by HeadroomProxyManager.
|
|
351
|
+
// Its URL is injected into the Pi subprocess env as HEADROOM_PROXY_URL.
|
|
354
352
|
//
|
|
355
|
-
//
|
|
356
|
-
//
|
|
357
|
-
//
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
353
|
+
// No npm package required — uses Node's built-in http module.
|
|
354
|
+
// Works identically on Windows and macOS (the server is pure TypeScript).
|
|
355
|
+
//
|
|
356
|
+
// SmartCrusher preserves statistical distribution:
|
|
357
|
+
// Lossless: CSV format for homogeneous arrays (51–84% savings)
|
|
358
|
+
// Lossy: 30% start + 55% importance-scored + 15% end kept;
|
|
359
|
+
// dropped rows stored in CCR and retrievable on demand.
|
|
361
360
|
let headroomApplied = false;
|
|
362
361
|
let headroomTokensSaved = 0;
|
|
363
362
|
|
|
364
363
|
try {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
364
|
+
const baseUrl = process.env.HEADROOM_PROXY_URL || process.env.ANTHROPIC_BASE_URL;
|
|
365
|
+
if (baseUrl && baseUrl.includes('127.0.0.1')) {
|
|
366
|
+
// POST /headroom/compress with the current messages
|
|
367
|
+
const payload = JSON.stringify({ messages });
|
|
368
|
+
const result: any = await new Promise((resolve, reject) => {
|
|
369
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
370
|
+
const http = require('http');
|
|
371
|
+
const url = new URL('/headroom/compress', baseUrl);
|
|
372
|
+
const req = http.request(
|
|
373
|
+
{
|
|
374
|
+
hostname: url.hostname,
|
|
375
|
+
port: parseInt(url.port || '8787', 10),
|
|
376
|
+
path: '/headroom/compress',
|
|
377
|
+
method: 'POST',
|
|
378
|
+
headers: {
|
|
379
|
+
'Content-Type': 'application/json',
|
|
380
|
+
'Content-Length': Buffer.byteLength(payload),
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
(res: any) => {
|
|
384
|
+
let body = '';
|
|
385
|
+
res.on('data', (c: Buffer) => { body += c; });
|
|
386
|
+
res.on('end', () => {
|
|
387
|
+
try { resolve(JSON.parse(body)); }
|
|
388
|
+
catch { reject(new Error('Invalid JSON from compression server')); }
|
|
389
|
+
});
|
|
390
|
+
res.on('error', reject);
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
req.setTimeout(5000, () => { req.destroy(); reject(new Error('Compression server timeout')); });
|
|
394
|
+
req.on('error', reject);
|
|
395
|
+
req.write(payload);
|
|
396
|
+
req.end();
|
|
377
397
|
});
|
|
378
398
|
|
|
379
399
|
if (result?.messages?.length) {
|
|
@@ -403,8 +423,7 @@ export default function contextCompaction(pi: ExtensionAPI): void {
|
|
|
403
423
|
}
|
|
404
424
|
}
|
|
405
425
|
} catch (hrErr) {
|
|
406
|
-
// Headroom compress failed —
|
|
407
|
-
// Log prominently and fall through to legacy L1 below.
|
|
426
|
+
// Headroom compress failed — log and fall through to legacy L1.
|
|
408
427
|
process.stderr.write(
|
|
409
428
|
`[context-compaction] ⚠️ Headroom compress error: ${String(hrErr)}\n` +
|
|
410
429
|
`[context-compaction] Falling back to legacy L1 tool result clearing.\n`
|
|
@@ -230,6 +230,11 @@ export async function spreadActivation(
|
|
|
230
230
|
initialActivation: EnrichedActivation,
|
|
231
231
|
graphClient?: { safeRead: (q: string, p?: any) => Promise<any[]> } | null,
|
|
232
232
|
): Promise<EnrichedActivation> {
|
|
233
|
+
const { isMemgraphAvailable } = require('../../lib/graph-availability');
|
|
234
|
+
if (!isMemgraphAvailable()) {
|
|
235
|
+
process.stderr.write('[cortex:activation-bridge] Memgraph unavailable — skipping activation spread\n');
|
|
236
|
+
return {};
|
|
237
|
+
}
|
|
233
238
|
if (!initialActivation.concepts.length) return initialActivation;
|
|
234
239
|
|
|
235
240
|
const mg = graphClient !== undefined ? graphClient : getDefaultMg();
|
|
@@ -154,6 +154,32 @@ try {
|
|
|
154
154
|
}
|
|
155
155
|
} catch (err) { /* fail-open: WAL module init */ if (process.env.HELIOS_DEBUG) console.error(`[cortex-learn] WAL init error: ${String(err)}`); }
|
|
156
156
|
|
|
157
|
+
// Register availability listener so cortex WAL replays automatically
|
|
158
|
+
// when Memgraph comes back up after a period of unavailability (P4-2).
|
|
159
|
+
// _walReplayInProgress guard prevents concurrent replays racing on the journal
|
|
160
|
+
// file when Memgraph flaps rapidly (F13).
|
|
161
|
+
let _walReplayInProgress = false;
|
|
162
|
+
try {
|
|
163
|
+
const { onAvailabilityChange } = require('../../lib/graph-availability');
|
|
164
|
+
onAvailabilityChange((available: boolean) => {
|
|
165
|
+
if (!available || _walReplayInProgress) return;
|
|
166
|
+
_walReplayInProgress = true;
|
|
167
|
+
// Fire-and-forget: WAL replay runs in background, never blocks dispatch
|
|
168
|
+
import('./wal-replay').then(({ replayCortexWal }) => {
|
|
169
|
+
replayCortexWal()
|
|
170
|
+
.catch((e: unknown) =>
|
|
171
|
+
process.stderr.write(`[cortex-learn] WAL replay failed: ${String(e)}\n`)
|
|
172
|
+
)
|
|
173
|
+
.finally(() => { _walReplayInProgress = false; });
|
|
174
|
+
}).catch(() => {
|
|
175
|
+
// wal-replay not available (e.g. pre-build) — silently skip
|
|
176
|
+
_walReplayInProgress = false;
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
} catch (_) {
|
|
180
|
+
// graph-availability not available — WAL replay disabled
|
|
181
|
+
}
|
|
182
|
+
|
|
157
183
|
function _persistCoherenceCounts(): void {
|
|
158
184
|
try {
|
|
159
185
|
const obj: Record<string, number> = {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extensions/cortex/wal-replay.ts
|
|
3
|
+
*
|
|
4
|
+
* Auto-replay cortex WAL entries when Memgraph becomes available.
|
|
5
|
+
* Called by learn.ts on the memgraph:available event (P4-2).
|
|
6
|
+
*
|
|
7
|
+
* Reads cortex-write-journal.jsonl, replays each entry via rawWrite,
|
|
8
|
+
* removes successfully replayed entries atomically (temp file + rename).
|
|
9
|
+
*
|
|
10
|
+
* Uses extensions/lib/helios-root (same module as learn.ts) to ensure
|
|
11
|
+
* the journal path resolves identically in both files.
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
|
|
15
|
+
// Re-use the same path derivation as learn.ts.
|
|
16
|
+
// MUST use '../lib/helios-root' (extensions/lib/helios-root), NOT
|
|
17
|
+
// '../../lib/helios-root' (lib/helios-root) — different fallback strategies.
|
|
18
|
+
const { heliosPath } = require('../lib/helios-root');
|
|
19
|
+
const WRITE_JOURNAL_PATH: string = heliosPath('sessions', 'cortex-write-journal.jsonl');
|
|
20
|
+
|
|
21
|
+
interface WalEntry {
|
|
22
|
+
cypher: string;
|
|
23
|
+
params: Record<string, unknown>;
|
|
24
|
+
timestamp?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readJournalEntries(): WalEntry[] {
|
|
28
|
+
if (!fs.existsSync(WRITE_JOURNAL_PATH)) return [];
|
|
29
|
+
try {
|
|
30
|
+
const lines = fs.readFileSync(WRITE_JOURNAL_PATH, 'utf8')
|
|
31
|
+
.split('\n')
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
return lines.map(line => {
|
|
34
|
+
try { return JSON.parse(line) as WalEntry; } catch { return null; }
|
|
35
|
+
}).filter((e): e is WalEntry => e !== null && typeof e.cypher === 'string');
|
|
36
|
+
} catch (e) {
|
|
37
|
+
process.stderr.write(`[cortex-wal-replay] failed to read journal: ${String(e)}\n`);
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function writeJournalEntries(entries: WalEntry[]): void {
|
|
43
|
+
const tmp = WRITE_JOURNAL_PATH + '.tmp';
|
|
44
|
+
try {
|
|
45
|
+
fs.writeFileSync(tmp, entries.map(e => JSON.stringify(e)).join('\n') + (entries.length ? '\n' : ''), 'utf8');
|
|
46
|
+
fs.renameSync(tmp, WRITE_JOURNAL_PATH);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
process.stderr.write(`[cortex-wal-replay] failed to write journal: ${String(e)}\n`);
|
|
49
|
+
try { fs.unlinkSync(tmp); } catch {}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function replayCortexWal(): Promise<void> {
|
|
54
|
+
const entries = readJournalEntries();
|
|
55
|
+
if (entries.length === 0) return;
|
|
56
|
+
|
|
57
|
+
let rawWrite: ((cypher: string, params: Record<string, unknown>) => Promise<unknown>) | null = null;
|
|
58
|
+
try {
|
|
59
|
+
const mg = require('../../lib/safe-memgraph');
|
|
60
|
+
rawWrite = mg.rawWrite ?? mg.safeWrite ?? null;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
process.stderr.write(`[cortex-wal-replay] failed to load safe-memgraph: ${String(e)}\n`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!rawWrite) {
|
|
67
|
+
process.stderr.write('[cortex-wal-replay] rawWrite not available — skipping replay\n');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const remaining: WalEntry[] = [];
|
|
72
|
+
let replayed = 0;
|
|
73
|
+
let failed = 0;
|
|
74
|
+
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
try {
|
|
77
|
+
await rawWrite(entry.cypher, entry.params ?? {});
|
|
78
|
+
replayed++;
|
|
79
|
+
} catch (e) {
|
|
80
|
+
failed++;
|
|
81
|
+
remaining.push(entry);
|
|
82
|
+
process.stderr.write(`[cortex-wal-replay] entry replay failed (kept in journal): ${String(e)}\n`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
writeJournalEntries(remaining);
|
|
87
|
+
|
|
88
|
+
process.stderr.write(
|
|
89
|
+
`[cortex-wal-replay] Replayed ${replayed} / ${entries.length} entries. ${failed} failed (left in journal).\n`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -11,7 +11,7 @@ const HIGH_IMPACT_SHARED_BRANCHES = /\b(main|master|dev|development|staging|stag
|
|
|
11
11
|
const HIGH_IMPACT_GIT_OPS = /\b(cherry.?pick|git\s+push|force.?push|git\s+merge|merge\s+(?:to|into)\s+|push\s+to\s+(?:origin|remote|upstream)|git\s+rebase|git\s+reset\s+--hard)\b/i;
|
|
12
12
|
const HIGH_IMPACT_AUTH_CRYPTO = /\b(?:auth|crypto|session|oauth|jwt|encrypt|decrypt|secret|cipher|password)\.(ts|js|tsx|jsx)\b|(?:session|token|secret|password|credential|encrypt|decrypt|hash|cipher|jwt|oauth)\s+(?:file|module|key|management)/i;
|
|
13
13
|
const HIGH_IMPACT_INFRA = /\b(?:(?:run|apply|execute|deploy|push|revert|rollback|sync)\s+migration|schema\s+change|drop\s+table|alter\s+table|environment\s+variable|aws\s+ssm|amplify\s+deploy|\.env\b)\b/i;
|
|
14
|
-
const HIGH_IMPACT_RUNTIME_UPGRADE = /\b(npm\s+install|npm\s+i|npm\s+update|npm\s+up)\b.*(pi-coding-agent|@mariozechner\/pi|@helios-agent\/pi)/i;
|
|
14
|
+
const HIGH_IMPACT_RUNTIME_UPGRADE = /\b(npm\s+install|npm\s+i|npm\s+update|npm\s+up|pnpm\s+add|pnpm\s+install)\b.*(pi-coding-agent|@mariozechner\/pi|@helios-agent\/pi|@cgh567\/cli|@cgh567\/agent|@cgh567\/pi)/i;
|
|
15
15
|
export const SHARED_INFRA_PATHS = /(?:~\/|\/Users\/\w+\/)?\.\.?pi\/agent\/(extensions|skills|agents)\//i;
|
|
16
16
|
|
|
17
17
|
export function isHighImpactOperation(task: string): boolean {
|
|
@@ -28,15 +28,22 @@ import { homedir } from 'os';
|
|
|
28
28
|
|
|
29
29
|
// Ordered list of jiti lib/jiti.cjs locations (lib/ not dist/ - dist requires module.createRequire which is unavailable in CJS context)
|
|
30
30
|
const JITI_PATHS = [
|
|
31
|
+
// ── npm package layout (production: @cgh567/agent installed in node_modules) ──
|
|
32
|
+
// When helios-agent runs from node_modules/@cgh567/agent, jiti is provided by
|
|
33
|
+
// @cgh567/cli which is in the same scope. Walk up to workspace root node_modules.
|
|
34
|
+
// Resolve relative to __dirname (this file's location in extensions/helios-governance/handlers/)
|
|
35
|
+
// node_modules/@cgh567/agent/extensions/helios-governance/handlers/ -> up 6 levels -> workspace root
|
|
36
|
+
join(__dirname, '..', '..', '..', '..', '..', '..', 'node_modules', '@mariozechner', 'jiti', 'lib', 'jiti.cjs'),
|
|
37
|
+
// @cgh567/cli bundles jiti under its own node_modules
|
|
38
|
+
join(__dirname, '..', '..', '..', '..', '..', '..', 'node_modules', '@cgh567', 'cli', 'node_modules', '@mariozechner', 'jiti', 'lib', 'jiti.cjs'),
|
|
39
|
+
// ── local clone layout (dev: ~/Desktop/Helios/helios-agent-main) ──
|
|
40
|
+
join(homedir(), 'Desktop', 'Helios', 'helios-agent-main', 'node_modules', '@mariozechner', 'jiti', 'lib', 'jiti.cjs'),
|
|
41
|
+
join(homedir(), 'helios-agent-main', 'node_modules', '@mariozechner', 'jiti', 'lib', 'jiti.cjs'),
|
|
31
42
|
join(homedir(), 'helios-agent', 'node_modules', '@mariozechner', 'jiti', 'lib', 'jiti.cjs'),
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
'@helios-agent', 'pi-coding-agent', 'node_modules', 'jiti', 'lib', 'jiti.cjs'),
|
|
37
|
-
join(process.env.NVM_DIR || join(homedir(), '.nvm'),
|
|
38
|
-
'versions', 'node', process.version, 'lib', 'node_modules',
|
|
39
|
-
'@earendil-works', 'pi-coding-agent', 'node_modules', 'jiti', 'lib', 'jiti.cjs'),
|
|
43
|
+
// ── HELIOS_ROOT env var override ──
|
|
44
|
+
...(process.env.HELIOS_ROOT
|
|
45
|
+
? [join(process.env.HELIOS_ROOT, 'node_modules', '@mariozechner', 'jiti', 'lib', 'jiti.cjs')]
|
|
46
|
+
: []),
|
|
40
47
|
];
|
|
41
48
|
|
|
42
49
|
/** Module-level jiti instance cache: callerFile → jiti fn */
|
|
File without changes
|
|
@@ -23,6 +23,11 @@ export async function queryGraphMemories(
|
|
|
23
23
|
taskText: string,
|
|
24
24
|
limit: number = 10
|
|
25
25
|
): Promise<GraphMemoryResult[]> {
|
|
26
|
+
const { isMemgraphAvailable } = require('../../lib/graph-availability');
|
|
27
|
+
if (!isMemgraphAvailable()) {
|
|
28
|
+
process.stderr.write('[hema:graph-memory] Memgraph unavailable — skipping graph memory recall\n');
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
26
31
|
try {
|
|
27
32
|
const mg = require('../../lib/safe-memgraph.js');
|
|
28
33
|
|
|
@@ -102,6 +107,11 @@ export async function queryCausalLessons(
|
|
|
102
107
|
taskText: string,
|
|
103
108
|
limit: number = 5
|
|
104
109
|
): Promise<GraphMemoryResult[]> {
|
|
110
|
+
const { isMemgraphAvailable } = require('../../lib/graph-availability');
|
|
111
|
+
if (!isMemgraphAvailable()) {
|
|
112
|
+
process.stderr.write('[hema:graph-memory] Memgraph unavailable — skipping causal lesson recall\n');
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
105
115
|
try {
|
|
106
116
|
const mg = require('../../lib/safe-memgraph.js');
|
|
107
117
|
|
|
@@ -682,15 +682,20 @@ export default function hemaDispatchV3(pi: any): void {
|
|
|
682
682
|
} catch (_) { process.stderr.write(`[hema:catch] fail-open: graceful degradation: ${(_ as Error)?.message || _}\n`); } // HeliosRuntime may not be initialized — fail-open
|
|
683
683
|
|
|
684
684
|
// ═══ TASK-13: Budget Pre-Admission Gate ═══
|
|
685
|
-
//
|
|
685
|
+
// MT-02: Path resolves from HELIOS_ROOT env var (required). If unset, daemon logs a startup error.
|
|
686
|
+
// budget-status.json is written by GraphSyncService at $HELIOS_ROOT/brainv2/budget-status.json.
|
|
686
687
|
// Fail-open: if file missing or unreadable, proceed normally.
|
|
687
688
|
// blocked=true → hard block, return early with ⛔ message
|
|
688
689
|
// warningActive → inject budget warning into agent context (soft signal)
|
|
689
690
|
let _budgetStatus: { blocked?: boolean; warningActive?: boolean; policies?: any[] } = {};
|
|
690
691
|
let _budgetWarning: string | null = null;
|
|
691
692
|
try {
|
|
692
|
-
const
|
|
693
|
-
if (
|
|
693
|
+
const _heliosRoot = process.env['HELIOS_ROOT'];
|
|
694
|
+
if (!_heliosRoot) {
|
|
695
|
+
process.stderr.write('[hema] HELIOS_ROOT not set — budget-status.json cannot be read. Set HELIOS_ROOT to the helios-agent repo root.\n');
|
|
696
|
+
}
|
|
697
|
+
const _budgetStatusPath = _heliosRoot ? join(_heliosRoot, 'brainv2/budget-status.json') : null;
|
|
698
|
+
if (_budgetStatusPath && fs.existsSync(_budgetStatusPath)) {
|
|
694
699
|
_budgetStatus = JSON.parse(fs.readFileSync(_budgetStatusPath, 'utf8'));
|
|
695
700
|
}
|
|
696
701
|
} catch (_budgetErr) {
|
|
@@ -1507,48 +1512,67 @@ export default function hemaDispatchV3(pi: any): void {
|
|
|
1507
1512
|
logHemaEvent('hema_no_context', { nativePacksUsed, legacyUsed: admitted.admitted?.length > 0 });
|
|
1508
1513
|
}
|
|
1509
1514
|
|
|
1510
|
-
// ──
|
|
1511
|
-
// The recall context
|
|
1512
|
-
//
|
|
1513
|
-
//
|
|
1514
|
-
//
|
|
1515
|
-
//
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1515
|
+
// ── Helios Compression: compress HEMA recall payload before injection ──
|
|
1516
|
+
// The recall context contains JSON graph payloads (leads, signals, tasks,
|
|
1517
|
+
// goals, code nodes). Send the assembled text as a tool_result block to
|
|
1518
|
+
// the compression server — it will find and compress embedded JSON arrays.
|
|
1519
|
+
//
|
|
1520
|
+
// Uses direct HTTP to HEADROOM_PROXY_URL (same pattern as context-compaction.ts)
|
|
1521
|
+
// rather than the headroom-ai npm package so this works in Pi subprocess context.
|
|
1522
|
+
// Applies to all companies: the role injection budgets enforce per-agent limits.
|
|
1523
|
+
if (enrichedTask.length > 2000) {
|
|
1524
|
+
const _hrUrl = process.env.HEADROOM_PROXY_URL;
|
|
1525
|
+
if (_hrUrl) {
|
|
1526
|
+
try {
|
|
1527
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
1528
|
+
const http = require('http');
|
|
1529
|
+
const _payload = JSON.stringify({
|
|
1530
|
+
messages: [{
|
|
1531
|
+
role: 'user',
|
|
1532
|
+
content: [{
|
|
1533
|
+
type: 'tool_result',
|
|
1534
|
+
tool_use_id: 'hema_recall',
|
|
1535
|
+
content: enrichedTask,
|
|
1536
|
+
}],
|
|
1537
|
+
}],
|
|
1538
|
+
});
|
|
1539
|
+
const _result: any = await new Promise((resolve, reject) => {
|
|
1540
|
+
const _url = new URL('/headroom/compress', _hrUrl);
|
|
1541
|
+
const _req = http.request(
|
|
1542
|
+
{
|
|
1543
|
+
hostname: _url.hostname,
|
|
1544
|
+
port: parseInt(_url.port || '8787', 10),
|
|
1545
|
+
path: '/headroom/compress',
|
|
1546
|
+
method: 'POST',
|
|
1547
|
+
headers: {
|
|
1548
|
+
'Content-Type': 'application/json',
|
|
1549
|
+
'Content-Length': Buffer.byteLength(_payload),
|
|
1550
|
+
},
|
|
1551
|
+
},
|
|
1552
|
+
(res: any) => {
|
|
1553
|
+
let body = '';
|
|
1554
|
+
res.on('data', (c: Buffer) => { body += c; });
|
|
1555
|
+
res.on('end', () => { try { resolve(JSON.parse(body)); } catch { reject(new Error('bad json')); } });
|
|
1556
|
+
res.on('error', reject);
|
|
1557
|
+
}
|
|
1558
|
+
);
|
|
1559
|
+
_req.setTimeout(3000, () => { _req.destroy(); reject(new Error('timeout')); });
|
|
1560
|
+
_req.on('error', reject);
|
|
1561
|
+
_req.write(_payload);
|
|
1562
|
+
_req.end();
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
const _compressed = _result?.messages?.[0]?.content?.[0]?.content ?? enrichedTask;
|
|
1566
|
+
if (typeof _compressed === 'string' && _compressed.length < enrichedTask.length) {
|
|
1567
|
+
const _saved = enrichedTask.length - _compressed.length;
|
|
1568
|
+
process.stderr.write(`[hema-dispatch-v3] Headroom compressed recall context: -${_saved} chars (${agentType})\n`);
|
|
1569
|
+
enrichedTask = _compressed;
|
|
1570
|
+
logHemaEvent('hema_headroom_compressed', { saved: _saved, agentType });
|
|
1547
1571
|
}
|
|
1572
|
+
} catch (_hrErr: any) {
|
|
1573
|
+
// Non-fatal: log and continue with uncompressed enrichedTask
|
|
1574
|
+
process.stderr.write(`[hema-dispatch-v3] Headroom recall compress skipped: ${_hrErr?.message}\n`);
|
|
1548
1575
|
}
|
|
1549
|
-
} catch (_hrErr: any) {
|
|
1550
|
-
// Non-fatal: log and continue with uncompressed enrichedTask
|
|
1551
|
-
process.stderr.write(`[hema-dispatch-v3] Headroom recall compress failed (non-fatal): ${_hrErr?.message}\n`);
|
|
1552
1576
|
}
|
|
1553
1577
|
}
|
|
1554
1578
|
|
|
@@ -2657,9 +2681,10 @@ export default function hemaDispatchV3(pi: any): void {
|
|
|
2657
2681
|
} catch (_) { process.stderr.write(`[hema:catch] fail-open: ${(_ as Error)?.message || _}\n`); }
|
|
2658
2682
|
|
|
2659
2683
|
// Load hot memory — ensure file exists
|
|
2660
|
-
const
|
|
2684
|
+
const _heliosRootForMem = process.env['HELIOS_ROOT'] ?? join(homedir(), 'helios-agent');
|
|
2685
|
+
const hotMemoryPath = join(_heliosRootForMem, 'sessions', 'hot-memory.json');
|
|
2661
2686
|
if (!fs.existsSync(hotMemoryPath)) {
|
|
2662
|
-
const sessDir = join(
|
|
2687
|
+
const sessDir = join(_heliosRootForMem, 'sessions');
|
|
2663
2688
|
if (!fs.existsSync(sessDir)) fs.mkdirSync(sessDir, { recursive: true });
|
|
2664
2689
|
fs.writeFileSync(hotMemoryPath, JSON.stringify({ sessions: [] }, null, 2), 'utf8');
|
|
2665
2690
|
}
|
|
@@ -2687,7 +2712,7 @@ export default function hemaDispatchV3(pi: any): void {
|
|
|
2687
2712
|
const pendingIds = [..._pendingDispatchIds.keys()];
|
|
2688
2713
|
try {
|
|
2689
2714
|
const _walSessionId = di('sessionId') || process.pid;
|
|
2690
|
-
const walPath = join(homedir(),
|
|
2715
|
+
const walPath = join(process.env['HELIOS_ROOT'] ?? join(homedir(), 'helios-agent'), `sessions/.pending-dispatches-${_walSessionId}.json`);
|
|
2691
2716
|
fs.writeFileSync(walPath, JSON.stringify({ ids: pendingIds, timestamp: Date.now(), sessionId: di('sessionId') || 'unknown' }));
|
|
2692
2717
|
process.stderr.write(`[hema] session_shutdown: wrote ${pendingIds.length} pending dispatch ID(s) to WAL\n`);
|
|
2693
2718
|
} catch (e: any) {
|
|
@@ -3125,7 +3150,7 @@ export default function hemaDispatchV3(pi: any): void {
|
|
|
3125
3150
|
return { systemPrompt: appendDynamic(event.systemPrompt, '\n' + evalContext) };
|
|
3126
3151
|
}
|
|
3127
3152
|
|
|
3128
|
-
const hotMemoryPath = join(homedir(), 'helios-agent', 'sessions', 'hot-memory.json');
|
|
3153
|
+
const hotMemoryPath = join(process.env['HELIOS_ROOT'] ?? join(homedir(), 'helios-agent'), 'sessions', 'hot-memory.json');
|
|
3129
3154
|
|
|
3130
3155
|
let hotMemory: any = null;
|
|
3131
3156
|
if (fs.existsSync(hotMemoryPath)) {
|
|
File without changes
|
|
File without changes
|
|
@@ -23,6 +23,17 @@ import { createRequire } from 'module';
|
|
|
23
23
|
const require = createRequire(import.meta.url);
|
|
24
24
|
const QUIET = process.env.PI_QUIET === '1' || process.env.PI_LOG_LEVEL === 'error';
|
|
25
25
|
|
|
26
|
+
// Graph availability singleton — updated whenever Memgraph comes up or goes down
|
|
27
|
+
let _graphAvailability: { setMemgraphAvailable: (v: boolean) => void } | null = null;
|
|
28
|
+
function getGraphAvailability() {
|
|
29
|
+
if (!_graphAvailability) {
|
|
30
|
+
try {
|
|
31
|
+
_graphAvailability = require('../lib/graph-availability');
|
|
32
|
+
} catch (_) {}
|
|
33
|
+
}
|
|
34
|
+
return _graphAvailability;
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
// ── Event emission helpers ───────────────────────────────────────────────────
|
|
27
38
|
|
|
28
39
|
/** Load MAGE query modules after Bolt becomes reachable.
|
|
@@ -109,6 +120,7 @@ function emitMemgraphReady(log: (msg: string) => void): void {
|
|
|
109
120
|
bus.emit('memgraph_ready', payload);
|
|
110
121
|
} catch (e) { process.stderr.write(`[extensions] non-fatal if bus unavailable: ${String(e)}\n`); }
|
|
111
122
|
log(`[memgraph-autostart] Memgraph ready — bolt reachable at ${BOLT_HOST}:${BOLT_PORT}`);
|
|
123
|
+
getGraphAvailability()?.setMemgraphAvailable(true);
|
|
112
124
|
}
|
|
113
125
|
|
|
114
126
|
/**
|
|
@@ -185,6 +197,7 @@ function emitMemgraphDegraded(log: (msg: string) => void, reason: string): void
|
|
|
185
197
|
try {
|
|
186
198
|
bus.emit('memgraph_degraded', payload);
|
|
187
199
|
} catch (e) { process.stderr.write(`[extensions] non-fatal: ${String(e)}\n`); }
|
|
200
|
+
getGraphAvailability()?.setMemgraphAvailable(false);
|
|
188
201
|
}
|
|
189
202
|
|
|
190
203
|
/** Returns true if Memgraph bolt was confirmed reachable during this session. */
|
|
File without changes
|
|
File without changes
|
|
@@ -713,6 +713,14 @@ export async function runScheduledMaintenance(): Promise<void> {
|
|
|
713
713
|
}
|
|
714
714
|
}
|
|
715
715
|
|
|
716
|
+
// SEC-5: Daily cleanup of expired DraftAction PII nodes (30-day TTL)
|
|
717
|
+
try {
|
|
718
|
+
const { rawWrite: _rawWrite } = require('../../lib/safe-memgraph.js');
|
|
719
|
+
await _rawWrite('MATCH (da:DraftAction) WHERE da.expiresAt < datetime() DETACH DELETE da', {});
|
|
720
|
+
} catch (err: any) {
|
|
721
|
+
console.warn('[warm-tick] DraftAction TTL cleanup failed:', err?.message || String(err));
|
|
722
|
+
}
|
|
723
|
+
|
|
716
724
|
// Daily: incremental label backfill (ensures critical graph labels are never empty)
|
|
717
725
|
try {
|
|
718
726
|
const { runIncrementalBackfill } = await import('./warm-tick-backfill.js');
|