@runcore-sh/runcore 0.1.8 → 0.1.10

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 (225) hide show
  1. package/dist/access/manifest.d.ts +59 -0
  2. package/dist/access/manifest.d.ts.map +1 -0
  3. package/dist/access/manifest.js +251 -0
  4. package/dist/access/manifest.js.map +1 -0
  5. package/dist/activity/log.d.ts +1 -1
  6. package/dist/activity/log.d.ts.map +1 -1
  7. package/dist/agents/autonomous.d.ts.map +1 -1
  8. package/dist/agents/autonomous.js +38 -0
  9. package/dist/agents/autonomous.js.map +1 -1
  10. package/dist/agents/governance.d.ts +70 -0
  11. package/dist/agents/governance.d.ts.map +1 -0
  12. package/dist/agents/governance.js +220 -0
  13. package/dist/agents/governance.js.map +1 -0
  14. package/dist/agents/governed-spawn.d.ts +83 -0
  15. package/dist/agents/governed-spawn.d.ts.map +1 -0
  16. package/dist/agents/governed-spawn.js +186 -0
  17. package/dist/agents/governed-spawn.js.map +1 -0
  18. package/dist/agents/heartbeat.d.ts +91 -0
  19. package/dist/agents/heartbeat.d.ts.map +1 -0
  20. package/dist/agents/heartbeat.js +323 -0
  21. package/dist/agents/heartbeat.js.map +1 -0
  22. package/dist/agents/index.d.ts +4 -1
  23. package/dist/agents/index.d.ts.map +1 -1
  24. package/dist/agents/index.js +6 -1
  25. package/dist/agents/index.js.map +1 -1
  26. package/dist/agents/spawn-policy.d.ts +45 -0
  27. package/dist/agents/spawn-policy.d.ts.map +1 -0
  28. package/dist/agents/spawn-policy.js +202 -0
  29. package/dist/agents/spawn-policy.js.map +1 -0
  30. package/dist/alert.d.ts +16 -0
  31. package/dist/alert.d.ts.map +1 -0
  32. package/dist/alert.js +70 -0
  33. package/dist/alert.js.map +1 -0
  34. package/dist/cli.js +261 -32
  35. package/dist/cli.js.map +1 -1
  36. package/dist/credentials/store.d.ts +1 -1
  37. package/dist/credentials/store.d.ts.map +1 -1
  38. package/dist/credentials/store.js +14 -3
  39. package/dist/credentials/store.js.map +1 -1
  40. package/dist/crystallizer.d.ts +56 -0
  41. package/dist/crystallizer.d.ts.map +1 -0
  42. package/dist/crystallizer.js +159 -0
  43. package/dist/crystallizer.js.map +1 -0
  44. package/dist/distiller.d.ts +48 -0
  45. package/dist/distiller.d.ts.map +1 -0
  46. package/dist/distiller.js +140 -0
  47. package/dist/distiller.js.map +1 -0
  48. package/dist/files/deep-index.d.ts +59 -0
  49. package/dist/files/deep-index.d.ts.map +1 -0
  50. package/dist/files/deep-index.js +337 -0
  51. package/dist/files/deep-index.js.map +1 -0
  52. package/dist/files/import.d.ts +44 -0
  53. package/dist/files/import.d.ts.map +1 -0
  54. package/dist/files/import.js +213 -0
  55. package/dist/files/import.js.map +1 -0
  56. package/dist/files/index-local.d.ts +37 -0
  57. package/dist/files/index-local.d.ts.map +1 -0
  58. package/dist/files/index-local.js +198 -0
  59. package/dist/files/index-local.js.map +1 -0
  60. package/dist/google/auth.d.ts +2 -0
  61. package/dist/google/auth.d.ts.map +1 -1
  62. package/dist/google/auth.js +2 -0
  63. package/dist/google/auth.js.map +1 -1
  64. package/dist/integrations/gate.d.ts +40 -0
  65. package/dist/integrations/gate.d.ts.map +1 -0
  66. package/dist/integrations/gate.js +100 -0
  67. package/dist/integrations/gate.js.map +1 -0
  68. package/dist/lib/audit.d.ts +43 -0
  69. package/dist/lib/audit.d.ts.map +1 -0
  70. package/dist/lib/audit.js +120 -0
  71. package/dist/lib/audit.js.map +1 -0
  72. package/dist/lib/brain-io.d.ts.map +1 -1
  73. package/dist/lib/brain-io.js +52 -0
  74. package/dist/lib/brain-io.js.map +1 -1
  75. package/dist/lib/dpapi.d.ts +14 -0
  76. package/dist/lib/dpapi.d.ts.map +1 -0
  77. package/dist/lib/dpapi.js +104 -0
  78. package/dist/lib/dpapi.js.map +1 -0
  79. package/dist/lib/glob-match.d.ts +22 -0
  80. package/dist/lib/glob-match.d.ts.map +1 -0
  81. package/dist/lib/glob-match.js +64 -0
  82. package/dist/lib/glob-match.js.map +1 -0
  83. package/dist/lib/locked.d.ts +40 -0
  84. package/dist/lib/locked.d.ts.map +1 -0
  85. package/dist/lib/locked.js +130 -0
  86. package/dist/lib/locked.js.map +1 -0
  87. package/dist/llm/complete.d.ts.map +1 -1
  88. package/dist/llm/complete.js +5 -2
  89. package/dist/llm/complete.js.map +1 -1
  90. package/dist/llm/fetch-guard.d.ts +16 -0
  91. package/dist/llm/fetch-guard.d.ts.map +1 -0
  92. package/dist/llm/fetch-guard.js +61 -0
  93. package/dist/llm/fetch-guard.js.map +1 -0
  94. package/dist/llm/guard.d.ts +40 -0
  95. package/dist/llm/guard.d.ts.map +1 -0
  96. package/dist/llm/guard.js +88 -0
  97. package/dist/llm/guard.js.map +1 -0
  98. package/dist/llm/membrane.d.ts +46 -0
  99. package/dist/llm/membrane.d.ts.map +1 -0
  100. package/dist/llm/membrane.js +123 -0
  101. package/dist/llm/membrane.js.map +1 -0
  102. package/dist/llm/providers/index.d.ts +5 -1
  103. package/dist/llm/providers/index.d.ts.map +1 -1
  104. package/dist/llm/providers/index.js +8 -1
  105. package/dist/llm/providers/index.js.map +1 -1
  106. package/dist/llm/redact.d.ts +39 -0
  107. package/dist/llm/redact.d.ts.map +1 -0
  108. package/dist/llm/redact.js +155 -0
  109. package/dist/llm/redact.js.map +1 -0
  110. package/dist/llm/sensitive-registry.d.ts +33 -0
  111. package/dist/llm/sensitive-registry.d.ts.map +1 -0
  112. package/dist/llm/sensitive-registry.js +106 -0
  113. package/dist/llm/sensitive-registry.js.map +1 -0
  114. package/dist/mcp-server.d.ts +11 -0
  115. package/dist/mcp-server.d.ts.map +1 -0
  116. package/dist/mcp-server.js +520 -0
  117. package/dist/mcp-server.js.map +1 -0
  118. package/dist/mdns.d.ts +17 -0
  119. package/dist/mdns.d.ts.map +1 -0
  120. package/dist/mdns.js +110 -0
  121. package/dist/mdns.js.map +1 -0
  122. package/dist/nerve/push.d.ts +26 -0
  123. package/dist/nerve/push.d.ts.map +1 -0
  124. package/dist/nerve/push.js +170 -0
  125. package/dist/nerve/push.js.map +1 -0
  126. package/dist/nerve/state.d.ts +35 -0
  127. package/dist/nerve/state.d.ts.map +1 -0
  128. package/dist/nerve/state.js +257 -0
  129. package/dist/nerve/state.js.map +1 -0
  130. package/dist/posture/engine.d.ts +41 -0
  131. package/dist/posture/engine.d.ts.map +1 -0
  132. package/dist/posture/engine.js +217 -0
  133. package/dist/posture/engine.js.map +1 -0
  134. package/dist/posture/index.d.ts +11 -0
  135. package/dist/posture/index.d.ts.map +1 -0
  136. package/dist/posture/index.js +10 -0
  137. package/dist/posture/index.js.map +1 -0
  138. package/dist/posture/middleware.d.ts +30 -0
  139. package/dist/posture/middleware.d.ts.map +1 -0
  140. package/dist/posture/middleware.js +92 -0
  141. package/dist/posture/middleware.js.map +1 -0
  142. package/dist/posture/types.d.ts +61 -0
  143. package/dist/posture/types.d.ts.map +1 -0
  144. package/dist/posture/types.js +48 -0
  145. package/dist/posture/types.js.map +1 -0
  146. package/dist/resend/inbox.d.ts +23 -0
  147. package/dist/resend/inbox.d.ts.map +1 -0
  148. package/dist/resend/inbox.js +198 -0
  149. package/dist/resend/inbox.js.map +1 -0
  150. package/dist/resend/webhooks.d.ts +30 -0
  151. package/dist/resend/webhooks.d.ts.map +1 -0
  152. package/dist/resend/webhooks.js +244 -0
  153. package/dist/resend/webhooks.js.map +1 -0
  154. package/dist/server.d.ts +5 -1
  155. package/dist/server.d.ts.map +1 -1
  156. package/dist/server.js +773 -58
  157. package/dist/server.js.map +1 -1
  158. package/dist/settings.d.ts +14 -1
  159. package/dist/settings.d.ts.map +1 -1
  160. package/dist/settings.js +32 -1
  161. package/dist/settings.js.map +1 -1
  162. package/dist/tier/bond.d.ts +51 -0
  163. package/dist/tier/bond.d.ts.map +1 -0
  164. package/dist/tier/bond.js +154 -0
  165. package/dist/tier/bond.js.map +1 -0
  166. package/dist/tier/freeze.d.ts +21 -0
  167. package/dist/tier/freeze.d.ts.map +1 -0
  168. package/dist/tier/freeze.js +73 -0
  169. package/dist/tier/freeze.js.map +1 -0
  170. package/dist/tier/gate.d.ts +11 -0
  171. package/dist/tier/gate.d.ts.map +1 -0
  172. package/dist/tier/gate.js +25 -0
  173. package/dist/tier/gate.js.map +1 -0
  174. package/dist/tier/heartbeat.d.ts +22 -0
  175. package/dist/tier/heartbeat.d.ts.map +1 -0
  176. package/dist/tier/heartbeat.js +128 -0
  177. package/dist/tier/heartbeat.js.map +1 -0
  178. package/dist/tier/token.d.ts +22 -0
  179. package/dist/tier/token.d.ts.map +1 -0
  180. package/dist/tier/token.js +100 -0
  181. package/dist/tier/token.js.map +1 -0
  182. package/dist/tier/types.d.ts +44 -0
  183. package/dist/tier/types.d.ts.map +1 -0
  184. package/dist/tier/types.js +61 -0
  185. package/dist/tier/types.js.map +1 -0
  186. package/dist/updater.d.ts +32 -0
  187. package/dist/updater.d.ts.map +1 -0
  188. package/dist/updater.js +145 -0
  189. package/dist/updater.js.map +1 -0
  190. package/dist/vault/policy.d.ts +42 -0
  191. package/dist/vault/policy.d.ts.map +1 -0
  192. package/dist/vault/policy.js +159 -0
  193. package/dist/vault/policy.js.map +1 -0
  194. package/dist/vault/store.d.ts +6 -0
  195. package/dist/vault/store.d.ts.map +1 -1
  196. package/dist/vault/store.js +15 -5
  197. package/dist/vault/store.js.map +1 -1
  198. package/dist/vault/transfer.d.ts +33 -0
  199. package/dist/vault/transfer.d.ts.map +1 -0
  200. package/dist/vault/transfer.js +187 -0
  201. package/dist/vault/transfer.js.map +1 -0
  202. package/dist/voucher.d.ts +39 -0
  203. package/dist/voucher.d.ts.map +1 -0
  204. package/dist/voucher.js +105 -0
  205. package/dist/voucher.js.map +1 -0
  206. package/dist/webhooks/handlers.d.ts +10 -0
  207. package/dist/webhooks/handlers.d.ts.map +1 -1
  208. package/dist/webhooks/handlers.js +53 -0
  209. package/dist/webhooks/handlers.js.map +1 -1
  210. package/dist/webhooks/index.d.ts +2 -2
  211. package/dist/webhooks/index.d.ts.map +1 -1
  212. package/dist/webhooks/index.js +2 -2
  213. package/dist/webhooks/index.js.map +1 -1
  214. package/dist/webhooks/verify.d.ts +8 -0
  215. package/dist/webhooks/verify.d.ts.map +1 -1
  216. package/dist/webhooks/verify.js +56 -0
  217. package/dist/webhooks/verify.js.map +1 -1
  218. package/package.json +8 -2
  219. package/public/board.html +8 -3
  220. package/public/browser.html +8 -3
  221. package/public/library.html +8 -3
  222. package/public/observatory.html +8 -3
  223. package/public/ops.html +8 -3
  224. package/public/registry.html +627 -0
  225. package/public/roadmap.html +975 -0
