@runcore-sh/runcore 0.1.8 → 0.1.9
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/dist/access/manifest.d.ts +59 -0
- package/dist/access/manifest.d.ts.map +1 -0
- package/dist/access/manifest.js +251 -0
- package/dist/access/manifest.js.map +1 -0
- package/dist/activity/log.d.ts +1 -1
- package/dist/activity/log.d.ts.map +1 -1
- package/dist/agents/autonomous.d.ts.map +1 -1
- package/dist/agents/autonomous.js +38 -0
- package/dist/agents/autonomous.js.map +1 -1
- package/dist/agents/governance.d.ts +70 -0
- package/dist/agents/governance.d.ts.map +1 -0
- package/dist/agents/governance.js +220 -0
- package/dist/agents/governance.js.map +1 -0
- package/dist/agents/governed-spawn.d.ts +83 -0
- package/dist/agents/governed-spawn.d.ts.map +1 -0
- package/dist/agents/governed-spawn.js +186 -0
- package/dist/agents/governed-spawn.js.map +1 -0
- package/dist/agents/heartbeat.d.ts +91 -0
- package/dist/agents/heartbeat.d.ts.map +1 -0
- package/dist/agents/heartbeat.js +323 -0
- package/dist/agents/heartbeat.js.map +1 -0
- package/dist/agents/index.d.ts +4 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +6 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/spawn-policy.d.ts +45 -0
- package/dist/agents/spawn-policy.d.ts.map +1 -0
- package/dist/agents/spawn-policy.js +202 -0
- package/dist/agents/spawn-policy.js.map +1 -0
- package/dist/alert.d.ts +16 -0
- package/dist/alert.d.ts.map +1 -0
- package/dist/alert.js +70 -0
- package/dist/alert.js.map +1 -0
- package/dist/cli.js +35 -27
- package/dist/cli.js.map +1 -1
- package/dist/credentials/store.d.ts +1 -1
- package/dist/credentials/store.d.ts.map +1 -1
- package/dist/credentials/store.js +14 -3
- package/dist/credentials/store.js.map +1 -1
- package/dist/crystallizer.d.ts +56 -0
- package/dist/crystallizer.d.ts.map +1 -0
- package/dist/crystallizer.js +159 -0
- package/dist/crystallizer.js.map +1 -0
- package/dist/distiller.d.ts +48 -0
- package/dist/distiller.d.ts.map +1 -0
- package/dist/distiller.js +140 -0
- package/dist/distiller.js.map +1 -0
- package/dist/google/auth.d.ts +2 -0
- package/dist/google/auth.d.ts.map +1 -1
- package/dist/google/auth.js +2 -0
- package/dist/google/auth.js.map +1 -1
- package/dist/integrations/gate.d.ts +40 -0
- package/dist/integrations/gate.d.ts.map +1 -0
- package/dist/integrations/gate.js +100 -0
- package/dist/integrations/gate.js.map +1 -0
- package/dist/lib/audit.d.ts +43 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +120 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/brain-io.d.ts.map +1 -1
- package/dist/lib/brain-io.js +52 -0
- package/dist/lib/brain-io.js.map +1 -1
- package/dist/lib/dpapi.d.ts +14 -0
- package/dist/lib/dpapi.d.ts.map +1 -0
- package/dist/lib/dpapi.js +104 -0
- package/dist/lib/dpapi.js.map +1 -0
- package/dist/lib/glob-match.d.ts +22 -0
- package/dist/lib/glob-match.d.ts.map +1 -0
- package/dist/lib/glob-match.js +64 -0
- package/dist/lib/glob-match.js.map +1 -0
- package/dist/lib/locked.d.ts +40 -0
- package/dist/lib/locked.d.ts.map +1 -0
- package/dist/lib/locked.js +130 -0
- package/dist/lib/locked.js.map +1 -0
- package/dist/llm/complete.d.ts.map +1 -1
- package/dist/llm/complete.js +5 -2
- package/dist/llm/complete.js.map +1 -1
- package/dist/llm/fetch-guard.d.ts +16 -0
- package/dist/llm/fetch-guard.d.ts.map +1 -0
- package/dist/llm/fetch-guard.js +61 -0
- package/dist/llm/fetch-guard.js.map +1 -0
- package/dist/llm/guard.d.ts +40 -0
- package/dist/llm/guard.d.ts.map +1 -0
- package/dist/llm/guard.js +88 -0
- package/dist/llm/guard.js.map +1 -0
- package/dist/llm/membrane.d.ts +46 -0
- package/dist/llm/membrane.d.ts.map +1 -0
- package/dist/llm/membrane.js +123 -0
- package/dist/llm/membrane.js.map +1 -0
- package/dist/llm/providers/index.d.ts +5 -1
- package/dist/llm/providers/index.d.ts.map +1 -1
- package/dist/llm/providers/index.js +8 -1
- package/dist/llm/providers/index.js.map +1 -1
- package/dist/llm/redact.d.ts +39 -0
- package/dist/llm/redact.d.ts.map +1 -0
- package/dist/llm/redact.js +155 -0
- package/dist/llm/redact.js.map +1 -0
- package/dist/llm/sensitive-registry.d.ts +33 -0
- package/dist/llm/sensitive-registry.d.ts.map +1 -0
- package/dist/llm/sensitive-registry.js +106 -0
- package/dist/llm/sensitive-registry.js.map +1 -0
- package/dist/mcp-server.d.ts +11 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +520 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mdns.d.ts +17 -0
- package/dist/mdns.d.ts.map +1 -0
- package/dist/mdns.js +110 -0
- package/dist/mdns.js.map +1 -0
- package/dist/nerve/push.d.ts +26 -0
- package/dist/nerve/push.d.ts.map +1 -0
- package/dist/nerve/push.js +170 -0
- package/dist/nerve/push.js.map +1 -0
- package/dist/nerve/state.d.ts +35 -0
- package/dist/nerve/state.d.ts.map +1 -0
- package/dist/nerve/state.js +257 -0
- package/dist/nerve/state.js.map +1 -0
- package/dist/resend/inbox.d.ts +23 -0
- package/dist/resend/inbox.d.ts.map +1 -0
- package/dist/resend/inbox.js +198 -0
- package/dist/resend/inbox.js.map +1 -0
- package/dist/resend/webhooks.d.ts +30 -0
- package/dist/resend/webhooks.d.ts.map +1 -0
- package/dist/resend/webhooks.js +244 -0
- package/dist/resend/webhooks.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +585 -16
- package/dist/server.js.map +1 -1
- package/dist/settings.d.ts +14 -1
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +32 -1
- package/dist/settings.js.map +1 -1
- package/dist/updater.d.ts +32 -0
- package/dist/updater.d.ts.map +1 -0
- package/dist/updater.js +145 -0
- package/dist/updater.js.map +1 -0
- package/dist/vault/policy.d.ts +42 -0
- package/dist/vault/policy.d.ts.map +1 -0
- package/dist/vault/policy.js +159 -0
- package/dist/vault/policy.js.map +1 -0
- package/dist/vault/store.d.ts +6 -0
- package/dist/vault/store.d.ts.map +1 -1
- package/dist/vault/store.js +15 -5
- package/dist/vault/store.js.map +1 -1
- package/dist/vault/transfer.d.ts +33 -0
- package/dist/vault/transfer.d.ts.map +1 -0
- package/dist/vault/transfer.js +187 -0
- package/dist/vault/transfer.js.map +1 -0
- package/dist/voucher.d.ts +39 -0
- package/dist/voucher.d.ts.map +1 -0
- package/dist/voucher.js +105 -0
- package/dist/voucher.js.map +1 -0
- package/dist/webhooks/handlers.d.ts +10 -0
- package/dist/webhooks/handlers.d.ts.map +1 -1
- package/dist/webhooks/handlers.js +53 -0
- package/dist/webhooks/handlers.js.map +1 -1
- package/dist/webhooks/index.d.ts +2 -2
- package/dist/webhooks/index.d.ts.map +1 -1
- package/dist/webhooks/index.js +2 -2
- package/dist/webhooks/index.js.map +1 -1
- package/dist/webhooks/verify.d.ts +8 -0
- package/dist/webhooks/verify.d.ts.map +1 -1
- package/dist/webhooks/verify.js +56 -0
- package/dist/webhooks/verify.js.map +1 -1
- package/package.json +8 -2
- package/public/board.html +8 -3
- package/public/browser.html +8 -3
- package/public/library.html +8 -3
- package/public/observatory.html +8 -3
- package/public/ops.html +8 -3
- package/public/registry.html +627 -0
- package/public/roadmap.html +975 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Governance Gate — CORE-9
|
|
3
|
+
*
|
|
4
|
+
* Pre-spawn validation that replaces the `--dangerously-skip-permissions`
|
|
5
|
+
* prompt with voucher-based authorization, locked-path enforcement, and
|
|
6
|
+
* principle injection.
|
|
7
|
+
*
|
|
8
|
+
* Every governed spawn:
|
|
9
|
+
* 1. Issues a scoped voucher for the task
|
|
10
|
+
* 2. Reads locked paths and builds a deny-list for the agent's prompt
|
|
11
|
+
* 3. Injects core principles as behavioral constraints
|
|
12
|
+
* 4. Wraps the prompt with governance preamble
|
|
13
|
+
* 5. Logs the governance decision to the audit trail
|
|
14
|
+
*/
|
|
15
|
+
import { readFile } from "node:fs/promises";
|
|
16
|
+
import { join, resolve } from "node:path";
|
|
17
|
+
import { issueVoucher, checkVoucher, revokeVoucher } from "../voucher.js";
|
|
18
|
+
import { loadLockedPaths } from "../lib/locked.js";
|
|
19
|
+
import { checkSpawnPolicy, loadSpawnPolicy } from "./spawn-policy.js";
|
|
20
|
+
import { logActivity } from "../activity/log.js";
|
|
21
|
+
import { createLogger } from "../utils/logger.js";
|
|
22
|
+
const log = createLogger("governance");
|
|
23
|
+
const BRAIN_DIR = resolve(process.cwd(), "brain");
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Governance preamble components
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
function buildLockedPathsSection(paths) {
|
|
28
|
+
if (paths.length === 0)
|
|
29
|
+
return "";
|
|
30
|
+
const pathList = paths.map((p) => ` - brain/${p}`).join("\n");
|
|
31
|
+
return `
|
|
32
|
+
## Locked Paths (DO NOT ACCESS)
|
|
33
|
+
The following paths are locked by governance policy. Do NOT read, write, or
|
|
34
|
+
reference these files. Violations will be logged and may terminate your session.
|
|
35
|
+
|
|
36
|
+
${pathList}
|
|
37
|
+
`;
|
|
38
|
+
}
|
|
39
|
+
function buildVoucherSection(token, scope) {
|
|
40
|
+
return `
|
|
41
|
+
## Governance Voucher
|
|
42
|
+
You are operating under voucher \`${token}\` with scope \`${scope}\`.
|
|
43
|
+
This voucher is time-limited. If you receive a governance violation, stop immediately.
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
async function loadPrinciples() {
|
|
47
|
+
try {
|
|
48
|
+
const principlesPath = join(BRAIN_DIR, "identity", "principles.md");
|
|
49
|
+
const content = await readFile(principlesPath, "utf-8");
|
|
50
|
+
// Extract just the key principles, not the full document
|
|
51
|
+
const lines = content.split("\n");
|
|
52
|
+
const keyPrinciples = [];
|
|
53
|
+
for (const line of lines) {
|
|
54
|
+
if (line.startsWith("**") && line.endsWith("**")) {
|
|
55
|
+
keyPrinciples.push(line);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (keyPrinciples.length === 0)
|
|
59
|
+
return "";
|
|
60
|
+
return `
|
|
61
|
+
## Operating Principles
|
|
62
|
+
You must adhere to these principles during execution:
|
|
63
|
+
${keyPrinciples.map((p) => `- ${p}`).join("\n")}
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
log.warn("Could not load principles — proceeding without them");
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Main governance gate
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
/**
|
|
75
|
+
* Run the governance gate before spawning an agent.
|
|
76
|
+
* Returns a GovernanceDecision with the governed prompt (or denial).
|
|
77
|
+
*/
|
|
78
|
+
export async function governanceGate(opts) {
|
|
79
|
+
const { taskId, label, prompt, origin, ltm, scope: scopeOverride, voucherTtlMinutes = 30, skipVoucher = false, } = opts;
|
|
80
|
+
const scope = scopeOverride ?? `agent:spawn:${taskId}`;
|
|
81
|
+
const timestamp = new Date().toISOString();
|
|
82
|
+
// 1. Load locked paths
|
|
83
|
+
const lockedPaths = await loadLockedPaths();
|
|
84
|
+
// 1b. Spawn policy check (if agentType provided)
|
|
85
|
+
if (opts.agentType) {
|
|
86
|
+
await loadSpawnPolicy();
|
|
87
|
+
const spawnCheck = checkSpawnPolicy(opts.agentType, opts.currentAgentCount ?? 0, opts.currentTypeCount ?? 0);
|
|
88
|
+
if (!spawnCheck.allowed) {
|
|
89
|
+
const reason = `Spawn policy denied: ${spawnCheck.reason}`;
|
|
90
|
+
log.warn(reason, { taskId, agentType: opts.agentType });
|
|
91
|
+
const auditEntry = {
|
|
92
|
+
timestamp,
|
|
93
|
+
taskId,
|
|
94
|
+
label,
|
|
95
|
+
decision: "deny",
|
|
96
|
+
lockedPathCount: lockedPaths.length,
|
|
97
|
+
reason,
|
|
98
|
+
};
|
|
99
|
+
logActivity({
|
|
100
|
+
source: "agent",
|
|
101
|
+
summary: `Governance DENIED (spawn policy): ${label}`,
|
|
102
|
+
detail: reason,
|
|
103
|
+
actionLabel: origin === "ai" ? "AUTONOMOUS" : "PROMPTED",
|
|
104
|
+
reason: "governance-gate",
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
allowed: false,
|
|
108
|
+
deniedReason: reason,
|
|
109
|
+
governedPrompt: prompt,
|
|
110
|
+
lockedPaths,
|
|
111
|
+
auditEntry,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 2. Issue voucher (unless skipped for system tasks)
|
|
116
|
+
let voucherToken;
|
|
117
|
+
if (!skipVoucher) {
|
|
118
|
+
try {
|
|
119
|
+
voucherToken = await issueVoucher(ltm, scope, voucherTtlMinutes);
|
|
120
|
+
log.info("Voucher issued for agent", { taskId, token: voucherToken, scope });
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
const reason = `Voucher issuance failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
124
|
+
log.error(reason, { taskId });
|
|
125
|
+
const auditEntry = {
|
|
126
|
+
timestamp,
|
|
127
|
+
taskId,
|
|
128
|
+
label,
|
|
129
|
+
decision: "deny",
|
|
130
|
+
lockedPathCount: lockedPaths.length,
|
|
131
|
+
reason,
|
|
132
|
+
};
|
|
133
|
+
logActivity({
|
|
134
|
+
source: "agent",
|
|
135
|
+
summary: `Governance DENIED: ${label}`,
|
|
136
|
+
detail: reason,
|
|
137
|
+
actionLabel: origin === "ai" ? "AUTONOMOUS" : "PROMPTED",
|
|
138
|
+
reason: "governance-gate",
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
allowed: false,
|
|
142
|
+
deniedReason: reason,
|
|
143
|
+
governedPrompt: prompt,
|
|
144
|
+
lockedPaths,
|
|
145
|
+
auditEntry,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// 3. Load principles
|
|
150
|
+
const principlesSection = await loadPrinciples();
|
|
151
|
+
// 4. Build governed prompt
|
|
152
|
+
const governancePreamble = [
|
|
153
|
+
"## Governance Context",
|
|
154
|
+
"This agent session is governed by the Core orchestration system.",
|
|
155
|
+
"You are running with `--dangerously-skip-permissions`. In exchange,",
|
|
156
|
+
"governance controls replace the permission prompt. Violating these",
|
|
157
|
+
"controls will terminate your session.",
|
|
158
|
+
"",
|
|
159
|
+
voucherToken ? buildVoucherSection(voucherToken, scope) : "",
|
|
160
|
+
buildLockedPathsSection(lockedPaths),
|
|
161
|
+
principlesSection,
|
|
162
|
+
"## Heartbeat Requirement",
|
|
163
|
+
"Your actions are monitored. Extended silence (no file writes, no output)",
|
|
164
|
+
"will trigger a timeout and termination. Stay on task.",
|
|
165
|
+
"",
|
|
166
|
+
"---",
|
|
167
|
+
"",
|
|
168
|
+
]
|
|
169
|
+
.filter(Boolean)
|
|
170
|
+
.join("\n");
|
|
171
|
+
const governedPrompt = governancePreamble + prompt;
|
|
172
|
+
// 5. Log the decision
|
|
173
|
+
const auditEntry = {
|
|
174
|
+
timestamp,
|
|
175
|
+
taskId,
|
|
176
|
+
label,
|
|
177
|
+
decision: "allow",
|
|
178
|
+
voucherToken,
|
|
179
|
+
voucherScope: scope,
|
|
180
|
+
lockedPathCount: lockedPaths.length,
|
|
181
|
+
};
|
|
182
|
+
logActivity({
|
|
183
|
+
source: "agent",
|
|
184
|
+
summary: `Governance ALLOWED: ${label}`,
|
|
185
|
+
detail: `Voucher: ${voucherToken ?? "skipped"}, locked paths: ${lockedPaths.length}`,
|
|
186
|
+
actionLabel: origin === "ai" ? "AUTONOMOUS" : "PROMPTED",
|
|
187
|
+
reason: "governance-gate",
|
|
188
|
+
});
|
|
189
|
+
log.info("Governance gate passed", { taskId, label, voucherToken });
|
|
190
|
+
return {
|
|
191
|
+
allowed: true,
|
|
192
|
+
voucherToken,
|
|
193
|
+
governedPrompt,
|
|
194
|
+
lockedPaths,
|
|
195
|
+
auditEntry,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Revoke a governance voucher (call on agent completion or termination).
|
|
200
|
+
*/
|
|
201
|
+
export async function revokeGovernanceVoucher(ltm, token) {
|
|
202
|
+
try {
|
|
203
|
+
await revokeVoucher(ltm, token);
|
|
204
|
+
log.info("Governance voucher revoked", { token });
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
log.warn("Failed to revoke voucher", {
|
|
208
|
+
token,
|
|
209
|
+
error: err instanceof Error ? err.message : String(err),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Validate that a voucher is still active (for mid-session checks).
|
|
215
|
+
*/
|
|
216
|
+
export async function validateGovernanceVoucher(ltm, token) {
|
|
217
|
+
const result = await checkVoucher(ltm, token);
|
|
218
|
+
return result.valid;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=governance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governance.js","sourceRoot":"","sources":["../../src/agents/governance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAkB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;AAEvC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;AAkDlD,8EAA8E;AAC9E,iCAAiC;AACjC,8EAA8E;AAE9E,SAAS,uBAAuB,CAAC,KAAe;IAC9C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,OAAO;;;;;EAKP,QAAQ;CACT,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa,EAAE,KAAa;IACvD,OAAO;;oCAE2B,KAAK,mBAAmB,KAAK;;CAEhE,CAAC;AACF,CAAC;AAED,KAAK,UAAU,cAAc;IAC3B,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QACxD,yDAAyD;QACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjD,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAC1C,OAAO;;;EAGT,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CAC9C,CAAC;IACA,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;QAChE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAuB;IAEvB,MAAM,EACJ,MAAM,EACN,KAAK,EACL,MAAM,EACN,MAAM,EACN,GAAG,EACH,KAAK,EAAE,aAAa,EACpB,iBAAiB,GAAG,EAAE,EACtB,WAAW,GAAG,KAAK,GACpB,GAAG,IAAI,CAAC;IAET,MAAM,KAAK,GAAG,aAAa,IAAI,eAAe,MAAM,EAAE,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3C,uBAAuB;IACvB,MAAM,WAAW,GAAG,MAAM,eAAe,EAAE,CAAC;IAE5C,iDAAiD;IACjD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,eAAe,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,gBAAgB,CACjC,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,iBAAiB,IAAI,CAAC,EAC3B,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAC3B,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,wBAAwB,UAAU,CAAC,MAAM,EAAE,CAAC;YAC3D,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAExD,MAAM,UAAU,GAAyB;gBACvC,SAAS;gBACT,MAAM;gBACN,KAAK;gBACL,QAAQ,EAAE,MAAM;gBAChB,eAAe,EAAE,WAAW,CAAC,MAAM;gBACnC,MAAM;aACP,CAAC;YAEF,WAAW,CAAC;gBACV,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,qCAAqC,KAAK,EAAE;gBACrD,MAAM,EAAE,MAAM;gBACd,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU;gBACxD,MAAM,EAAE,iBAAiB;aAC1B,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,MAAM;gBACpB,cAAc,EAAE,MAAM;gBACtB,WAAW;gBACX,UAAU;aACX,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,IAAI,YAAgC,CAAC;IACrC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,YAAY,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;YACjE,GAAG,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,4BAA4B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9F,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAE9B,MAAM,UAAU,GAAyB;gBACvC,SAAS;gBACT,MAAM;gBACN,KAAK;gBACL,QAAQ,EAAE,MAAM;gBAChB,eAAe,EAAE,WAAW,CAAC,MAAM;gBACnC,MAAM;aACP,CAAC;YAEF,WAAW,CAAC;gBACV,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,sBAAsB,KAAK,EAAE;gBACtC,MAAM,EAAE,MAAM;gBACd,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU;gBACxD,MAAM,EAAE,iBAAiB;aAC1B,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,MAAM;gBACpB,cAAc,EAAE,MAAM;gBACtB,WAAW;gBACX,UAAU;aACX,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,MAAM,iBAAiB,GAAG,MAAM,cAAc,EAAE,CAAC;IAEjD,2BAA2B;IAC3B,MAAM,kBAAkB,GAAG;QACzB,uBAAuB;QACvB,kEAAkE;QAClE,qEAAqE;QACrE,oEAAoE;QACpE,uCAAuC;QACvC,EAAE;QACF,YAAY,CAAC,CAAC,CAAC,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;QAC5D,uBAAuB,CAAC,WAAW,CAAC;QACpC,iBAAiB;QACjB,0BAA0B;QAC1B,0EAA0E;QAC1E,uDAAuD;QACvD,EAAE;QACF,KAAK;QACL,EAAE;KACH;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,cAAc,GAAG,kBAAkB,GAAG,MAAM,CAAC;IAEnD,sBAAsB;IACtB,MAAM,UAAU,GAAyB;QACvC,SAAS;QACT,MAAM;QACN,KAAK;QACL,QAAQ,EAAE,OAAO;QACjB,YAAY;QACZ,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,WAAW,CAAC,MAAM;KACpC,CAAC;IAEF,WAAW,CAAC;QACV,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,uBAAuB,KAAK,EAAE;QACvC,MAAM,EAAE,YAAY,YAAY,IAAI,SAAS,mBAAmB,WAAW,CAAC,MAAM,EAAE;QACpF,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU;QACxD,MAAM,EAAE,iBAAiB;KAC1B,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;IAEpE,OAAO;QACL,OAAO,EAAE,IAAI;QACb,YAAY;QACZ,cAAc;QACd,WAAW;QACX,UAAU;KACX,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,GAAwB,EACxB,KAAa;IAEb,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,0BAA0B,EAAE;YACnC,KAAK;YACL,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,GAAwB,EACxB,KAAa;IAEb,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governed Agent Spawn — CORE-9
|
|
3
|
+
*
|
|
4
|
+
* High-level entry point for spawning Claude Code agents with full
|
|
5
|
+
* governance controls. Composes:
|
|
6
|
+
*
|
|
7
|
+
* 1. Governance gate (voucher + locked paths + principles)
|
|
8
|
+
* 2. Agent spawning (via existing pool or direct spawn)
|
|
9
|
+
* 3. Heartbeat monitoring (silence + drift detection)
|
|
10
|
+
* 4. Lifecycle management (cleanup on completion/termination)
|
|
11
|
+
*
|
|
12
|
+
* This replaces raw `--dangerously-skip-permissions` with a governed
|
|
13
|
+
* equivalent where vouchers, locked paths, and principles replace the
|
|
14
|
+
* interactive permission prompt.
|
|
15
|
+
*/
|
|
16
|
+
import type { LongTermMemoryStore } from "../memory/long-term.js";
|
|
17
|
+
import type { AgentPool } from "./runtime.js";
|
|
18
|
+
import type { AgentInstance } from "./runtime/types.js";
|
|
19
|
+
import { type GovernanceDecision } from "./governance.js";
|
|
20
|
+
import { type HeartbeatConfig, type HeartbeatTracker } from "./heartbeat.js";
|
|
21
|
+
/** Input for a governed agent spawn. */
|
|
22
|
+
export interface GovernedSpawnRequest {
|
|
23
|
+
/** Task identifier (should be unique). */
|
|
24
|
+
taskId: string;
|
|
25
|
+
/** Human-readable label. */
|
|
26
|
+
label: string;
|
|
27
|
+
/** The actual task prompt. */
|
|
28
|
+
prompt: string;
|
|
29
|
+
/** Working directory for the agent. */
|
|
30
|
+
cwd?: string;
|
|
31
|
+
/** Who initiated the spawn. */
|
|
32
|
+
origin: "user" | "ai" | "system";
|
|
33
|
+
/** Tags for grouping/filtering. */
|
|
34
|
+
tags?: string[];
|
|
35
|
+
/** Parent agent ID (for sub-agent spawns). */
|
|
36
|
+
parentId?: string;
|
|
37
|
+
/** Override heartbeat config. */
|
|
38
|
+
heartbeat?: Partial<HeartbeatConfig>;
|
|
39
|
+
/** Override voucher TTL (minutes). */
|
|
40
|
+
voucherTtlMinutes?: number;
|
|
41
|
+
/** Skip voucher for system-level tasks. */
|
|
42
|
+
skipVoucher?: boolean;
|
|
43
|
+
/** Agent type for spawn policy checks (e.g. "administration", "brand"). */
|
|
44
|
+
agentType?: string;
|
|
45
|
+
/** Current total running agent count (for spawn policy max check). */
|
|
46
|
+
currentAgentCount?: number;
|
|
47
|
+
/** Current running count of this specific agent type. */
|
|
48
|
+
currentTypeCount?: number;
|
|
49
|
+
}
|
|
50
|
+
/** Result of a governed spawn — includes governance metadata. */
|
|
51
|
+
export interface GovernedSpawnResult {
|
|
52
|
+
/** Whether the spawn was allowed and succeeded. */
|
|
53
|
+
success: boolean;
|
|
54
|
+
/** The spawned agent instance (if successful). */
|
|
55
|
+
instance?: AgentInstance;
|
|
56
|
+
/** Governance decision details. */
|
|
57
|
+
governance: GovernanceDecision;
|
|
58
|
+
/** Heartbeat tracker (if spawn succeeded). */
|
|
59
|
+
heartbeat?: HeartbeatTracker;
|
|
60
|
+
/** Trace ID linking all activity for this spawn. */
|
|
61
|
+
traceId: string;
|
|
62
|
+
/** Denial reason (if not allowed). */
|
|
63
|
+
deniedReason?: string;
|
|
64
|
+
}
|
|
65
|
+
/** Dependencies injected into the governed spawn system. */
|
|
66
|
+
export interface GovernedSpawnDeps {
|
|
67
|
+
/** Long-term memory store for voucher operations. */
|
|
68
|
+
ltm: LongTermMemoryStore;
|
|
69
|
+
/** Agent pool for spawning (preferred). */
|
|
70
|
+
pool?: AgentPool;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Spawn a Claude Code agent with full governance controls.
|
|
74
|
+
*
|
|
75
|
+
* Flow:
|
|
76
|
+
* 1. Run governance gate (voucher + locked paths + principles)
|
|
77
|
+
* 2. If denied → return failure with reason
|
|
78
|
+
* 3. Spawn agent via pool with governed prompt
|
|
79
|
+
* 4. Attach heartbeat tracker
|
|
80
|
+
* 5. Wire lifecycle cleanup (voucher revocation on exit)
|
|
81
|
+
*/
|
|
82
|
+
export declare function governedSpawn(request: GovernedSpawnRequest, deps: GovernedSpawnDeps): Promise<GovernedSpawnResult>;
|
|
83
|
+
//# sourceMappingURL=governed-spawn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governed-spawn.d.ts","sourceRoot":"","sources":["../../src/agents/governed-spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAIL,KAAK,kBAAkB,EAExB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAUxB,wCAAwC;AACxC,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC;IACjC,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACrC,sCAAsC;IACtC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2CAA2C;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,mCAAmC;IACnC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,8CAA8C;IAC9C,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,GAAG,EAAE,mBAAmB,CAAC;IACzB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAMD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,EAC7B,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,mBAAmB,CAAC,CA+K9B"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governed Agent Spawn — CORE-9
|
|
3
|
+
*
|
|
4
|
+
* High-level entry point for spawning Claude Code agents with full
|
|
5
|
+
* governance controls. Composes:
|
|
6
|
+
*
|
|
7
|
+
* 1. Governance gate (voucher + locked paths + principles)
|
|
8
|
+
* 2. Agent spawning (via existing pool or direct spawn)
|
|
9
|
+
* 3. Heartbeat monitoring (silence + drift detection)
|
|
10
|
+
* 4. Lifecycle management (cleanup on completion/termination)
|
|
11
|
+
*
|
|
12
|
+
* This replaces raw `--dangerously-skip-permissions` with a governed
|
|
13
|
+
* equivalent where vouchers, locked paths, and principles replace the
|
|
14
|
+
* interactive permission prompt.
|
|
15
|
+
*/
|
|
16
|
+
import { governanceGate, revokeGovernanceVoucher, } from "./governance.js";
|
|
17
|
+
import { createHeartbeatTracker, removeHeartbeatTracker, extractTaskKeywords, } from "./heartbeat.js";
|
|
18
|
+
import { logActivity, generateTraceId } from "../activity/log.js";
|
|
19
|
+
import { createLogger } from "../utils/logger.js";
|
|
20
|
+
const log = createLogger("governed-spawn");
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Governed spawn
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/**
|
|
25
|
+
* Spawn a Claude Code agent with full governance controls.
|
|
26
|
+
*
|
|
27
|
+
* Flow:
|
|
28
|
+
* 1. Run governance gate (voucher + locked paths + principles)
|
|
29
|
+
* 2. If denied → return failure with reason
|
|
30
|
+
* 3. Spawn agent via pool with governed prompt
|
|
31
|
+
* 4. Attach heartbeat tracker
|
|
32
|
+
* 5. Wire lifecycle cleanup (voucher revocation on exit)
|
|
33
|
+
*/
|
|
34
|
+
export async function governedSpawn(request, deps) {
|
|
35
|
+
const traceId = generateTraceId();
|
|
36
|
+
const { ltm, pool } = deps;
|
|
37
|
+
log.info("Governed spawn requested", {
|
|
38
|
+
taskId: request.taskId,
|
|
39
|
+
label: request.label,
|
|
40
|
+
origin: request.origin,
|
|
41
|
+
traceId,
|
|
42
|
+
});
|
|
43
|
+
// 1. Run governance gate
|
|
44
|
+
const govOpts = {
|
|
45
|
+
taskId: request.taskId,
|
|
46
|
+
label: request.label,
|
|
47
|
+
prompt: request.prompt,
|
|
48
|
+
origin: request.origin,
|
|
49
|
+
ltm,
|
|
50
|
+
voucherTtlMinutes: request.voucherTtlMinutes,
|
|
51
|
+
skipVoucher: request.skipVoucher,
|
|
52
|
+
agentType: request.agentType,
|
|
53
|
+
currentAgentCount: request.currentAgentCount,
|
|
54
|
+
currentTypeCount: request.currentTypeCount,
|
|
55
|
+
};
|
|
56
|
+
const governance = await governanceGate(govOpts);
|
|
57
|
+
// 2. Check governance decision
|
|
58
|
+
if (!governance.allowed) {
|
|
59
|
+
log.warn("Governed spawn denied", {
|
|
60
|
+
taskId: request.taskId,
|
|
61
|
+
reason: governance.deniedReason,
|
|
62
|
+
traceId,
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
governance,
|
|
67
|
+
traceId,
|
|
68
|
+
deniedReason: governance.deniedReason,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// 3. Spawn agent via pool
|
|
72
|
+
if (!pool) {
|
|
73
|
+
const reason = "No agent pool available — cannot spawn governed agent";
|
|
74
|
+
log.error(reason, { taskId: request.taskId });
|
|
75
|
+
// Revoke the voucher since we can't use it
|
|
76
|
+
if (governance.voucherToken) {
|
|
77
|
+
await revokeGovernanceVoucher(ltm, governance.voucherToken);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
governance,
|
|
82
|
+
traceId,
|
|
83
|
+
deniedReason: reason,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
let instance;
|
|
87
|
+
try {
|
|
88
|
+
const spawnRequest = {
|
|
89
|
+
taskId: request.taskId,
|
|
90
|
+
label: request.label,
|
|
91
|
+
prompt: governance.governedPrompt,
|
|
92
|
+
cwd: request.cwd,
|
|
93
|
+
origin: request.origin,
|
|
94
|
+
tags: [
|
|
95
|
+
...(request.tags ?? []),
|
|
96
|
+
"governed",
|
|
97
|
+
governance.voucherToken ? `voucher:${governance.voucherToken}` : "voucher:none",
|
|
98
|
+
],
|
|
99
|
+
parentId: request.parentId,
|
|
100
|
+
};
|
|
101
|
+
instance = await pool.spawn(spawnRequest);
|
|
102
|
+
logActivity({
|
|
103
|
+
source: "agent",
|
|
104
|
+
summary: `Governed agent spawned: ${request.label}`,
|
|
105
|
+
detail: `Instance: ${instance.id}, PID: ${instance.pid}, voucher: ${governance.voucherToken ?? "none"}`,
|
|
106
|
+
traceId,
|
|
107
|
+
actionLabel: request.origin === "ai" ? "AUTONOMOUS" : "PROMPTED",
|
|
108
|
+
reason: "governed-spawn",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
const reason = `Spawn failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
113
|
+
log.error(reason, { taskId: request.taskId, traceId });
|
|
114
|
+
// Revoke voucher on spawn failure
|
|
115
|
+
if (governance.voucherToken) {
|
|
116
|
+
await revokeGovernanceVoucher(ltm, governance.voucherToken);
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
governance,
|
|
121
|
+
traceId,
|
|
122
|
+
deniedReason: reason,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// 4. Attach heartbeat tracker
|
|
126
|
+
const taskKeywords = extractTaskKeywords(request.prompt);
|
|
127
|
+
const heartbeat = createHeartbeatTracker(request.taskId, instance.id, {
|
|
128
|
+
taskDescription: request.prompt,
|
|
129
|
+
taskKeywords,
|
|
130
|
+
...request.heartbeat,
|
|
131
|
+
}, async (instanceId, reason) => {
|
|
132
|
+
// Termination callback from heartbeat
|
|
133
|
+
log.warn("Heartbeat triggered termination", { instanceId, reason, traceId });
|
|
134
|
+
try {
|
|
135
|
+
await pool.terminate(instanceId, reason);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
log.error("Failed to terminate via heartbeat", {
|
|
139
|
+
instanceId,
|
|
140
|
+
error: err instanceof Error ? err.message : String(err),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
heartbeat.start();
|
|
145
|
+
// 5. Wire lifecycle cleanup via bus events
|
|
146
|
+
const cleanupHandler = async (event) => {
|
|
147
|
+
if (event.agentId !== instance.id)
|
|
148
|
+
return;
|
|
149
|
+
const terminalStates = new Set(["completed", "failed", "terminated"]);
|
|
150
|
+
if (!terminalStates.has(event.newState))
|
|
151
|
+
return;
|
|
152
|
+
// Remove handler
|
|
153
|
+
pool.runtimeManager.bus.off("agent:lifecycle", cleanupHandler);
|
|
154
|
+
// Stop heartbeat
|
|
155
|
+
removeHeartbeatTracker(instance.id);
|
|
156
|
+
// Revoke voucher
|
|
157
|
+
if (governance.voucherToken) {
|
|
158
|
+
await revokeGovernanceVoucher(ltm, governance.voucherToken);
|
|
159
|
+
}
|
|
160
|
+
logActivity({
|
|
161
|
+
source: "agent",
|
|
162
|
+
summary: `Governed agent ${event.newState}: ${request.label}`,
|
|
163
|
+
detail: `Instance: ${instance.id}, voucher revoked: ${governance.voucherToken ?? "none"}`,
|
|
164
|
+
traceId,
|
|
165
|
+
actionLabel: request.origin === "ai" ? "AUTONOMOUS" : "PROMPTED",
|
|
166
|
+
reason: "governed-lifecycle",
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
pool.runtimeManager.bus.on("agent:lifecycle", cleanupHandler);
|
|
170
|
+
log.info("Governed spawn complete", {
|
|
171
|
+
taskId: request.taskId,
|
|
172
|
+
instanceId: instance.id,
|
|
173
|
+
pid: instance.pid,
|
|
174
|
+
voucherToken: governance.voucherToken,
|
|
175
|
+
heartbeatKeywords: taskKeywords.slice(0, 5),
|
|
176
|
+
traceId,
|
|
177
|
+
});
|
|
178
|
+
return {
|
|
179
|
+
success: true,
|
|
180
|
+
instance,
|
|
181
|
+
governance,
|
|
182
|
+
heartbeat,
|
|
183
|
+
traceId,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=governed-spawn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governed-spawn.js","sourceRoot":"","sources":["../../src/agents/governed-spawn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
/** A single heartbeat pulse from an agent. */
|
|
16
|
+
export interface HeartbeatPulse {
|
|
17
|
+
timestamp: string;
|
|
18
|
+
taskId: string;
|
|
19
|
+
instanceId: string;
|
|
20
|
+
type: "spawn" | "action" | "output" | "checkpoint" | "complete" | "terminate" | "silence-warning";
|
|
21
|
+
detail?: string;
|
|
22
|
+
/** Semantic summary of what the agent is doing (for drift detection). */
|
|
23
|
+
actionSummary?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Configuration for a heartbeat tracker. */
|
|
26
|
+
export interface HeartbeatConfig {
|
|
27
|
+
/** Max silence before warning (ms). Default: 120_000 (2 min). */
|
|
28
|
+
silenceWarningMs: number;
|
|
29
|
+
/** Max silence before termination (ms). Default: 300_000 (5 min). */
|
|
30
|
+
silenceTerminateMs: number;
|
|
31
|
+
/** Check interval (ms). Default: 15_000 (15s). */
|
|
32
|
+
checkIntervalMs: number;
|
|
33
|
+
/** Task description for drift detection. */
|
|
34
|
+
taskDescription: string;
|
|
35
|
+
/** Keywords from the task for simple drift heuristic. */
|
|
36
|
+
taskKeywords: string[];
|
|
37
|
+
/** Max consecutive drift warnings before termination. Default: 3. */
|
|
38
|
+
maxDriftWarnings: number;
|
|
39
|
+
}
|
|
40
|
+
/** Status of a tracked agent's heartbeat. */
|
|
41
|
+
export interface HeartbeatStatus {
|
|
42
|
+
taskId: string;
|
|
43
|
+
instanceId: string;
|
|
44
|
+
alive: boolean;
|
|
45
|
+
lastPulseAt: string | null;
|
|
46
|
+
silenceMs: number;
|
|
47
|
+
driftWarnings: number;
|
|
48
|
+
totalPulses: number;
|
|
49
|
+
state: "healthy" | "warning" | "critical" | "terminated";
|
|
50
|
+
}
|
|
51
|
+
/** Callback when an agent needs to be terminated. */
|
|
52
|
+
export type TerminateCallback = (instanceId: string, reason: string) => Promise<void>;
|
|
53
|
+
/** Extract meaningful keywords from a task description. */
|
|
54
|
+
export declare function extractTaskKeywords(description: string): string[];
|
|
55
|
+
export declare class HeartbeatTracker {
|
|
56
|
+
readonly taskId: string;
|
|
57
|
+
readonly instanceId: string;
|
|
58
|
+
private config;
|
|
59
|
+
private onTerminate;
|
|
60
|
+
private lastPulseAt;
|
|
61
|
+
private driftWarnings;
|
|
62
|
+
private totalPulses;
|
|
63
|
+
private checkTimer;
|
|
64
|
+
private terminated;
|
|
65
|
+
private traceId;
|
|
66
|
+
constructor(taskId: string, instanceId: string, config: Partial<HeartbeatConfig>, onTerminate: TerminateCallback);
|
|
67
|
+
/** Start monitoring the agent's heartbeat. */
|
|
68
|
+
start(): void;
|
|
69
|
+
/** Stop monitoring (call on agent completion). */
|
|
70
|
+
stop(reason?: "complete" | "terminate"): void;
|
|
71
|
+
/**
|
|
72
|
+
* Record a heartbeat pulse. Call this whenever the agent produces
|
|
73
|
+
* observable output (file write, stdout, checkpoint).
|
|
74
|
+
*/
|
|
75
|
+
recordPulse(type: HeartbeatPulse["type"], detail?: string, actionSummary?: string): void;
|
|
76
|
+
/** Get the current heartbeat status. */
|
|
77
|
+
getStatus(): HeartbeatStatus;
|
|
78
|
+
private check;
|
|
79
|
+
private terminateAgent;
|
|
80
|
+
}
|
|
81
|
+
/** Create and register a heartbeat tracker for an agent instance. */
|
|
82
|
+
export declare function createHeartbeatTracker(taskId: string, instanceId: string, config: Partial<HeartbeatConfig>, onTerminate: TerminateCallback): HeartbeatTracker;
|
|
83
|
+
/** Get a tracker by instance ID. */
|
|
84
|
+
export declare function getHeartbeatTracker(instanceId: string): HeartbeatTracker | undefined;
|
|
85
|
+
/** Remove a tracker (call on agent completion). */
|
|
86
|
+
export declare function removeHeartbeatTracker(instanceId: string): void;
|
|
87
|
+
/** Get status of all tracked agents. */
|
|
88
|
+
export declare function getAllHeartbeatStatuses(): HeartbeatStatus[];
|
|
89
|
+
/** Stop all trackers (call on shutdown). */
|
|
90
|
+
export declare function shutdownHeartbeats(): void;
|
|
91
|
+
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../src/agents/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA4BH,8CAA8C;AAC9C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,GAAG,iBAAiB,CAAC;IAClG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,eAAe,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CAAC;CAC1D;AAED,qDAAqD;AACrD,MAAM,MAAM,iBAAiB,GAAG,CAC9B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,IAAI,CAAC,CAAC;AAmCnB,2DAA2D;AAC3D,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBjE;AA+BD,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAoB;IAEvC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAS;gBAGtB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,EAChC,WAAW,EAAE,iBAAiB;IAehC,8CAA8C;IAC9C,KAAK,IAAI,IAAI;IAgBb,kDAAkD;IAClD,IAAI,CAAC,MAAM,GAAE,UAAU,GAAG,WAAwB,GAAG,IAAI;IAezD;;;OAGG;IACH,WAAW,CACT,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAC5B,MAAM,CAAC,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,GACrB,IAAI;IAkDP,wCAAwC;IACxC,SAAS,IAAI,eAAe;IA+B5B,OAAO,CAAC,KAAK;IA8Bb,OAAO,CAAC,cAAc;CA+BvB;AAQD,qEAAqE;AACrE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,EAChC,WAAW,EAAE,iBAAiB,GAC7B,gBAAgB,CAUlB;AAED,oCAAoC;AACpC,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAEpF;AAED,mDAAmD;AACnD,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAM/D;AAED,wCAAwC;AACxC,wBAAgB,uBAAuB,IAAI,eAAe,EAAE,CAE3D;AAED,4CAA4C;AAC5C,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
|