@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.
Files changed (146) hide show
  1. package/bin/helios +0 -0
  2. package/bin/helios-rpc-node-wrapper.cjs +0 -0
  3. package/bin/helios-rpc-wrapper.sh +0 -0
  4. package/daemon/adapters/helios-rpc-adapter.js +47 -25
  5. package/daemon/config/com.familiar.helios-daemon.plist +5 -0
  6. package/daemon/config/helios-daemon.service +4 -0
  7. package/daemon/context-enrichment.js +59 -21
  8. package/daemon/helios-api.js +149 -37
  9. package/daemon/helios-company-daemon.js +516 -124
  10. package/daemon/lib/harada/cascade-judge.js +12 -50
  11. package/daemon/lib/harada/mandala.js +20 -0
  12. package/daemon/lib/harada/pillar-dispatcher.js +1 -1
  13. package/daemon/lib/harada/project-factory.js +7 -2
  14. package/daemon/lib/hbo-bridge.js +31 -12
  15. package/daemon/lib/helios-hitl-host.js +15 -2
  16. package/daemon/lib/hitl-interaction-service.js +0 -0
  17. package/daemon/lib/memgraph-verify.js +38 -33
  18. package/daemon/lib/project-drift-detector.js +7 -17
  19. package/daemon/lib/project-semantic-updater.js +1 -14
  20. package/daemon/routes/channels.js +10 -5
  21. package/daemon/routes/harada-map.js +11 -48
  22. package/daemon/routes/hbo.js +89 -28
  23. package/daemon/routes/hitl.js +0 -0
  24. package/daemon/routes/project.js +4 -3
  25. package/daemon/routes/wizard.js +11 -4
  26. package/daemon/schema-migrations-hitl.js +0 -0
  27. package/extensions/001-tool-output-cap.ts +0 -0
  28. package/extensions/context-compaction.ts +45 -26
  29. package/extensions/cortex/activation-bridge.ts +5 -0
  30. package/extensions/cortex/learn.ts +26 -0
  31. package/extensions/email/backfill.ts +0 -0
  32. package/extensions/helios-governance/analysis/ambiguity.ts +0 -0
  33. package/extensions/helios-governance/analysis/compliance.ts +0 -0
  34. package/extensions/helios-governance/analysis/long-task-detector.ts +0 -0
  35. package/extensions/helios-governance/analysis/output-contract.ts +0 -0
  36. package/extensions/helios-governance/analysis/patterns.ts +0 -0
  37. package/extensions/helios-governance/analysis/preflight.ts +0 -0
  38. package/extensions/helios-governance/analysis/recurring-violations.ts +0 -0
  39. package/extensions/helios-governance/analysis/task-classification.ts +0 -0
  40. package/extensions/helios-governance/analysis/task-intent.ts +0 -0
  41. package/extensions/helios-governance/gates/high-impact.ts +1 -1
  42. package/extensions/helios-governance/handlers/_jiti-require.ts +15 -8
  43. package/extensions/helios-governance/handlers/proxy-test-detector.ts +0 -0
  44. package/extensions/hema-dispatch-v3/graph-memory.ts +10 -0
  45. package/extensions/hema-dispatch-v3/index.ts +59 -40
  46. package/extensions/lib/elo-engine.js +0 -0
  47. package/extensions/lib/elo-engine.test.js +0 -0
  48. package/extensions/memgraph-autostart.ts +13 -0
  49. package/extensions/neuroplastic-eval.ts +0 -0
  50. package/extensions/shadow-loop/index.ts +0 -0
  51. package/lib/brain-v2-budget.js +0 -0
  52. package/lib/brain-v2-circuit-breaker.js +0 -0
  53. package/lib/brain-v2.js +0 -0
  54. package/lib/broker/adaptive-throttle.js +0 -0
  55. package/lib/broker/batch-coalescer.js +0 -0
  56. package/lib/broker/bulkhead.js +0 -0
  57. package/lib/broker/channel-registry.js +0 -0
  58. package/lib/broker/circuit-breaker.js +0 -0
  59. package/lib/broker/evidence-cache.js +0 -0
  60. package/lib/broker/health-monitor.js +0 -0
  61. package/lib/broker/mage-queue.js +0 -0
  62. package/lib/broker/priority-queue.js +0 -0
  63. package/lib/broker/server.js.bak-error2-fix +0 -0
  64. package/lib/broker/session-registry.js +0 -0
  65. package/lib/broker/singleton-timers.js +0 -0
  66. package/lib/broker/types.d.ts +0 -0
  67. package/lib/broker/vegas-limit.js +0 -0
  68. package/lib/compression/dist/ccr-store.js +74 -0
  69. package/lib/compression/dist/content-router.js +115 -0
  70. package/lib/compression/dist/pipeline.js +113 -0
  71. package/lib/compression/dist/server.js +265 -0
  72. package/lib/compression/dist/smart-crusher.js +251 -0
  73. package/lib/context-budget.ts +0 -0
  74. package/lib/context-firewall.js +0 -0
  75. package/lib/crm/integration/triage-bridge.js +0 -0
  76. package/lib/email-utils.ts +0 -0
  77. package/lib/eval/__tests__/preflight-checker.test.ts +0 -0
  78. package/lib/eval/__tests__/task-instruction-parser.test.ts +0 -0
  79. package/lib/eval/__tests__/verifier-runner.test.ts +0 -0
  80. package/lib/eval/index.ts +0 -0
  81. package/lib/eval/preflight-checker.ts +0 -0
  82. package/lib/eval/task-domain-classifier.ts +0 -0
  83. package/lib/eval/task-instruction-parser.ts +0 -0
  84. package/lib/eval/verifier-runner.ts +0 -0
  85. package/lib/event-bus.d.ts +0 -0
  86. package/lib/governance-context-selector.ts +0 -0
  87. package/lib/graph/generate-extension-embeddings.js +0 -0
  88. package/lib/graph/generate-static-embeddings.js +0 -0
  89. package/lib/graph/lib/utils.js +1 -1
  90. package/lib/graph-audit.d.ts +0 -0
  91. package/lib/mesh-circuit-breaker.js +0 -0
  92. package/lib/mission-loop/lesson-extractor.ts +0 -0
  93. package/lib/mission-loop/mental-model-scorer.ts +0 -0
  94. package/lib/mission-loop/occ-detector.ts +0 -0
  95. package/lib/mission-loop/query-variants.ts +0 -0
  96. package/lib/mission-loop/verifier-check.ts +0 -0
  97. package/lib/skill-reference-builder.ts +0 -0
  98. package/lib/telemetry/token-breakdown.ts +0 -0
  99. package/lib/tool-compressor.ts +0 -0
  100. package/lib/triage-core/legal-routing.ts +0 -0
  101. package/lib/triage-core/mental-model/dunbar-classifier.ts +0 -0
  102. package/lib/triage-core/mental-model/enrich-all.ts +0 -0
  103. package/lib/triage-core/mental-model/identity-resolver.ts +0 -0
  104. package/lib/triage-core/mental-model/key-facts.ts +0 -0
  105. package/lib/triage-core/mental-model/model-assembler.ts +0 -0
  106. package/lib/triage-core/orchestrator.ts +0 -0
  107. package/lib/triage-core/orchestrator.ts.bak-r005-r006-r008 +0 -0
  108. package/package.json +10 -4
  109. package/skills/helios-business-operator/services/signals/upwork-signals.js +0 -0
  110. package/skills/talisman-ceo/SKILL.md +23 -25
  111. package/skills/talisman-comms/SKILL.md +5 -5
  112. package/skills/talisman-engineering/SKILL.md +5 -5
  113. package/skills/talisman-finance/SKILL.md +10 -8
  114. package/skills/talisman-marketing/SKILL.md +10 -10
  115. package/skills/talisman-sales/SKILL.md +12 -15
  116. package/skills/talisman-support/SKILL.md +5 -5
  117. package/agents/business/talisman-ceo.md +0 -183
  118. package/agents/business/talisman-comms.md +0 -257
  119. package/agents/business/talisman-cto.md +0 -153
  120. package/agents/business/talisman-finance.md +0 -246
  121. package/agents/business/talisman-marketing.md +0 -240
  122. package/agents/business/talisman-sales.md +0 -242
  123. package/agents/business/talisman-support.md +0 -236
  124. package/daemon/lib/approval-expiry.js +0 -162
  125. package/daemon/lib/blast-radius-analyzer.js +0 -75
  126. package/daemon/lib/domain-bootstrap-orchestrator.js +0 -267
  127. package/daemon/lib/forensic-log.js +0 -113
  128. package/daemon/lib/goal-research-pipeline.js +0 -644
  129. package/daemon/lib/harada/cascade-research-dispatcher.js +0 -261
  130. package/daemon/lib/headroom-middleware.js +0 -167
  131. package/daemon/lib/headroom-proxy-manager.js +0 -623
  132. package/daemon/lib/hed-engine.js +0 -307
  133. package/daemon/lib/mental-model-cache.js +0 -96
  134. package/daemon/lib/project-factory.js +0 -47
  135. package/daemon/lib/session-log-reader.js +0 -93
  136. package/daemon/routes/hed.js +0 -133
  137. package/lib/graph/learning/headroom-learn-bridge.js +0 -215
  138. package/skills/helios-bookkeeping/SKILL.md +0 -321
  139. package/skills/helios-briefer/SKILL.md +0 -44
  140. package/skills/helios-client-relations/SKILL.md +0 -322
  141. package/skills/helios-personal-triager/SKILL.md +0 -45
  142. package/skills/helios-recruitment/SKILL.md +0 -317
  143. package/skills/helios-relationship-nudger/SKILL.md +0 -77
  144. package/skills/helios-researcher/SKILL.md +0 -44
  145. package/skills/helios-scheduler/SKILL.md +0 -58
  146. package/skills/helios-tax-analyst/SKILL.md +0 -280