@@ -0,0 +1,323 @@
1
+ /**
2
+ * Agent Heartbeat Monitor — CORE-9
3
+ *
4
+ * Action-based heartbeat: every agent action IS the ping.
5
+ * No polling, no timer-based pings. The append-only log is the tracking.
6
+ *
7
+ * Monitors:
8
+ * 1. **Silence detection** — agent produces no output for too long → terminate
9
+ * 2. **Drift detection** — agent's actions diverge from the assigned task → warn/terminate
10
+ * 3. **Heartbeat logging** — append-only JSONL trail of agent pulses
11
+ *
12
+ * Designed to work with the existing activity log system. Each agent gets
13
+ * a HeartbeatTracker that watches for signs of life and task adherence.
14
+ */
15
+ import { join, resolve } from "node:path";
16
+ import { createLogger } from "../utils/logger.js";
17
+ import { logActivity, generateTraceId } from "../activity/log.js";
18
+ import { appendBrainLineSync, ensureBrainFileSync, } from "../lib/brain-io.js";
19
+ const log = createLogger("heartbeat");
20
+ const OPS_DIR = resolve(process.cwd(), "brain", "ops");
21
+ const HEARTBEAT_FILE = join(OPS_DIR, "heartbeats.jsonl");
22
+ const SCHEMA_LINE = JSON.stringify({ _schema: "heartbeat", _version: "1.0" });
23
+ // Ensure the file exists on module load
24
+ try {
25
+ ensureBrainFileSync(HEARTBEAT_FILE, SCHEMA_LINE);
26
+ }
27
+ catch {
28
+ // Non-fatal — will retry on first write
29
+ }
30
+ // ---------------------------------------------------------------------------
31
+ // Default config
32
+ // ---------------------------------------------------------------------------
33
+ const DEFAULT_CONFIG = {
34
+ silenceWarningMs: 120_000, // 2 minutes
35
+ silenceTerminateMs: 300_000, // 5 minutes
36
+ checkIntervalMs: 15_000, // 15 seconds
37
+ taskDescription: "",
38
+ taskKeywords: [],
39
+ maxDriftWarnings: 3,
40
+ };
41
+ // ---------------------------------------------------------------------------
42
+ // Heartbeat persistence
43
+ // ---------------------------------------------------------------------------
44
+ function persistPulse(pulse) {
45
+ try {
46
+ ensureBrainFileSync(HEARTBEAT_FILE, SCHEMA_LINE);
47
+ appendBrainLineSync(HEARTBEAT_FILE, JSON.stringify(pulse));
48
+ }
49
+ catch (err) {
50
+ log.warn("Failed to persist heartbeat pulse", {
51
+ taskId: pulse.taskId,
52
+ error: err instanceof Error ? err.message : String(err),
53
+ });
54
+ }
55
+ }
56
+ // ---------------------------------------------------------------------------
57
+ // Keyword extraction for drift detection
58
+ // ---------------------------------------------------------------------------
59
+ /** Extract meaningful keywords from a task description. */
60
+ export function extractTaskKeywords(description) {
61
+ // Remove common stop words and short words, keep meaningful terms
62
+ const stopWords = new Set([
63
+ "the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for",
64
+ "of", "with", "by", "from", "is", "are", "was", "were", "be", "been",
65
+ "being", "have", "has", "had", "do", "does", "did", "will", "would",
66
+ "could", "should", "may", "might", "shall", "can", "this", "that",
67
+ "these", "those", "it", "its", "not", "no", "all", "any", "each",
68
+ "every", "if", "then", "else", "when", "where", "how", "what", "which",
69
+ "who", "whom", "why", "so", "as", "up", "out", "about", "into", "over",
70
+ "after", "before", "between", "under", "above", "below", "just", "also",
71
+ "very", "too", "only", "own", "same", "than", "other", "such", "more",
72
+ "most", "some", "make", "use", "get", "set", "add", "run", "file",
73
+ ]);
74
+ return description
75
+ .toLowerCase()
76
+ .replace(/[^a-z0-9\s-]/g, " ")
77
+ .split(/\s+/)
78
+ .filter((w) => w.length > 2 && !stopWords.has(w))
79
+ .slice(0, 20); // Cap at 20 keywords
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // Simple drift heuristic
83
+ // ---------------------------------------------------------------------------
84
+ /**
85
+ * Score how relevant an action summary is to the original task.
86
+ * Returns 0.0 (no overlap) to 1.0 (perfect overlap).
87
+ * Uses simple keyword overlap — not semantic, but fast and transparent.
88
+ */
89
+ function driftScore(actionSummary, taskKeywords) {
90
+ if (taskKeywords.length === 0)
91
+ return 1.0; // No keywords = no drift detection
92
+ const actionWords = new Set(actionSummary
93
+ .toLowerCase()
94
+ .replace(/[^a-z0-9\s-]/g, " ")
95
+ .split(/\s+/)
96
+ .filter((w) => w.length > 2));
97
+ let matches = 0;
98
+ for (const kw of taskKeywords) {
99
+ if (actionWords.has(kw))
100
+ matches++;
101
+ }
102
+ return matches / taskKeywords.length;
103
+ }
104
+ // ---------------------------------------------------------------------------
105
+ // HeartbeatTracker — per-agent instance
106
+ // ---------------------------------------------------------------------------
107
+ export class HeartbeatTracker {
108
+ taskId;
109
+ instanceId;
110
+ config;
111
+ onTerminate;
112
+ lastPulseAt;
113
+ driftWarnings = 0;
114
+ totalPulses = 0;
115
+ checkTimer = null;
116
+ terminated = false;
117
+ traceId;
118
+ constructor(taskId, instanceId, config, onTerminate) {
119
+ this.taskId = taskId;
120
+ this.instanceId = instanceId;
121
+ this.config = { ...DEFAULT_CONFIG, ...config };
122
+ this.onTerminate = onTerminate;
123
+ this.lastPulseAt = Date.now();
124
+ this.traceId = generateTraceId();
125
+ // If task description provided but no keywords, extract them
126
+ if (this.config.taskDescription && this.config.taskKeywords.length === 0) {
127
+ this.config.taskKeywords = extractTaskKeywords(this.config.taskDescription);
128
+ }
129
+ }
130
+ /** Start monitoring the agent's heartbeat. */
131
+ start() {
132
+ if (this.checkTimer)
133
+ return;
134
+ this.recordPulse("spawn", "Agent spawned, heartbeat tracking started");
135
+ this.checkTimer = setInterval(() => {
136
+ this.check();
137
+ }, this.config.checkIntervalMs);
138
+ log.info("Heartbeat tracking started", {
139
+ taskId: this.taskId,
140
+ instanceId: this.instanceId,
141
+ keywords: this.config.taskKeywords.slice(0, 5),
142
+ });
143
+ }
144
+ /** Stop monitoring (call on agent completion). */
145
+ stop(reason = "complete") {
146
+ if (this.checkTimer) {
147
+ clearInterval(this.checkTimer);
148
+ this.checkTimer = null;
149
+ }
150
+ this.recordPulse(reason, `Heartbeat tracking stopped: ${reason}`);
151
+ log.info("Heartbeat tracking stopped", {
152
+ taskId: this.taskId,
153
+ instanceId: this.instanceId,
154
+ reason,
155
+ totalPulses: this.totalPulses,
156
+ driftWarnings: this.driftWarnings,
157
+ });
158
+ }
159
+ /**
160
+ * Record a heartbeat pulse. Call this whenever the agent produces
161
+ * observable output (file write, stdout, checkpoint).
162
+ */
163
+ recordPulse(type, detail, actionSummary) {
164
+ if (this.terminated)
165
+ return;
166
+ this.lastPulseAt = Date.now();
167
+ this.totalPulses++;
168
+ const pulse = {
169
+ timestamp: new Date().toISOString(),
170
+ taskId: this.taskId,
171
+ instanceId: this.instanceId,
172
+ type,
173
+ detail,
174
+ actionSummary,
175
+ };
176
+ persistPulse(pulse);
177
+ // Drift detection on action pulses
178
+ if (type === "action" && actionSummary && this.config.taskKeywords.length > 0) {
179
+ const score = driftScore(actionSummary, this.config.taskKeywords);
180
+ if (score < 0.1) {
181
+ this.driftWarnings++;
182
+ log.warn("Drift detected", {
183
+ taskId: this.taskId,
184
+ instanceId: this.instanceId,
185
+ score,
186
+ actionSummary: actionSummary.slice(0, 100),
187
+ driftWarnings: this.driftWarnings,
188
+ maxDriftWarnings: this.config.maxDriftWarnings,
189
+ });
190
+ logActivity({
191
+ source: "agent",
192
+ summary: `Drift warning (${this.driftWarnings}/${this.config.maxDriftWarnings}): ${this.taskId}`,
193
+ detail: `Score: ${score.toFixed(2)}, action: ${actionSummary.slice(0, 200)}`,
194
+ traceId: this.traceId,
195
+ actionLabel: "AUTONOMOUS",
196
+ reason: "heartbeat-drift",
197
+ });
198
+ if (this.driftWarnings >= this.config.maxDriftWarnings) {
199
+ this.terminateAgent(`Drift limit exceeded (${this.driftWarnings} warnings)`);
200
+ }
201
+ }
202
+ else if (score > 0.3) {
203
+ // Good signal — reset drift counter on clearly relevant actions
204
+ this.driftWarnings = Math.max(0, this.driftWarnings - 1);
205
+ }
206
+ }
207
+ }
208
+ /** Get the current heartbeat status. */
209
+ getStatus() {
210
+ const silenceMs = Date.now() - this.lastPulseAt;
211
+ let state = "healthy";
212
+ if (this.terminated) {
213
+ state = "terminated";
214
+ }
215
+ else if (silenceMs > this.config.silenceTerminateMs) {
216
+ state = "critical";
217
+ }
218
+ else if (silenceMs > this.config.silenceWarningMs ||
219
+ this.driftWarnings >= this.config.maxDriftWarnings - 1) {
220
+ state = "warning";
221
+ }
222
+ return {
223
+ taskId: this.taskId,
224
+ instanceId: this.instanceId,
225
+ alive: !this.terminated,
226
+ lastPulseAt: this.lastPulseAt ? new Date(this.lastPulseAt).toISOString() : null,
227
+ silenceMs,
228
+ driftWarnings: this.driftWarnings,
229
+ totalPulses: this.totalPulses,
230
+ state,
231
+ };
232
+ }
233
+ // -------------------------------------------------------------------------
234
+ // Internal
235
+ // -------------------------------------------------------------------------
236
+ check() {
237
+ if (this.terminated)
238
+ return;
239
+ const silenceMs = Date.now() - this.lastPulseAt;
240
+ if (silenceMs > this.config.silenceTerminateMs) {
241
+ this.terminateAgent(`Silence timeout: no activity for ${Math.round(silenceMs / 1000)}s ` +
242
+ `(limit: ${Math.round(this.config.silenceTerminateMs / 1000)}s)`);
243
+ return;
244
+ }
245
+ if (silenceMs > this.config.silenceWarningMs) {
246
+ this.recordPulse("silence-warning", `No activity for ${Math.round(silenceMs / 1000)}s`);
247
+ logActivity({
248
+ source: "agent",
249
+ summary: `Silence warning: ${this.taskId}`,
250
+ detail: `No activity for ${Math.round(silenceMs / 1000)}s`,
251
+ traceId: this.traceId,
252
+ actionLabel: "AUTONOMOUS",
253
+ reason: "heartbeat-silence",
254
+ });
255
+ }
256
+ }
257
+ terminateAgent(reason) {
258
+ if (this.terminated)
259
+ return;
260
+ this.terminated = true;
261
+ log.warn("Terminating agent via heartbeat", {
262
+ taskId: this.taskId,
263
+ instanceId: this.instanceId,
264
+ reason,
265
+ });
266
+ this.recordPulse("terminate", reason);
267
+ logActivity({
268
+ source: "agent",
269
+ summary: `Heartbeat termination: ${this.taskId}`,
270
+ detail: reason,
271
+ traceId: this.traceId,
272
+ actionLabel: "AUTONOMOUS",
273
+ reason: "heartbeat-terminate",
274
+ });
275
+ this.stop("terminate");
276
+ // Fire-and-forget termination callback
277
+ this.onTerminate(this.instanceId, reason).catch((err) => {
278
+ log.error("Failed to terminate agent", {
279
+ instanceId: this.instanceId,
280
+ error: err instanceof Error ? err.message : String(err),
281
+ });
282
+ });
283
+ }
284
+ }
285
+ // ---------------------------------------------------------------------------
286
+ // Tracker registry — manage all active heartbeat trackers
287
+ // ---------------------------------------------------------------------------
288
+ const activeTrackers = new Map();
289
+ /** Create and register a heartbeat tracker for an agent instance. */
290
+ export function createHeartbeatTracker(taskId, instanceId, config, onTerminate) {
291
+ // Clean up any existing tracker for this instance
292
+ const existing = activeTrackers.get(instanceId);
293
+ if (existing) {
294
+ existing.stop("terminate");
295
+ }
296
+ const tracker = new HeartbeatTracker(taskId, instanceId, config, onTerminate);
297
+ activeTrackers.set(instanceId, tracker);
298
+ return tracker;
299
+ }
300
+ /** Get a tracker by instance ID. */
301
+ export function getHeartbeatTracker(instanceId) {
302
+ return activeTrackers.get(instanceId);
303
+ }
304
+ /** Remove a tracker (call on agent completion). */
305
+ export function removeHeartbeatTracker(instanceId) {
306
+ const tracker = activeTrackers.get(instanceId);
307
+ if (tracker) {
308
+ tracker.stop();
309
+ activeTrackers.delete(instanceId);
310
+ }
311
+ }
312
+ /** Get status of all tracked agents. */
313
+ export function getAllHeartbeatStatuses() {
314
+ return Array.from(activeTrackers.values()).map((t) => t.getStatus());
315
+ }
316
+ /** Stop all trackers (call on shutdown). */
317
+ export function shutdownHeartbeats() {
318
+ for (const [id, tracker] of activeTrackers) {
319
+ tracker.stop("terminate");
320
+ activeTrackers.delete(id);
321
+ }
322
+ }
323
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../src/agents/heartbeat.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,9 @@ export { acquireLocks, releaseLocks, releaseFileLock, forceReleaseLock, listLock
7
7
  export { Orchestrator, parseFilesFromOutput, type WorkflowTaskDef, type CreateWorkflowInput, type Workflow, type WorkflowTask, type WorkflowResult, type WorkflowStatus, type TaskStatus, type FileConflict, type ConflictStrategy, type ExecutionMode, type OrchestratorReport, } from "./orchestration.js";
8
8
  export { TaskCooldownManager, type CooldownConfig, type CooldownEntry, type CooldownStatus, } from "./cooldown.js";
9
9
  export { WorkflowEngine, parseWorkflowFile, type WorkflowDefinition, type StepDef, type Condition, type FailurePolicy, type WorkflowRun, type StepResult, type StepStatus, } from "./workflow.js";
10
+ export { governanceGate, revokeGovernanceVoucher, validateGovernanceVoucher, type GovernanceDecision, type GovernanceAuditEntry, type GovernanceOptions, } from "./governance.js";
11
+ export { HeartbeatTracker, createHeartbeatTracker, getHeartbeatTracker, removeHeartbeatTracker, getAllHeartbeatStatuses, shutdownHeartbeats, extractTaskKeywords, type HeartbeatPulse, type HeartbeatConfig, type HeartbeatStatus, type TerminateCallback, } from "./heartbeat.js";
12
+ export { governedSpawn, type GovernedSpawnRequest, type GovernedSpawnResult, type GovernedSpawnDeps, } from "./governed-spawn.js";
10
13
  import type { CreateTaskInput, AgentTask } from "./types.js";
11
14
  /** Create a task and immediately spawn it. */
12
15
  export declare function submitTask(input: CreateTaskInput): Promise<AgentTask>;
@@ -29,6 +32,6 @@ export declare function initAgents(): Promise<void>;
29
32
  * This prevents the double-recovery race that caused DASH-82.
30
33
  */
31
34
  export declare function recoverAndStartMonitor(): Promise<void>;
32
- /** Shutdown: stop the monitor. Does NOT kill detached processes. */
35
+ /** Shutdown: stop the monitor and heartbeat trackers. Does NOT kill detached processes. */
33
36
  export declare function shutdownAgents(): void;
34
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK7D,8CAA8C;AAC9C,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAI3E;AAED,+BAA+B;AAC/B,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAEnE;AAED,oCAAoC;AACpC,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE/D;AAED,6BAA6B;AAC7B,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7D;AAED;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAEhD;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG5D;AAED,oEAAoE;AACpE,wBAAgB,cAAc,IAAI,IAAI,CAErC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAM7D,8CAA8C;AAC9C,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAI3E;AAED,+BAA+B;AAC/B,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAEnE;AAED,oCAAoC;AACpC,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE/D;AAED,6BAA6B;AAC7B,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7D;AAED;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAEhD;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG5D;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,IAAI,IAAI,CAGrC"}
@@ -5,9 +5,13 @@ export { acquireLocks, releaseLocks, releaseFileLock, forceReleaseLock, listLock
5
5
  export { Orchestrator, parseFilesFromOutput, } from "./orchestration.js";
6
6
  export { TaskCooldownManager, } from "./cooldown.js";
7
7
  export { WorkflowEngine, parseWorkflowFile, } from "./workflow.js";
8
+ export { governanceGate, revokeGovernanceVoucher, validateGovernanceVoucher, } from "./governance.js";
9
+ export { HeartbeatTracker, createHeartbeatTracker, getHeartbeatTracker, removeHeartbeatTracker, getAllHeartbeatStatuses, shutdownHeartbeats, extractTaskKeywords, } from "./heartbeat.js";
10
+ export { governedSpawn, } from "./governed-spawn.js";
8
11
  import { ensureDirs, createTask, readTask, readTaskOutput } from "./store.js";
9
12
  import { spawnAgent, cancelAgent } from "./spawn.js";
10
13
  import { recoverTasks, startAgentMonitor, stopAgentMonitor } from "./monitor.js";
14
+ import { shutdownHeartbeats } from "./heartbeat.js";
11
15
  /** Create a task and immediately spawn it. */
12
16
  export async function submitTask(input) {
13
17
  const task = await createTask(input);
@@ -44,8 +48,9 @@ export async function recoverAndStartMonitor() {
44
48
  await recoverTasks();
45
49
  startAgentMonitor();
46
50
  }
47
- /** Shutdown: stop the monitor. Does NOT kill detached processes. */
51
+ /** Shutdown: stop the monitor and heartbeat trackers. Does NOT kill detached processes. */
48
52
  export function shutdownAgents() {
49
53
  stopAgentMonitor();
54
+ shutdownHeartbeats();
50
55
  }
51
56
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,kBAAkB,GAInB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,oBAAoB,GAYrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,GAIpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,iBAAiB,GAQlB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAA6B,cAAc,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,EAAE,UAAU,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEjF,8CAA8C;AAC9C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAsB;IACrD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+BAA+B;AAC/B,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAU;IACtC,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtB,CAAC;AAED,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAU;IAC5C,OAAO,cAAc,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED,6BAA6B;AAC7B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAAU;IACzC,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,UAAU,EAAE,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,MAAM,YAAY,EAAE,CAAC;IACrB,iBAAiB,EAAE,CAAC;AACtB,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,cAAc;IAC5B,gBAAgB,EAAE,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,kBAAkB,GAInB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,oBAAoB,GAYrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,GAIpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,iBAAiB,GAQlB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,yBAAyB,GAI1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,GAKpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,aAAa,GAId,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAA6B,cAAc,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,EAAE,UAAU,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,8CAA8C;AAC9C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAsB;IACrD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+BAA+B;AAC/B,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAU;IACtC,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtB,CAAC;AAED,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAU;IAC5C,OAAO,cAAc,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED,6BAA6B;AAC7B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAAU;IACzC,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,UAAU,EAAE,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,MAAM,YAAY,EAAE,CAAC;IACrB,iBAAiB,EAAE,CAAC;AACtB,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,cAAc;IAC5B,gBAAgB,EAAE,CAAC;IACnB,kBAAkB,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Spawn Policy Loader — governs what agent types can be spawned and how many.
3
+ *
4
+ * Reads brain/templates/spawn-policy.yaml (or instance-specific path).
5
+ * Provides checkSpawnPolicy() for the governance gate to call before spawn.
6
+ *
7
+ * Hand-rolled YAML parser (no external deps).
8
+ */
9
+ export interface AllowedType {
10
+ max: number;
11
+ autoSpawn: boolean;
12
+ }
13
+ export interface SpawnPolicy {
14
+ owner: string;
15
+ governedBy: string;
16
+ maxAgents: number;
17
+ allowedTypes: Map<string, AllowedType>;
18
+ denyTypes: string[];
19
+ requireOwnerApproval: boolean;
20
+ }
21
+ export interface SpawnPolicyCheck {
22
+ allowed: boolean;
23
+ reason?: string;
24
+ }
25
+ /**
26
+ * Load and cache the spawn policy.
27
+ */
28
+ export declare function loadSpawnPolicy(policyPath?: string): Promise<SpawnPolicy>;
29
+ /**
30
+ * Get the cached spawn policy (loads synchronously if not cached).
31
+ */
32
+ export declare function getSpawnPolicy(): SpawnPolicy;
33
+ /**
34
+ * Check whether spawning an agent of the given type is allowed.
35
+ *
36
+ * @param agentType - The agent type to spawn (e.g. "administration", "brand")
37
+ * @param currentCount - Total number of currently running agents
38
+ * @param typeCount - Number of currently running agents of this specific type
39
+ */
40
+ export declare function checkSpawnPolicy(agentType: string, currentCount: number, typeCount: number): SpawnPolicyCheck;
41
+ /**
42
+ * Force reload of spawn policy.
43
+ */
44
+ export declare function reloadSpawnPolicy(policyPath?: string): Promise<SpawnPolicy>;
45
+ //# sourceMappingURL=spawn-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn-policy.d.ts","sourceRoot":"","sources":["../../src/agents/spawn-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmGD;;GAEG;AACH,wBAAsB,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA2B/E;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAsB5C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,gBAAgB,CAyBlB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAGjF"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Spawn Policy Loader — governs what agent types can be spawned and how many.
3
+ *
4
+ * Reads brain/templates/spawn-policy.yaml (or instance-specific path).
5
+ * Provides checkSpawnPolicy() for the governance gate to call before spawn.
6
+ *
7
+ * Hand-rolled YAML parser (no external deps).
8
+ */
9
+ import { readFile } from "node:fs/promises";
10
+ import { readFileSync, existsSync } from "node:fs";
11
+ import { join, resolve } from "node:path";
12
+ import { createLogger } from "../utils/logger.js";
13
+ const log = createLogger("agents.spawn-policy");
14
+ const BRAIN_DIR = resolve(process.cwd(), "brain");
15
+ const DEFAULT_POLICY_PATH = join(BRAIN_DIR, "templates", "spawn-policy.yaml");
16
+ // ── Cache ────────────────────────────────────────────────────────────────────
17
+ let cached = null;
18
+ // ── YAML parser ──────────────────────────────────────────────────────────────
19
+ function parseSpawnPolicy(raw) {
20
+ const lines = raw.split("\n");
21
+ let owner = "";
22
+ let governedBy = "";
23
+ let maxAgents = 4;
24
+ let requireOwnerApproval = true;
25
+ const allowedTypes = new Map();
26
+ const denyTypes = [];
27
+ let section = "root";
28
+ let currentType = "";
29
+ for (const line of lines) {
30
+ const trimmed = line.trimEnd();
31
+ if (!trimmed || trimmed.match(/^\s*#/))
32
+ continue;
33
+ const indent = (line.match(/^(\s*)/) ?? ["", ""])[1].length;
34
+ // Top-level key: value
35
+ if (indent === 0) {
36
+ const kv = trimmed.match(/^(\w[\w_]*)\s*:\s*(.+)$/);
37
+ if (kv) {
38
+ const [, key, val] = kv;
39
+ const unquoted = val.replace(/^["']|["']$/g, "").trim();
40
+ if (key === "owner")
41
+ owner = unquoted;
42
+ else if (key === "governed_by")
43
+ governedBy = unquoted;
44
+ else if (key === "max_agents")
45
+ maxAgents = parseInt(unquoted, 10) || 4;
46
+ else if (key === "require_owner_approval")
47
+ requireOwnerApproval = unquoted === "true";
48
+ section = "root";
49
+ continue;
50
+ }
51
+ // Section header
52
+ const sectionHeader = trimmed.match(/^(\w[\w_]*)\s*:\s*$/);
53
+ if (sectionHeader) {
54
+ if (sectionHeader[1] === "allowed_types")
55
+ section = "allowed_types";
56
+ else if (sectionHeader[1] === "deny_types")
57
+ section = "deny_types";
58
+ else
59
+ section = "root";
60
+ continue;
61
+ }
62
+ }
63
+ // Under allowed_types — type name headers (indent 2)
64
+ if (section === "allowed_types" && indent >= 2) {
65
+ const typeHeader = trimmed.trim().match(/^([\w-]+)\s*:\s*$/);
66
+ if (typeHeader) {
67
+ currentType = typeHeader[1];
68
+ allowedTypes.set(currentType, { max: 1, autoSpawn: false });
69
+ section = "allowed_type_entry";
70
+ continue;
71
+ }
72
+ }
73
+ // Under a specific allowed type entry (indent 4)
74
+ if (section === "allowed_type_entry" && indent >= 4) {
75
+ const kv = trimmed.trim().match(/^(\w[\w_]*)\s*:\s*(.+)$/);
76
+ if (kv) {
77
+ const [, key, val] = kv;
78
+ const entry = allowedTypes.get(currentType);
79
+ if (entry) {
80
+ if (key === "max")
81
+ entry.max = parseInt(val, 10) || 1;
82
+ else if (key === "auto_spawn")
83
+ entry.autoSpawn = val.trim() === "true";
84
+ }
85
+ continue;
86
+ }
87
+ // New type header at indent 2 — go back to allowed_types
88
+ const typeHeader = trimmed.trim().match(/^([\w-]+)\s*:\s*$/);
89
+ if (typeHeader) {
90
+ currentType = typeHeader[1];
91
+ allowedTypes.set(currentType, { max: 1, autoSpawn: false });
92
+ continue;
93
+ }
94
+ }
95
+ // deny_types list items
96
+ if (section === "deny_types") {
97
+ const listItem = trimmed.match(/^\s+-\s+(.+)$/);
98
+ if (listItem) {
99
+ denyTypes.push(listItem[1].replace(/^["']|["']$/g, "").trim());
100
+ }
101
+ }
102
+ }
103
+ return { owner, governedBy, maxAgents, allowedTypes, denyTypes, requireOwnerApproval };
104
+ }
105
+ // ── Public API ───────────────────────────────────────────────────────────────
106
+ /**
107
+ * Load and cache the spawn policy.
108
+ */
109
+ export async function loadSpawnPolicy(policyPath) {
110
+ if (cached)
111
+ return cached;
112
+ const filePath = policyPath ?? DEFAULT_POLICY_PATH;
113
+ try {
114
+ const raw = await readFile(filePath, "utf-8");
115
+ cached = parseSpawnPolicy(raw);
116
+ log.info("Spawn policy loaded", {
117
+ maxAgents: cached.maxAgents,
118
+ allowedTypes: Array.from(cached.allowedTypes.keys()),
119
+ denyTypes: cached.denyTypes,
120
+ });
121
+ }
122
+ catch (err) {
123
+ if (err.code === "ENOENT") {
124
+ log.warn("No spawn-policy.yaml found — using permissive defaults");
125
+ }
126
+ else {
127
+ log.warn("Failed to parse spawn-policy.yaml", { error: err.message });
128
+ }
129
+ cached = {
130
+ owner: "",
131
+ governedBy: "",
132
+ maxAgents: 4,
133
+ allowedTypes: new Map(),
134
+ denyTypes: [],
135
+ requireOwnerApproval: false,
136
+ };
137
+ }
138
+ return cached;
139
+ }
140
+ /**
141
+ * Get the cached spawn policy (loads synchronously if not cached).
142
+ */
143
+ export function getSpawnPolicy() {
144
+ if (!cached) {
145
+ try {
146
+ if (existsSync(DEFAULT_POLICY_PATH)) {
147
+ const raw = readFileSync(DEFAULT_POLICY_PATH, "utf-8");
148
+ cached = parseSpawnPolicy(raw);
149
+ }
150
+ }
151
+ catch {
152
+ // Fall through to defaults
153
+ }
154
+ if (!cached) {
155
+ cached = {
156
+ owner: "",
157
+ governedBy: "",
158
+ maxAgents: 4,
159
+ allowedTypes: new Map(),
160
+ denyTypes: [],
161
+ requireOwnerApproval: false,
162
+ };
163
+ }
164
+ }
165
+ return cached;
166
+ }
167
+ /**
168
+ * Check whether spawning an agent of the given type is allowed.
169
+ *
170
+ * @param agentType - The agent type to spawn (e.g. "administration", "brand")
171
+ * @param currentCount - Total number of currently running agents
172
+ * @param typeCount - Number of currently running agents of this specific type
173
+ */
174
+ export function checkSpawnPolicy(agentType, currentCount, typeCount) {
175
+ const policy = getSpawnPolicy();
176
+ // Check deny list
177
+ if (policy.denyTypes.includes(agentType)) {
178
+ return { allowed: false, reason: `Agent type "${agentType}" is denied by spawn policy` };
179
+ }
180
+ // Check global max
181
+ if (currentCount >= policy.maxAgents) {
182
+ return { allowed: false, reason: `Max agents reached (${policy.maxAgents})` };
183
+ }
184
+ // Check type-specific max
185
+ const typeConfig = policy.allowedTypes.get(agentType);
186
+ if (typeConfig && typeCount >= typeConfig.max) {
187
+ return { allowed: false, reason: `Max "${agentType}" agents reached (${typeConfig.max})` };
188
+ }
189
+ // If the type isn't in allowed_types and the map is non-empty, it's implicitly denied
190
+ if (policy.allowedTypes.size > 0 && !typeConfig) {
191
+ return { allowed: false, reason: `Agent type "${agentType}" is not in allowed_types` };
192
+ }
193
+ return { allowed: true };
194
+ }
195
+ /**
196
+ * Force reload of spawn policy.
197
+ */
198
+ export async function reloadSpawnPolicy(policyPath) {
199
+ cached = null;
200
+ return loadSpawnPolicy(policyPath);
201
+ }
202
+ //# sourceMappingURL=spawn-policy.js.map