@cgh567/agent 2.4.0 → 2.4.2
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/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/helios-api.js +149 -37
- package/daemon/helios-company-daemon.js +516 -124
- 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 +31 -12
- 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/routes/channels.js +10 -5
- package/daemon/routes/harada-map.js +11 -48
- package/daemon/routes/hbo.js +89 -28
- package/daemon/routes/hitl.js +0 -0
- package/daemon/routes/project.js +4 -3
- package/daemon/routes/wizard.js +11 -4
- package/daemon/schema-migrations-hitl.js +0 -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/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 +59 -40
- 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/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/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/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/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 +0 -0
- package/lib/triage-core/mental-model/model-assembler.ts +0 -0
- package/lib/triage-core/orchestrator.ts +0 -0
- package/lib/triage-core/orchestrator.ts.bak-r005-r006-r008 +0 -0
- package/package.json +10 -4
- 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/hed-engine.js +0 -307
- 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
package/daemon/lib/hed-engine.js
DELETED
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { randomUUID } = require('crypto');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* HEDEngine — Helios Execution Document orchestration.
|
|
7
|
-
* A HED is a PlanChangeProposal {scope:'execution'} with wave-based CRUD operations.
|
|
8
|
-
* Agents execute against HEDOperations; Murray audits each completion.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
class HEDEngine {
|
|
12
|
-
constructor(mg) {
|
|
13
|
-
this._mg = mg;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// ─── Create ────────────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
async createHED({ companyId, title, intent, worldStateSnapshot, operations, goalId }) {
|
|
19
|
-
const hedId = `hed_${Date.now()}_${randomUUID().slice(0, 8)}`;
|
|
20
|
-
const now = new Date().toISOString();
|
|
21
|
-
|
|
22
|
-
// Create PlanChangeProposal with scope='execution'
|
|
23
|
-
await this._mg(
|
|
24
|
-
`CREATE (pcp:PlanChangeProposal {
|
|
25
|
-
id: $id, companyId: $companyId, scope: 'execution',
|
|
26
|
-
title: $title, intent: $intent,
|
|
27
|
-
worldStateSnapshot: $worldStateSnapshot,
|
|
28
|
-
status: 'draft', requiresApproval: true,
|
|
29
|
-
waveCount: $waveCount, currentWave: 1,
|
|
30
|
-
createdAt: $now, resolvedAt: null, resolvedBy: null
|
|
31
|
-
})`,
|
|
32
|
-
{
|
|
33
|
-
id: hedId, companyId, title, intent,
|
|
34
|
-
worldStateSnapshot: JSON.stringify(worldStateSnapshot || {}),
|
|
35
|
-
waveCount: Math.max(...operations.map(o => o.wave || 1), 1),
|
|
36
|
-
now
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
if (goalId) {
|
|
41
|
-
await this._mg(
|
|
42
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId}), (g:BusinessGoal {id: $goalId})
|
|
43
|
-
MERGE (pcp)-[:IMPLEMENTS_GOAL]->(g)`,
|
|
44
|
-
{ hedId, goalId }
|
|
45
|
-
).catch(() => {});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Create HEDOperation nodes
|
|
49
|
-
for (const op of operations) {
|
|
50
|
-
await this.createOperation(hedId, op, now);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return { hedId };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async createOperation(hedId, op, now = new Date().toISOString()) {
|
|
57
|
-
const opId = op.opId || `op_${Date.now()}_${randomUUID().slice(0, 6)}`;
|
|
58
|
-
await this._mg(
|
|
59
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId})
|
|
60
|
-
CREATE (o:HEDOperation {
|
|
61
|
-
id: $opId, hedId: $hedId,
|
|
62
|
-
type: $type, target: $target, targetScope: $targetScope,
|
|
63
|
-
description: $description,
|
|
64
|
-
acceptanceCriteria: $acceptanceCriteria,
|
|
65
|
-
dependsOn: $dependsOn, wave: $wave,
|
|
66
|
-
assignedAgentRole: $assignedAgentRole,
|
|
67
|
-
deviationPolicy: $deviationPolicy,
|
|
68
|
-
status: 'pending', createdAt: $now
|
|
69
|
-
})
|
|
70
|
-
MERGE (pcp)-[:HAS_OPERATION]->(o)`,
|
|
71
|
-
{
|
|
72
|
-
hedId, opId,
|
|
73
|
-
type: op.type || 'UPDATE',
|
|
74
|
-
target: op.target || '',
|
|
75
|
-
targetScope: op.targetScope || '',
|
|
76
|
-
description: op.description || '',
|
|
77
|
-
acceptanceCriteria: JSON.stringify(op.acceptanceCriteria || []),
|
|
78
|
-
dependsOn: JSON.stringify(op.dependsOn || []),
|
|
79
|
-
wave: op.wave || 1,
|
|
80
|
-
assignedAgentRole: op.assignedAgentRole || 'worker',
|
|
81
|
-
deviationPolicy: op.deviationPolicy || 'smart',
|
|
82
|
-
now
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
return opId;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// ─── Read ──────────────────────────────────────────────────────────────────
|
|
89
|
-
|
|
90
|
-
async getHED(hedId) {
|
|
91
|
-
const rows = await this._mg(
|
|
92
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId, scope: 'execution'})
|
|
93
|
-
RETURN pcp`,
|
|
94
|
-
{ hedId }
|
|
95
|
-
);
|
|
96
|
-
if (!rows?.length) return null;
|
|
97
|
-
const pcp = rows[0].pcp;
|
|
98
|
-
try { pcp.worldStateSnapshot = JSON.parse(pcp.worldStateSnapshot); } catch {}
|
|
99
|
-
return pcp;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async getOperations(hedId) {
|
|
103
|
-
const rows = await this._mg(
|
|
104
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId})-[:HAS_OPERATION]->(o:HEDOperation)
|
|
105
|
-
RETURN o ORDER BY o.wave ASC, o.id ASC`,
|
|
106
|
-
{ hedId }
|
|
107
|
-
);
|
|
108
|
-
return (rows || []).map(r => {
|
|
109
|
-
const o = r.o;
|
|
110
|
-
try { o.acceptanceCriteria = JSON.parse(o.acceptanceCriteria); } catch { o.acceptanceCriteria = []; }
|
|
111
|
-
try { o.dependsOn = JSON.parse(o.dependsOn); } catch { o.dependsOn = []; }
|
|
112
|
-
return o;
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async getOperation(opId) {
|
|
117
|
-
const rows = await this._mg(
|
|
118
|
-
`MATCH (o:HEDOperation {id: $opId}) RETURN o`, { opId }
|
|
119
|
-
);
|
|
120
|
-
if (!rows?.length) return null;
|
|
121
|
-
const o = rows[0].o;
|
|
122
|
-
try { o.acceptanceCriteria = JSON.parse(o.acceptanceCriteria); } catch { o.acceptanceCriteria = []; }
|
|
123
|
-
try { o.dependsOn = JSON.parse(o.dependsOn); } catch { o.dependsOn = []; }
|
|
124
|
-
return o;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ─── State transitions ─────────────────────────────────────────────────────
|
|
128
|
-
|
|
129
|
-
async approveHED(hedId, approvedBy) {
|
|
130
|
-
const now = new Date().toISOString();
|
|
131
|
-
await this._mg(
|
|
132
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId, scope: 'execution', status: 'draft'})
|
|
133
|
-
SET pcp.status = 'approved', pcp.approvedAt = $now, pcp.approvedBy = $approvedBy`,
|
|
134
|
-
{ hedId, now, approvedBy }
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async claimOperation(opId, agentId) {
|
|
139
|
-
const now = new Date().toISOString();
|
|
140
|
-
const rows = await this._mg(
|
|
141
|
-
`MATCH (o:HEDOperation {id: $opId, status: 'pending'})
|
|
142
|
-
SET o.status = 'in_progress', o.executionLockedAt = $now, o.executionAgentId = $agentId
|
|
143
|
-
RETURN o.id AS claimed`,
|
|
144
|
-
{ opId, now, agentId }
|
|
145
|
-
);
|
|
146
|
-
return rows?.[0]?.claimed === opId;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async completeOperation(opId, { summary, sessionKey, verdict = 'pending_review' }) {
|
|
150
|
-
const now = new Date().toISOString();
|
|
151
|
-
await this._mg(
|
|
152
|
-
`MATCH (o:HEDOperation {id: $opId})
|
|
153
|
-
SET o.status = $status, o.completedAt = $now,
|
|
154
|
-
o.executionSummary = $summary, o.sessionKey = $sessionKey`,
|
|
155
|
-
{ opId, status: verdict === 'pending_review' ? 'done' : verdict, now, summary, sessionKey }
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async postReviewFinding(opId, finding) {
|
|
160
|
-
const findingId = `hrf_${Date.now()}_${randomUUID().slice(0, 6)}`;
|
|
161
|
-
const now = new Date().toISOString();
|
|
162
|
-
await this._mg(
|
|
163
|
-
`MATCH (o:HEDOperation {id: $opId})
|
|
164
|
-
CREATE (f:HEDReviewFinding {
|
|
165
|
-
id: $findingId, opId: $opId, hedId: o.hedId,
|
|
166
|
-
verdict: $verdict, deviationClass: $deviationClass,
|
|
167
|
-
criteriaResults: $criteriaResults,
|
|
168
|
-
deviationNarrative: $deviationNarrative,
|
|
169
|
-
blockingBehavior: $blockingBehavior,
|
|
170
|
-
createdAt: $now
|
|
171
|
-
})
|
|
172
|
-
MERGE (o)-[:HAS_REVIEW]->(f)
|
|
173
|
-
SET o.reviewVerdict = $verdict`,
|
|
174
|
-
{
|
|
175
|
-
findingId, opId,
|
|
176
|
-
verdict: finding.verdict || 'ALIGNED',
|
|
177
|
-
deviationClass: finding.deviationClass || null,
|
|
178
|
-
criteriaResults: JSON.stringify(finding.criteriaResults || []),
|
|
179
|
-
deviationNarrative: finding.deviationNarrative || '',
|
|
180
|
-
blockingBehavior: finding.blockingBehavior || 'continue',
|
|
181
|
-
now
|
|
182
|
-
}
|
|
183
|
-
);
|
|
184
|
-
// If hard block — pause HED
|
|
185
|
-
if (finding.blockingBehavior === 'hard-pause') {
|
|
186
|
-
await this._mg(
|
|
187
|
-
`MATCH (pcp:PlanChangeProposal {id: o.hedId})
|
|
188
|
-
MATCH (o:HEDOperation {id: $opId})
|
|
189
|
-
SET pcp.status = 'review'`,
|
|
190
|
-
{ opId }
|
|
191
|
-
).catch(() => {});
|
|
192
|
-
}
|
|
193
|
-
if (finding.blastRadius) {
|
|
194
|
-
await this._writeBlastRadius(opId, finding.blastRadius, now);
|
|
195
|
-
}
|
|
196
|
-
return findingId;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async _writeBlastRadius(opId, br, now) {
|
|
200
|
-
const brId = `bre_${Date.now()}_${randomUUID().slice(0, 6)}`;
|
|
201
|
-
await this._mg(
|
|
202
|
-
`MATCH (o:HEDOperation {id: $opId})
|
|
203
|
-
CREATE (b:BlastRadiusEvent {
|
|
204
|
-
id: $brId, opId: $opId,
|
|
205
|
-
filesChanged: $filesChanged,
|
|
206
|
-
nodesAffected: $nodesAffected,
|
|
207
|
-
severity: $severity,
|
|
208
|
-
createdAt: $now
|
|
209
|
-
})
|
|
210
|
-
MERGE (o)-[:HAS_BLAST_RADIUS]->(b)`,
|
|
211
|
-
{
|
|
212
|
-
brId, opId,
|
|
213
|
-
filesChanged: JSON.stringify(br.filesChanged || []),
|
|
214
|
-
nodesAffected: JSON.stringify(br.nodesAffected || []),
|
|
215
|
-
severity: br.severity || 'none',
|
|
216
|
-
now
|
|
217
|
-
}
|
|
218
|
-
).catch(err => console.error('[hed-engine] blast radius write failed:', err.message));
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// ─── Wave advancement ──────────────────────────────────────────────────────
|
|
222
|
-
|
|
223
|
-
async checkWaveAdvancement(companyId) {
|
|
224
|
-
// Find approved HEDs for this company that are executing
|
|
225
|
-
const heds = await this._mg(
|
|
226
|
-
`MATCH (pcp:PlanChangeProposal {companyId: $companyId, scope: 'execution', status: 'approved'})
|
|
227
|
-
RETURN pcp.id AS hedId, pcp.currentWave AS currentWave, pcp.waveCount AS waveCount`,
|
|
228
|
-
{ companyId }
|
|
229
|
-
);
|
|
230
|
-
for (const { hedId, currentWave, waveCount } of (heds || [])) {
|
|
231
|
-
await this._advanceWaveIfReady(hedId, currentWave, waveCount);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
async _advanceWaveIfReady(hedId, currentWave, waveCount) {
|
|
236
|
-
// Check if all ops in currentWave are done or deviated (not blocked/failed)
|
|
237
|
-
const pending = await this._mg(
|
|
238
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId})-[:HAS_OPERATION]->(o:HEDOperation)
|
|
239
|
-
WHERE o.wave = $wave AND o.status IN ['pending', 'in_progress']
|
|
240
|
-
RETURN count(o) AS pendingCount`,
|
|
241
|
-
{ hedId, wave: currentWave }
|
|
242
|
-
);
|
|
243
|
-
const hardBlocked = await this._mg(
|
|
244
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId})-[:HAS_OPERATION]->(o:HEDOperation)
|
|
245
|
-
WHERE o.wave = $wave AND o.reviewVerdict = 'FAILED'
|
|
246
|
-
RETURN count(o) AS blockedCount`,
|
|
247
|
-
{ hedId, wave: currentWave }
|
|
248
|
-
);
|
|
249
|
-
if ((pending?.[0]?.pendingCount || 0) > 0) return; // wave still running
|
|
250
|
-
if ((hardBlocked?.[0]?.blockedCount || 0) > 0) {
|
|
251
|
-
// Hard block — pause entire HED
|
|
252
|
-
await this._mg(
|
|
253
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId}) SET pcp.status = 'review'`,
|
|
254
|
-
{ hedId }
|
|
255
|
-
);
|
|
256
|
-
// Publish PLAN_STALLED to mesh bus — fires the already-wired reflexion loop subscriber
|
|
257
|
-
try {
|
|
258
|
-
const mesh = (global).__helios_session_mesh;
|
|
259
|
-
if (mesh?.bus?.publish) {
|
|
260
|
-
mesh.bus.publish('PLAN_STALLED', {
|
|
261
|
-
hedId,
|
|
262
|
-
wave: currentWave,
|
|
263
|
-
reason: 'HEDOperation hard-blocked by reviewer verdict',
|
|
264
|
-
timestamp: new Date().toISOString(),
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
} catch (_meshErr) { /* mesh not available in daemon context — non-fatal */ }
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (currentWave >= waveCount) {
|
|
271
|
-
// All waves complete
|
|
272
|
-
await this._mg(
|
|
273
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId}) SET pcp.status = 'closed', pcp.closedAt = $now`,
|
|
274
|
-
{ hedId, now: new Date().toISOString() }
|
|
275
|
-
);
|
|
276
|
-
} else {
|
|
277
|
-
// Advance to next wave
|
|
278
|
-
await this._mg(
|
|
279
|
-
`MATCH (pcp:PlanChangeProposal {id: $hedId}) SET pcp.currentWave = $nextWave`,
|
|
280
|
-
{ hedId, nextWave: currentWave + 1 }
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// ─── Context brief helper ──────────────────────────────────────────────────
|
|
286
|
-
|
|
287
|
-
async buildOperationContext(opId) {
|
|
288
|
-
const op = await this.getOperation(opId);
|
|
289
|
-
if (!op) return null;
|
|
290
|
-
const hed = await this.getHED(op.hedId);
|
|
291
|
-
if (!hed) return null;
|
|
292
|
-
return {
|
|
293
|
-
hedIntent: hed.intent,
|
|
294
|
-
worldStateSnapshot: hed.worldStateSnapshot,
|
|
295
|
-
operation: {
|
|
296
|
-
type: op.type,
|
|
297
|
-
target: op.target,
|
|
298
|
-
targetScope: op.targetScope,
|
|
299
|
-
description: op.description,
|
|
300
|
-
acceptanceCriteria: op.acceptanceCriteria,
|
|
301
|
-
deviationPolicy: op.deviationPolicy
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
module.exports = { HEDEngine };
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
/**
|
|
3
|
-
* mental-model-cache.js — CachedPersonModel node CRUD
|
|
4
|
-
* Pre-assembled mental models for fast agent brief injection.
|
|
5
|
-
* Cache is invalidated by enrichmentNeeded flag on Person node.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const SCHEMA_VERSION = 1;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* writeCachedModel — upsert a CachedPersonModel node for a person in a company.
|
|
12
|
-
*
|
|
13
|
-
* @param {Function} mgQuery — Memgraph query function (async)
|
|
14
|
-
* @param {string} personId — Person node id
|
|
15
|
-
* @param {string} companyId — Company node id
|
|
16
|
-
* @param {object} assembledModel — Output from assembleMentalModel()
|
|
17
|
-
*/
|
|
18
|
-
async function writeCachedModel(mgQuery, personId, companyId, assembledModel) {
|
|
19
|
-
const modelId = `model:${companyId}:${personId}`;
|
|
20
|
-
const contextBrief = assembledModel.contextBrief || '';
|
|
21
|
-
const faveeJson = JSON.stringify(assembledModel.favee || {});
|
|
22
|
-
const topicsJson = JSON.stringify((assembledModel.activeTopics || []).slice(0, 10));
|
|
23
|
-
const questionsJson = JSON.stringify((assembledModel.openQuestions || []).slice(0, 5));
|
|
24
|
-
const completeness = contextBrief ? 'full' : (faveeJson !== '{}' ? 'partial' : 'none');
|
|
25
|
-
|
|
26
|
-
await mgQuery(
|
|
27
|
-
`MERGE (m:CachedPersonModel {id: $id})
|
|
28
|
-
ON CREATE SET
|
|
29
|
-
m.personId = $personId, m.companyId = $companyId,
|
|
30
|
-
m.contextBrief = $brief, m.faveeJson = $favee,
|
|
31
|
-
m.topicsJson = $topics, m.questionsJson = $questions,
|
|
32
|
-
m.assembledAt = localdatetime(), m.completeness = $completeness,
|
|
33
|
-
m.schemaVersion = $sv
|
|
34
|
-
ON MATCH SET
|
|
35
|
-
m.contextBrief = $brief, m.faveeJson = $favee,
|
|
36
|
-
m.topicsJson = $topics, m.questionsJson = $questions,
|
|
37
|
-
m.assembledAt = localdatetime(), m.completeness = $completeness,
|
|
38
|
-
m.dirtyAt = null
|
|
39
|
-
WITH m
|
|
40
|
-
MATCH (p:Person {id: $personId})
|
|
41
|
-
MERGE (p)-[:HAS_CACHED_MODEL]->(m)`,
|
|
42
|
-
{ id: modelId, personId, companyId, brief: contextBrief,
|
|
43
|
-
favee: faveeJson, topics: topicsJson, questions: questionsJson,
|
|
44
|
-
completeness, sv: SCHEMA_VERSION }
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* invalidateCache — mark a CachedPersonModel dirty so next read triggers a refresh.
|
|
50
|
-
* Non-fatal: silently ignores errors if the model node doesn't exist yet.
|
|
51
|
-
*
|
|
52
|
-
* @param {Function} mgQuery
|
|
53
|
-
* @param {string} personId
|
|
54
|
-
* @param {string} companyId
|
|
55
|
-
*/
|
|
56
|
-
async function invalidateCache(mgQuery, personId, companyId) {
|
|
57
|
-
const modelId = `model:${companyId}:${personId}`;
|
|
58
|
-
await mgQuery(
|
|
59
|
-
`MATCH (m:CachedPersonModel {id: $id}) SET m.dirtyAt = localdatetime()`,
|
|
60
|
-
{ id: modelId }
|
|
61
|
-
).catch(() => {});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* getCachedModel — return a cached model if it exists, is not dirty, and is within maxAge.
|
|
66
|
-
* Returns null if the cache is cold, dirty, or expired.
|
|
67
|
-
*
|
|
68
|
-
* @param {Function} mgQuery
|
|
69
|
-
* @param {string} personId
|
|
70
|
-
* @param {string} companyId
|
|
71
|
-
* @param {number} maxAgeMinutes — default 60 minutes
|
|
72
|
-
* @returns {object|null}
|
|
73
|
-
*/
|
|
74
|
-
async function getCachedModel(mgQuery, personId, companyId, maxAgeMinutes = 60) {
|
|
75
|
-
const modelId = `model:${companyId}:${personId}`;
|
|
76
|
-
const rows = await mgQuery(
|
|
77
|
-
`MATCH (m:CachedPersonModel {id: $id})
|
|
78
|
-
WHERE m.dirtyAt IS NULL
|
|
79
|
-
AND m.assembledAt > localdatetime() - duration({minutes: $maxAge})
|
|
80
|
-
RETURN m.contextBrief, m.faveeJson, m.topicsJson, m.questionsJson,
|
|
81
|
-
m.assembledAt, m.completeness`,
|
|
82
|
-
{ id: modelId, maxAge: maxAgeMinutes }
|
|
83
|
-
);
|
|
84
|
-
if (!rows?.rows?.length) return null;
|
|
85
|
-
const r = rows.rows[0];
|
|
86
|
-
return {
|
|
87
|
-
contextBrief: r[0],
|
|
88
|
-
faveeJson: r[1],
|
|
89
|
-
topicsJson: r[2],
|
|
90
|
-
questionsJson: r[3],
|
|
91
|
-
assembledAt: r[4],
|
|
92
|
-
completeness: r[5],
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
module.exports = { writeCachedModel, invalidateCache, getCachedModel, SCHEMA_VERSION };
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
/**
|
|
3
|
-
* project-factory.js — Creates HeliosProject + ProjectDocument nodes when
|
|
4
|
-
* a GoalPillar is initialized via tickGoalDecompose().
|
|
5
|
-
*
|
|
6
|
-
* Called from daemon/lib/hbo-bridge.js tickGoalDecompose() after
|
|
7
|
-
* mandala.initializeMandala() succeeds for each GoalPillar.
|
|
8
|
-
*
|
|
9
|
-
* ID conventions:
|
|
10
|
-
* HeliosProject: proj:<companyId>:<pillarSlug>
|
|
11
|
-
* ProjectDocument: pdoc:<projectId>:main
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
async function ensureProject(mgQuery, companyId, goalId, pillarId, pillarTitle) {
|
|
15
|
-
const slug = pillarId.replace(/[^a-z0-9]/gi, '-').toLowerCase().slice(0, 40);
|
|
16
|
-
const projId = `proj:${companyId}:${slug}`;
|
|
17
|
-
const docId = `pdoc:${projId}:main`;
|
|
18
|
-
|
|
19
|
-
await mgQuery(
|
|
20
|
-
`MERGE (p:HeliosProject {id: $projId})
|
|
21
|
-
ON CREATE SET
|
|
22
|
-
p.companyId = $cid,
|
|
23
|
-
p.goalId = $goalId,
|
|
24
|
-
p.pillarId = $pillarId,
|
|
25
|
-
p.name = $name,
|
|
26
|
-
p.status = 'planning',
|
|
27
|
-
p.phase = 'planning',
|
|
28
|
-
p.createdAt = datetime()`,
|
|
29
|
-
{ projId, cid: companyId, goalId, pillarId, name: pillarTitle }
|
|
30
|
-
).catch(() => {});
|
|
31
|
-
|
|
32
|
-
await mgQuery(
|
|
33
|
-
`MERGE (d:ProjectDocument {id: $docId})
|
|
34
|
-
ON CREATE SET
|
|
35
|
-
d.projectId = $projId,
|
|
36
|
-
d.purpose = '',
|
|
37
|
-
d.approach = '',
|
|
38
|
-
d.successCriteria = '[]',
|
|
39
|
-
d.intentAnchor = '',
|
|
40
|
-
d.exclusions = '[]',
|
|
41
|
-
d.version = toInteger(1),
|
|
42
|
-
d.updatedAt = datetime()`,
|
|
43
|
-
{ docId, projId }
|
|
44
|
-
).catch(() => {});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
module.exports = { ensureProject };
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const os = require('os');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* SessionLogReader — reads OpenCode session logs from opencode.db
|
|
8
|
-
* to reconstruct agent decision traces for HED audit.
|
|
9
|
-
* Uses better-sqlite3 (already a dependency via daemon) for read-only access.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
// OpenCode stores sessions at platform-specific paths:
|
|
13
|
-
// Linux/WSL: ~/.local/share/opencode/opencode.db
|
|
14
|
-
// macOS: ~/Library/Application Support/opencode/opencode.db
|
|
15
|
-
// Windows: %APPDATA%\opencode\opencode.db
|
|
16
|
-
function getOpenCodeDbPath() {
|
|
17
|
-
if (process.platform === 'linux') {
|
|
18
|
-
return path.join(os.homedir(), '.local', 'share', 'opencode', 'opencode.db');
|
|
19
|
-
}
|
|
20
|
-
if (process.platform === 'darwin') {
|
|
21
|
-
return path.join(os.homedir(), 'Library', 'Application Support', 'opencode', 'opencode.db');
|
|
22
|
-
}
|
|
23
|
-
return path.join(os.homedir(), 'AppData', 'Local', 'opencode', 'opencode.db');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async function readSessionLog(sessionKey) {
|
|
27
|
-
if (!sessionKey) return [];
|
|
28
|
-
let Database;
|
|
29
|
-
try {
|
|
30
|
-
Database = require('better-sqlite3');
|
|
31
|
-
} catch {
|
|
32
|
-
console.warn('[session-log-reader] better-sqlite3 not available — cannot read session log');
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
const dbPath = getOpenCodeDbPath();
|
|
36
|
-
let db;
|
|
37
|
-
try {
|
|
38
|
-
db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
39
|
-
} catch (err) {
|
|
40
|
-
console.warn('[session-log-reader] cannot open opencode.db:', err.message);
|
|
41
|
-
return [];
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
const messages = db.prepare(
|
|
45
|
-
`SELECT role, content, created_at FROM messages WHERE session_id = ? ORDER BY created_at ASC`
|
|
46
|
-
).all(sessionKey);
|
|
47
|
-
return messages.map((m, i) => ({
|
|
48
|
-
index: i,
|
|
49
|
-
role: m.role,
|
|
50
|
-
content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
|
|
51
|
-
createdAt: m.created_at
|
|
52
|
-
}));
|
|
53
|
-
} catch (err) {
|
|
54
|
-
console.warn('[session-log-reader] query failed:', err.message);
|
|
55
|
-
return [];
|
|
56
|
-
} finally {
|
|
57
|
-
db.close();
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Classify messages into XEPV sequence: eXplore, Execute, Plan, Verify
|
|
62
|
-
function classifyXEPV(messages) {
|
|
63
|
-
return messages.map(m => {
|
|
64
|
-
const content = m.content || '';
|
|
65
|
-
// Tool calls in content indicate action type
|
|
66
|
-
if (content.includes('"edit"') || content.includes('"write"')) return { ...m, xepv: 'X_Execute' };
|
|
67
|
-
if (content.includes('"read"') || content.includes('"grep"') || content.includes('"search_codebase"') || content.includes('"glob"')) return { ...m, xepv: 'X_Explore' };
|
|
68
|
-
if (content.includes('"bash"') && (content.includes('test') || content.includes('vitest') || content.includes('grep -n'))) return { ...m, xepv: 'X_Verify' };
|
|
69
|
-
if (m.role === 'assistant' && (content.includes('plan') || content.includes('approach') || content.includes('strategy') || content.includes('first'))) return { ...m, xepv: 'X_Plan' };
|
|
70
|
-
return { ...m, xepv: 'X_Unknown' };
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Find the branch point where the agent deviated from the declared target
|
|
75
|
-
function findBranchPoint(xepvMessages, opTarget) {
|
|
76
|
-
const exploreBeforeExecute = xepvMessages.filter(m => m.xepv === 'X_Explore');
|
|
77
|
-
for (const msg of exploreBeforeExecute) {
|
|
78
|
-
// If the agent explored files NOT in the declared target, that's the branch point
|
|
79
|
-
if (opTarget && !msg.content.includes(opTarget)) {
|
|
80
|
-
return { message: msg, reason: `Agent explored ${msg.content.slice(0, 200)} instead of declared target ${opTarget}` };
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Compute P-ratio: plan steps vs execution steps
|
|
87
|
-
function computePRatio(xepvMessages) {
|
|
88
|
-
const plan = xepvMessages.filter(m => m.xepv === 'X_Plan').length;
|
|
89
|
-
const execute = xepvMessages.filter(m => m.xepv === 'X_Execute').length;
|
|
90
|
-
return { planSteps: plan, executeSteps: execute, ratio: execute > 0 ? plan / execute : plan };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
module.exports = { readSessionLog, classifyXEPV, findBranchPoint, computePRatio };
|
package/daemon/routes/hed.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { HEDEngine } = require('../lib/hed-engine');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* HED API routes — /api/hed/*
|
|
7
|
-
* Follows the standard Helios router pattern: returns true if handled, false otherwise.
|
|
8
|
-
* Initialized lazily inside startApi() via createHedRoutes(mgQuery).
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
function jsonOk(res, data, status = 200) {
|
|
12
|
-
res.writeHead(status, {
|
|
13
|
-
'Content-Type': 'application/json',
|
|
14
|
-
'Access-Control-Allow-Origin': '*',
|
|
15
|
-
'Access-Control-Allow-Methods': 'GET, POST, PATCH, OPTIONS',
|
|
16
|
-
'Access-Control-Allow-Headers': 'Content-Type, Accept',
|
|
17
|
-
});
|
|
18
|
-
res.end(JSON.stringify(data));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function jsonErr(res, status, message) {
|
|
22
|
-
res.writeHead(status, {
|
|
23
|
-
'Content-Type': 'application/json',
|
|
24
|
-
'Access-Control-Allow-Origin': '*',
|
|
25
|
-
'Access-Control-Allow-Methods': 'GET, POST, PATCH, OPTIONS',
|
|
26
|
-
'Access-Control-Allow-Headers': 'Content-Type, Accept',
|
|
27
|
-
});
|
|
28
|
-
res.end(JSON.stringify({ error: message }));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function readBody(req) {
|
|
32
|
-
return new Promise((resolve, reject) => {
|
|
33
|
-
let body = '';
|
|
34
|
-
req.on('data', chunk => { body += chunk; });
|
|
35
|
-
req.on('end', () => {
|
|
36
|
-
try { resolve(body ? JSON.parse(body) : {}); }
|
|
37
|
-
catch (e) { reject(new Error('Invalid JSON body')); }
|
|
38
|
-
});
|
|
39
|
-
req.on('error', reject);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function createHedRoutes(mgQuery) {
|
|
44
|
-
const engine = new HEDEngine(mgQuery);
|
|
45
|
-
|
|
46
|
-
return async function hedRoute(req, res, ctx, pathname, method) {
|
|
47
|
-
// Only handle /api/hed paths
|
|
48
|
-
if (!pathname.startsWith('/api/hed')) return false;
|
|
49
|
-
|
|
50
|
-
const mg = ctx?.mgQuery ?? mgQuery;
|
|
51
|
-
const _engine = ctx?.mgQuery ? new HEDEngine(ctx.mgQuery) : engine;
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
// POST /api/hed — create a new HED
|
|
55
|
-
if (method === 'POST' && pathname === '/api/hed') {
|
|
56
|
-
const body = await readBody(req);
|
|
57
|
-
const { companyId, title, intent, worldStateSnapshot, operations, goalId } = body;
|
|
58
|
-
if (!companyId || !title || !operations?.length) {
|
|
59
|
-
jsonErr(res, 400, 'companyId, title, and operations are required');
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
const result = await _engine.createHED({ companyId, title, intent, worldStateSnapshot, operations, goalId });
|
|
63
|
-
jsonOk(res, result, 201);
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// POST /api/hed/:id/approve — HITL approval
|
|
68
|
-
const approveMatch = method === 'POST' && pathname.match(/^\/api\/hed\/([^/]+)\/approve$/);
|
|
69
|
-
if (approveMatch) {
|
|
70
|
-
const hedId = approveMatch[1];
|
|
71
|
-
const body = await readBody(req);
|
|
72
|
-
const { approvedBy } = body;
|
|
73
|
-
await _engine.approveHED(hedId, approvedBy || 'human');
|
|
74
|
-
jsonOk(res, { hedId, approved: true });
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// GET /api/hed/:id/review — aggregated review report
|
|
79
|
-
const reviewMatch = method === 'GET' && pathname.match(/^\/api\/hed\/([^/]+)\/review$/);
|
|
80
|
-
if (reviewMatch) {
|
|
81
|
-
const hedId = reviewMatch[1];
|
|
82
|
-
const operations = await _engine.getOperations(hedId);
|
|
83
|
-
const findings = operations.map(op => ({
|
|
84
|
-
opId: op.id,
|
|
85
|
-
status: op.status,
|
|
86
|
-
reviewVerdict: op.reviewVerdict || 'pending'
|
|
87
|
-
}));
|
|
88
|
-
const aligned = findings.filter(f => f.reviewVerdict === 'ALIGNED').length;
|
|
89
|
-
const deviated = findings.filter(f => f.reviewVerdict === 'DEVIATED').length;
|
|
90
|
-
const failed = findings.filter(f => f.reviewVerdict === 'FAILED').length;
|
|
91
|
-
jsonOk(res, {
|
|
92
|
-
hedId,
|
|
93
|
-
findings,
|
|
94
|
-
summary: { aligned, deviated, failed, pending: findings.length - aligned - deviated - failed }
|
|
95
|
-
});
|
|
96
|
-
return true;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// PATCH /api/hed/:hedId/operations/:opId — update operation status
|
|
100
|
-
const opPatchMatch = method === 'PATCH' && pathname.match(/^\/api\/hed\/([^/]+)\/operations\/([^/]+)$/);
|
|
101
|
-
if (opPatchMatch) {
|
|
102
|
-
const opId = opPatchMatch[2];
|
|
103
|
-
const body = await readBody(req);
|
|
104
|
-
const { status, summary, sessionKey, verdict } = body;
|
|
105
|
-
if (status === 'done' || status === 'completed') {
|
|
106
|
-
await _engine.completeOperation(opId, { summary, sessionKey, verdict });
|
|
107
|
-
}
|
|
108
|
-
jsonOk(res, { opId, updated: true });
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// GET /api/hed/:id — get HED + all operations
|
|
113
|
-
const hedMatch = method === 'GET' && pathname.match(/^\/api\/hed\/([^/]+)$/);
|
|
114
|
-
if (hedMatch) {
|
|
115
|
-
const hedId = hedMatch[1];
|
|
116
|
-
const hed = await _engine.getHED(hedId);
|
|
117
|
-
if (!hed) { jsonErr(res, 404, 'HED not found'); return true; }
|
|
118
|
-
const operations = await _engine.getOperations(hedId);
|
|
119
|
-
jsonOk(res, { ...hed, operations });
|
|
120
|
-
return true;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
} catch (err) {
|
|
124
|
-
console.error('[hed-routes] error:', err.message);
|
|
125
|
-
jsonErr(res, 500, err.message);
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return false;
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
module.exports = { createHedRoutes };
|