@@ -1,236 +0,0 @@
1
- ---
2
- name: talisman-support
3
- description: Talisman Support — ticket triage, customer issues, FAQ responses, escalation
4
- tools: read, write, edit, bash, grep, find, ls, ~/helios-agent/git/github.com/helios-agi/pi-web-access/index.ts, ~/helios-agent/extensions/codebase-index.ts
5
- extensions: ~/helios-agent/git/github.com/helios-agi/pi-web-access/index.ts, ~/helios-agent/extensions/codebase-index.ts, ~/helios-agent/extensions/cache-split-system-blocks.ts
6
- skills: talisman-support
7
- ---
8
-
9
- # Talisman Support Agent
10
-
11
- You are the **Support Lead** for **Talisman**, an AI-powered accounting platform for small accounting firms. Your mission is to resolve customer issues quickly and accurately, maintain a knowledge base of known issues and solutions, track SLA compliance, and escalate to Engineering when a bug or infrastructure problem is the root cause. Every ticket is logged in Memgraph so the CEO and Finance agents can track customer satisfaction and churn risk.
12
-
13
- ## Responsibilities
14
-
15
- 1. **Ticket Classification** — Categorise every incoming support request by type (bug, question, feature-request, billing, account, integration) and priority (P1–P4) within 30 minutes
16
- 2. **Resolution** — Resolve P3/P4 tickets directly using the knowledge base; escalate P1/P2 bugs to Engineering with full reproduction details
17
- 3. **Knowledge Base Updates** — After resolving a novel issue, write a KB article so the same issue is handled instantly next time
18
- 4. **SLA Monitoring** — Track time-to-first-response and time-to-resolution for every ticket; flag breaches to the CEO
19
- 5. **Customer Satisfaction** — Log CSAT scores after ticket closure; surface declining satisfaction trends to the CEO
20
- 6. **Churn Risk Detection** — When a customer opens their 3rd unresolved ticket in 30 days, flag them as churn risk and notify Sales
21
-
22
- ## Available Tools
23
-
24
- - **bash** — Execute Cypher queries via `node -e` with neo4j-driver; look up customer history and known issues
25
- - **read / write / edit** — Write KB articles, update support playbooks, draft responses
26
- - **web_search** — Research known bugs in third-party integrations; find community solutions
27
-
28
- ## Memgraph Access
29
-
30
- Connect to Memgraph at `bolt://localhost:7687` using neo4j-driver:
31
-
32
- ```bash
33
- node -e "
34
- const neo4j = require('neo4j-driver');
35
- const driver = neo4j.driver('bolt://localhost:7687', neo4j.auth.basic('', ''));
36
- const session = driver.session();
37
- session.run('<CYPHER_QUERY>', {}).then(r => {
38
- console.log(JSON.stringify(r.records.map(rec => rec.toObject()), null, 2));
39
- return session.close();
40
- }).then(() => driver.close()).catch(console.error);
41
- "
42
- ```
43
-
44
- ## Cypher Templates
45
-
46
- ### Create a Support Ticket
47
-
48
- ```cypher
49
- MERGE (p:Person {email: $customerEmail})
50
- ON CREATE SET p.name = $customerName, p.createdAt = localDateTime()
51
- MERGE (o:Organisation {name: $orgName})
52
- MERGE (p)-[:WORKS_AT]->(o)
53
- CREATE (t:SupportTicket {
54
- id: randomUUID(),
55
- title: $title,
56
- description: $description,
57
- type: $type,
58
- priority: $priority,
59
- status: 'open',
60
- channel: $channel,
61
- tags: $tags,
62
- createdAt: localDateTime(),
63
- slaDeadline: localDateTime() + duration({hours: $slaHours}),
64
- assignedTo: 'agent:support',
65
- csatScore: null
66
- })-[:RAISED_BY]->(p)
67
- RETURN t.id
68
- ```
69
-
70
- ### Update Ticket Status
71
-
72
- ```cypher
73
- MATCH (t:SupportTicket {id: $ticketId})
74
- SET t.status = $newStatus,
75
- t.resolution = $resolution,
76
- t.resolvedAt = CASE $newStatus WHEN 'closed' THEN localDateTime() ELSE t.resolvedAt END,
77
- t.lastUpdatedAt = localDateTime(),
78
- t.updatedBy = 'agent:support'
79
- RETURN t.id, t.status, t.resolvedAt
80
- ```
81
-
82
- ### Look Up Customer Ticket History
83
-
84
- ```cypher
85
- MATCH (p:Person {email: $customerEmail})-[:WORKS_AT]->(o:Organisation)
86
- MATCH (t:SupportTicket)-[:RAISED_BY]->(p)
87
- RETURN t.id, t.title, t.type, t.priority, t.status, t.createdAt, t.resolvedAt,
88
- t.csatScore, o.name AS org
89
- ORDER BY t.createdAt DESC
90
- LIMIT 20
91
- ```
92
-
93
- ### Check SLA Breaches
94
-
95
- ```cypher
96
- MATCH (t:SupportTicket)
97
- WHERE t.status IN ['open', 'in_progress']
98
- AND t.slaDeadline < localDateTime()
99
- RETURN t.id, t.title, t.priority, t.status, t.slaDeadline, t.createdAt,
100
- duration.between(t.createdAt, localDateTime()).hours AS ageHours
101
- ORDER BY t.priority ASC, t.slaDeadline ASC
102
- ```
103
-
104
- ### Escalate to Engineering
105
-
106
- ```cypher
107
- MATCH (t:SupportTicket {id: $ticketId})
108
- CREATE (e:EngineeringEscalation {
109
- id: randomUUID(),
110
- ticketId: $ticketId,
111
- title: 'Bug Escalation: ' + t.title,
112
- reproSteps: $reproSteps,
113
- expectedBehavior: $expectedBehavior,
114
- actualBehavior: $actualBehavior,
115
- severity: t.priority,
116
- affectedCustomers: $affectedCustomers,
117
- createdBy: 'agent:support',
118
- createdAt: localDateTime(),
119
- status: 'pending'
120
- })-[:ESCALATED_FROM]->(t)
121
- SET t.status = 'escalated',
122
- t.escalatedAt = localDateTime()
123
- RETURN e.id
124
- ```
125
-
126
- ### Record CSAT Score
127
-
128
- ```cypher
129
- MATCH (t:SupportTicket {id: $ticketId})
130
- SET t.csatScore = $score,
131
- t.csatComment = $comment,
132
- t.csatRecordedAt = localDateTime()
133
- RETURN t.id, t.csatScore
134
- ```
135
-
136
- ### Detect Churn Risk
137
-
138
- ```cypher
139
- MATCH (p:Person)-[:WORKS_AT]->(o:Organisation)
140
- MATCH (t:SupportTicket)-[:RAISED_BY]->(p)
141
- WHERE t.createdAt > localDateTime() - duration({days: 30})
142
- WITH o, p, count(t) AS recentTickets,
143
- sum(CASE WHEN t.status IN ['open', 'escalated'] THEN 1 ELSE 0 END) AS unresolvedTickets
144
- WHERE recentTickets >= 3 OR unresolvedTickets >= 2
145
- RETURN o.name, p.email, recentTickets, unresolvedTickets
146
- ORDER BY unresolvedTickets DESC, recentTickets DESC
147
- ```
148
-
149
- ### Create Knowledge Base Article
150
-
151
- ```cypher
152
- CREATE (kb:KBArticle {
153
- id: randomUUID(),
154
- title: $title,
155
- symptom: $symptom,
156
- rootCause: $rootCause,
157
- resolution: $resolution,
158
- tags: $tags,
159
- relatedTicketId: $relatedTicketId,
160
- authorAgent: 'agent:support',
161
- createdAt: localDateTime(),
162
- views: 0,
163
- helpfulVotes: 0
164
- })
165
- RETURN kb.id
166
- ```
167
-
168
- ### Weekly Support Metrics
169
-
170
- ```cypher
171
- MATCH (t:SupportTicket)
172
- WHERE t.createdAt > localDateTime() - duration({days: 7})
173
- RETURN count(t) AS totalTickets,
174
- sum(CASE WHEN t.status = 'closed' THEN 1 ELSE 0 END) AS resolved,
175
- avg(CASE WHEN t.resolvedAt IS NOT NULL
176
- THEN duration.between(t.createdAt, t.resolvedAt).hours
177
- ELSE null END) AS avgResolutionHours,
178
- avg(t.csatScore) AS avgCsat,
179
- sum(CASE WHEN t.slaDeadline < t.resolvedAt OR (t.status != 'closed' AND t.slaDeadline < localDateTime()) THEN 1 ELSE 0 END) AS slaBreaches
180
- ```
181
-
182
- ## Priority / SLA Matrix
183
-
184
- | Priority | Trigger | First Response SLA | Resolution SLA |
185
- |----------|---------|--------------------|----------------|
186
- | P1 — Critical | Production down, data loss | 30 minutes | 4 hours |
187
- | P2 — High | Core feature broken, workaround exists | 2 hours | 24 hours |
188
- | P3 — Normal | Non-critical issue, question | 4 hours | 72 hours |
189
- | P4 — Low | Feature request, cosmetic | 8 hours | Next sprint |
190
-
191
- ## Escalation Decision Tree
192
-
193
- ```
194
- Is it a bug? Yes → Can I reproduce it? Yes → Engineering Escalation
195
- No → Ask for repro steps → wait
196
- Is it a bug? No → Is answer in KB? Yes → Link KB article → close
197
- No → Draft answer → create KB article → close
198
- Is it billing? → Route to Finance agent
199
- Is it legal? → Create Approval → notify human
200
- ```
201
-
202
- ## Structured Output Schema
203
-
204
- When producing plans, output the following JSON schema. Every action must have an exact tool invocation.
205
-
206
- ```json
207
- {
208
- "planTitle": "string",
209
- "objective": "string",
210
- "phases": [{
211
- "name": "string",
212
- "weeks": "string",
213
- "actions": [{
214
- "description": "string",
215
- "tool": "web_search|bash|write|read",
216
- "command_or_query": "string (exact command/cypher/search query)",
217
- "expected_output": "string",
218
- "success_criteria": "string"
219
- }],
220
- "deliverables": ["string"],
221
- "metrics": {"metric_name": "target_value"}
222
- }],
223
- "total_budget": "string",
224
- "verification_queries": ["cypher query strings"]
225
- }
226
- ```
227
-
228
- ## Operating Principles
229
-
230
- - **Customer history first** — always look up ticket history before responding; a customer with 5 unresolved tickets needs a different response than a first-time contact
231
- - **Reproduce before escalating** — never escalate a bug to Engineering without a confirmed repro; "I can't reproduce it" is not an escalation
232
- - **KB-first responses** — check the knowledge base before writing a custom reply; if a KB article exists, link it and close; if not, create one after resolving
233
- - **SLA clock always running** — check the SLA breach query at the start of every session; any P1 or P2 breach is an immediate priority
234
- - **CSAT after every close** — request a CSAT score within 24 hours of closing a ticket; track the aggregate weekly
235
- - **Churn radar** — run the churn risk query weekly; notify Sales and CEO when a customer shows churn signals
236
- - **Escalation completeness** — every Engineering escalation must include: exact repro steps, expected vs actual behaviour, affected customers, and ticket ID
@@ -1,162 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * ApprovalExpiry — General-purpose approval expiry processor.
5
- *
6
- * Runs on the slow-tick (every 10 daemon ticks). Finds all pending Approval
7
- * nodes whose expiresAt has passed and auto-approves them.
8
- *
9
- * Currently handles:
10
- * - 'kaizen_proposal' — creates PDSACycle + Task + emits AgentReadySignal
11
- * - all other types — marks approved; existing ApprovalWatcher handles follow-up
12
- *
13
- * This makes the 24h auto-accept pattern that was declared in harada/pillar-dispatcher.js
14
- * (expiresAt field set but never processed) actually work.
15
- */
16
-
17
- class ApprovalExpiry {
18
- constructor(mgQuery, companyId, broadcast) {
19
- this.mg = mgQuery;
20
- this.companyId = companyId;
21
- // Broadcast for real-time push when approvals are auto-approved on expiry.
22
- // Falls back to a no-op so expiry processing never crashes on missing broadcast.
23
- this._broadcast = (typeof broadcast === 'function') ? broadcast : () => {};
24
- }
25
-
26
- async check() {
27
- const expired = await this.mg(
28
- `MATCH (a:Approval {companyId: $cid, status: 'pending'})
29
- WHERE a.expiresAt IS NOT NULL AND localDateTime() > a.expiresAt
30
- RETURN a.id AS approvalId, a.type AS type,
31
- a.kaizenProposalId AS kpId`,
32
- { cid: this.companyId }
33
- ).catch(() => null);
34
-
35
- for (const row of (expired?.rows ?? [])) {
36
- const approvalId = row[0] ?? row['approvalId'];
37
- const type = row[1] ?? row['type'];
38
- const kpId = row[2] ?? row['kpId'];
39
-
40
- await this._autoApprove(approvalId, type, kpId);
41
- }
42
- }
43
-
44
- async _autoApprove(approvalId, type, kpId) {
45
- await this.mg(
46
- `MATCH (a:Approval {id: $id})
47
- SET a.status = 'approved',
48
- a.approvedAt = localDateTime(),
49
- a.approvedBy = 'system:auto_expiry',
50
- a.autoApproved = true`,
51
- { id: approvalId }
52
- ).catch(() => {});
53
-
54
- if (type === 'kaizen_proposal' && kpId) {
55
- await this._processKaizenApproval(kpId);
56
- }
57
- // Broadcast so connected desktop clients know this approval was auto-approved.
58
- // Without this, the approval queue only refreshes after the 10s staleTime expires.
59
- // This covers harada_strategy_review 24h auto-approvals and kaizen_proposal expiry.
60
- this._broadcast({ type: 'approval.approved', approvalId, companyId: this.companyId });
61
- // harada_l2_review and other types with expiresAt: the existing ApprovalWatcher
62
- // in helios-company-daemon.js already handles 'approved' status transitions for
63
- // those types — no duplication needed here.
64
- }
65
-
66
- async _processKaizenApproval(kpId) {
67
- const result = await this.mg(
68
- `MATCH (kp:KaizenProposal {id: $kpId})
69
- RETURN kp.ownerAgentId AS owner,
70
- kp.hypothesis AS hypothesis,
71
- kp.proposedCountermeasure AS countermeasure,
72
- kp.problemStatement AS problem`,
73
- { kpId }
74
- ).catch(() => null);
75
-
76
- if (!result?.rows?.length) return;
77
-
78
- const row = result.rows[0];
79
- const owner = row[0] ?? row['owner'];
80
- const hypothesis = row[1] ?? row['hypothesis'];
81
- const countermeasure = row[2] ?? row['countermeasure'];
82
- const problem = row[3] ?? row['problem'];
83
-
84
- if (!owner) return; // no owner — can't dispatch
85
-
86
- const cycleId = `pdsa:kaizen:${kpId}`;
87
- const taskId = `task:kaizen:${kpId}`;
88
-
89
- // Create PDSACycle + Task atomically via MERGE (idempotent on retry)
90
- await this.mg(
91
- `MERGE (p:PDSACycle {id: $cycleId})
92
- ON CREATE SET
93
- p.companyId = $cid,
94
- p.kaizenProposalId = $kpId,
95
- p.planTheory = $hypothesis,
96
- p.planPrediction = $countermeasure,
97
- p.actDecision = 'iterate',
98
- p.createdAt = localDateTime()
99
- MERGE (t:Task {id: $taskId})
100
- ON CREATE SET
101
- t.companyId = $cid,
102
- t.title = 'Kaizen: ' + substring($problem, 0, 120),
103
- t.body = $countermeasure,
104
- t.originKind = 'kaizen_implementation',
105
- t.assigneeAgentId = $owner,
106
- t.status = 'todo',
107
- t.priority = 2,
108
- t.workType = 'improvement',
109
- t.pdsaProcessed = false,
110
- t.andoning = false,
111
- t.createdAt = localDateTime()
112
- MERGE (t)-[:IMPLEMENTS]->(p)
113
- WITH p
114
- MATCH (kp:KaizenProposal {id: $kpId})
115
- MERGE (p)-[:PROMPTED_BY]->(kp)`,
116
- {
117
- cycleId,
118
- taskId,
119
- cid: this.companyId,
120
- hypothesis: hypothesis ?? '',
121
- countermeasure: countermeasure ?? '',
122
- problem: problem ?? 'Kaizen improvement task',
123
- owner,
124
- kpId,
125
- }
126
- ).catch(e => {
127
- // log but don't throw — MERGE is idempotent, partial creation acceptable
128
- console.warn(`[ApprovalExpiry] PDSACycle/Task creation partial for kpId=${kpId}: ${e.message}`);
129
- });
130
-
131
- // Mark KaizenProposal accepted
132
- await this.mg(
133
- `MATCH (kp:KaizenProposal {id: $kpId}) SET kp.status = 'accepted'`,
134
- { kpId }
135
- ).catch(() => {});
136
-
137
- // Transition original andon_paused task to help_pending — a responder is now
138
- // working on the improvement. The original task remains paused but its status
139
- // reflects that help is actively in progress rather than just requested.
140
- await this.mg(
141
- `MATCH (t:Task {companyId: $cid, andoning: true})
142
- WHERE t.status = 'andon_paused'
143
- SET t.status = 'help_pending',
144
- t.helpPendingAt = localDateTime()`,
145
- { cid: this.companyId }
146
- ).catch(() => {});
147
-
148
- // Emit AgentReadySignal so the new improvement task gets dispatched immediately
149
- await this.mg(
150
- `MERGE (s:AgentReadySignal {id: $arsId})
151
- ON CREATE SET
152
- s.agentId = $owner,
153
- s.companyId = $cid,
154
- s.status = 'pending',
155
- s.createdAt = localDateTime(),
156
- s.claimedBy = null`,
157
- { arsId: `ars:kaizen:${taskId}`, owner, cid: this.companyId }
158
- ).catch(() => {});
159
- }
160
- }
161
-
162
- module.exports = { ApprovalExpiry };
@@ -1,75 +0,0 @@
1
- 'use strict';
2
-
3
- const { execFile } = require('child_process');
4
- const { promisify } = require('util');
5
- const execFileAsync = promisify(execFile);
6
-
7
- /**
8
- * BlastRadiusAnalyzer — measures the impact of a HED operation's execution.
9
- * Compares declared target vs actual changes (git diff + Memgraph diff).
10
- */
11
-
12
- class BlastRadiusAnalyzer {
13
- constructor(mg, repoPath) {
14
- this._mg = mg;
15
- this._repoPath = repoPath || process.cwd();
16
- }
17
-
18
- async analyze(opId, operation, executionLockedAt, completedAt) {
19
- const [filesChanged, nodesAffected] = await Promise.allSettled([
20
- this._getChangedFiles(operation.target),
21
- this._getChangedNodes(executionLockedAt, completedAt)
22
- ]);
23
-
24
- const changedFiles = filesChanged.status === 'fulfilled' ? filesChanged.value : [];
25
- const changedNodes = nodesAffected.status === 'fulfilled' ? nodesAffected.value : [];
26
-
27
- const outsideTarget = changedFiles.filter(f => !f.includes(operation.target || ''));
28
- const severity = this._computeSeverity(outsideTarget, changedNodes);
29
-
30
- return {
31
- filesChanged: outsideTarget,
32
- allFilesChanged: changedFiles,
33
- nodesAffected: changedNodes,
34
- severity,
35
- opId
36
- };
37
- }
38
-
39
- async _getChangedFiles(declaredTarget) {
40
- try {
41
- const { stdout } = await execFileAsync('git', ['diff', '--name-only', 'HEAD~1'], {
42
- cwd: this._repoPath,
43
- windowsHide: true
44
- });
45
- return stdout.trim().split('\n').filter(Boolean);
46
- } catch {
47
- return [];
48
- }
49
- }
50
-
51
- async _getChangedNodes(executionLockedAt, completedAt) {
52
- if (!executionLockedAt || !completedAt) return [];
53
- try {
54
- const rows = await this._mg(
55
- `MATCH (n) WHERE n.updatedAt >= $from AND n.updatedAt <= $to
56
- RETURN DISTINCT labels(n)[0] AS label, count(n) AS count LIMIT 20`,
57
- { from: executionLockedAt, to: completedAt }
58
- );
59
- return (rows || []).map(r => `${r.label}(${r.count})`);
60
- } catch {
61
- return [];
62
- }
63
- }
64
-
65
- _computeSeverity(outsideFiles, changedNodes) {
66
- const score = outsideFiles.length * 2 + changedNodes.length;
67
- if (score === 0) return 'none';
68
- if (score <= 2) return 'low';
69
- if (score <= 6) return 'medium';
70
- if (score <= 12) return 'high';
71
- return 'critical';
72
- }
73
- }
74
-
75
- module.exports = { BlastRadiusAnalyzer };