@sema-agent/server 1.314.0 → 1.315.0

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 (52) hide show
  1. package/dist/approval-hmac.d.ts +17 -0
  2. package/dist/approval-hmac.js +27 -0
  3. package/dist/config-center/apply-effective.d.ts +22 -0
  4. package/dist/config-center/apply-effective.js +283 -0
  5. package/dist/config-center/http-client.d.ts +23 -0
  6. package/dist/config-center/http-client.js +109 -0
  7. package/dist/config-center/restart-signal.d.ts +12 -0
  8. package/dist/config-center/restart-signal.js +70 -0
  9. package/dist/config-center/skills-mcp.d.ts +13 -0
  10. package/dist/config-center/skills-mcp.js +113 -0
  11. package/dist/config-center/types.d.ts +143 -0
  12. package/dist/config-center/types.js +2 -0
  13. package/dist/fleet/fleet-bus.js +92 -83
  14. package/dist/hooks/hook-runner.js +18 -9
  15. package/dist/http/server.d.ts +95 -69
  16. package/dist/http/server.js +8 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/leader/leader.js +5 -2
  19. package/dist/leader/wire.js +169 -165
  20. package/dist/main.js +462 -451
  21. package/dist/plugins/checkpoint-store-sql.d.ts +67 -0
  22. package/dist/plugins/checkpoint-store-sql.js +224 -0
  23. package/dist/plugins/image-bake-store-sql.d.ts +53 -0
  24. package/dist/plugins/image-bake-store-sql.js +463 -0
  25. package/dist/plugins/k8s-bg-scripts.d.ts +19 -0
  26. package/dist/plugins/k8s-bg-scripts.js +129 -0
  27. package/dist/plugins/k8s-exec-protocol.d.ts +20 -0
  28. package/dist/plugins/k8s-exec-protocol.js +87 -0
  29. package/dist/plugins/pg-checkpoint-store.d.ts +1 -33
  30. package/dist/plugins/pg-checkpoint-store.js +1 -189
  31. package/dist/plugins/pg-cost-quota.js +3 -143
  32. package/dist/plugins/pg-image-bake.d.ts +1 -40
  33. package/dist/plugins/pg-image-bake.js +1 -420
  34. package/dist/plugins/pg-rate-limiter.d.ts +2 -32
  35. package/dist/plugins/pg-rate-limiter.js +4 -147
  36. package/dist/plugins/remote-env-k8s.d.ts +5 -38
  37. package/dist/plugins/remote-env-k8s.js +7 -213
  38. package/dist/plugins/sql-driver.d.ts +25 -0
  39. package/dist/plugins/sql-driver.js +59 -0
  40. package/dist/plugins/tidb-checkpoint-store.d.ts +1 -49
  41. package/dist/plugins/tidb-checkpoint-store.js +1 -191
  42. package/dist/plugins/tidb-image-bake.d.ts +1 -38
  43. package/dist/plugins/tidb-image-bake.js +1 -348
  44. package/dist/plugins/write-behind-counter.d.ts +14 -3
  45. package/dist/plugins/write-behind-counter.js +39 -12
  46. package/dist/principal-jwt.d.ts +44 -0
  47. package/dist/principal-jwt.js +95 -0
  48. package/dist/security.d.ts +2 -58
  49. package/dist/security.js +3 -118
  50. package/dist/sema-registry.d.ts +5 -200
  51. package/dist/sema-registry.js +4 -567
  52. package/package.json +1 -1
@@ -0,0 +1,113 @@
1
+ import { skillContentHash } from "@sema-agent/registry-core";
2
+ import { fetchSkillContent } from "./http-client.js";
3
+ export async function applyCenterSkills(baseline, manifest, baseUrl, token, logger, fetchImpl = fetch, diskCacheDir) {
4
+ const { promises: fsp } = await import("node:fs");
5
+ const { join: joinPath } = await import("node:path");
6
+ const diskRead = async (hash) => {
7
+ if (!diskCacheDir)
8
+ return undefined;
9
+ const hex = hash.replace(/^sha256:/, "");
10
+ if (!/^[0-9a-f]{64}$/.test(hex))
11
+ return undefined;
12
+ try {
13
+ const text = await fsp.readFile(joinPath(diskCacheDir, hex), "utf8");
14
+ if (skillContentHash(text) === hash)
15
+ return text;
16
+ logger?.warn("sema_registry_skill_cache_corrupt", { hash, note: "on-disk body fails its own hash — ignored, refetching from center" });
17
+ }
18
+ catch {
19
+ }
20
+ return undefined;
21
+ };
22
+ const pendingWrites = [];
23
+ const diskWrite = (hash, content) => {
24
+ if (!diskCacheDir)
25
+ return;
26
+ const hex = hash.replace(/^sha256:/, "");
27
+ pendingWrites.push((async () => {
28
+ await fsp.mkdir(diskCacheDir, { recursive: true });
29
+ const tmp = joinPath(diskCacheDir, `${hex}.${Math.random().toString(36).slice(2, 8)}.tmp`);
30
+ await fsp.writeFile(tmp, content, { mode: 0o600 });
31
+ await fsp.rename(tmp, joinPath(diskCacheDir, hex));
32
+ })().catch((err) => logger?.warn("sema_registry_skill_cache_write_failed", { hash, err: String(err) })));
33
+ };
34
+ const byName = new Map(baseline.map((s) => [s.spec.name, s]));
35
+ const contentCache = new Map();
36
+ const seenNames = new Set();
37
+ for (const m of manifest.skills ?? []) {
38
+ if (m.enabled === false)
39
+ continue;
40
+ if (seenNames.has(m.name))
41
+ logger?.warn("sema_registry_skill_duplicate_name", { name: m.name, note: "duplicate name in center manifest — last entry wins" });
42
+ seenNames.add(m.name);
43
+ try {
44
+ let content = contentCache.get(m.contentHash);
45
+ if (content === undefined)
46
+ content = await diskRead(m.contentHash);
47
+ if (content === undefined) {
48
+ content = await fetchSkillContent(baseUrl, token, m.contentHash, fetchImpl);
49
+ diskWrite(m.contentHash, content);
50
+ }
51
+ contentCache.set(m.contentHash, content);
52
+ const overrodeBuiltin = byName.has(m.name);
53
+ byName.set(m.name, { spec: { name: m.name, description: m.description, content }, scenarios: m.scenarios ?? [] });
54
+ logger?.info("sema_registry_skill", { name: m.name, hash: m.contentHash, scenarios: m.scenarios, overrodeBuiltin });
55
+ }
56
+ catch (err) {
57
+ logger?.warn("sema_registry_skill_failed", { name: m.name, hash: m.contentHash, err: String(err), note: "keeping baseline if any; skipping center version" });
58
+ }
59
+ }
60
+ await Promise.all(pendingWrites);
61
+ return [...byName.values()];
62
+ }
63
+ function resolveRefs(refs, server, kind, logger) {
64
+ if (!refs)
65
+ return {};
66
+ const out = {};
67
+ for (const [key, envName] of Object.entries(refs)) {
68
+ const v = process.env[envName];
69
+ if (v === undefined) {
70
+ logger?.warn("sema_registry_mcp_env_missing", { server, kind, key, envName, note: "skipping this MCP server — referenced env var is unset in this service" });
71
+ return null;
72
+ }
73
+ out[key] = v;
74
+ }
75
+ return out;
76
+ }
77
+ export function resolveMcpServers(mcp, logger) {
78
+ const out = [];
79
+ for (const s of mcp.servers ?? []) {
80
+ if (s.enabled === false)
81
+ continue;
82
+ const allow = s.allowTools && s.allowTools.length > 0 ? { allowTools: s.allowTools } : {};
83
+ const elicit = s.elicitation === true ? { elicitation: true } : {};
84
+ if (s.transport.kind === "stdio") {
85
+ const env = resolveRefs(s.transport.envRefs, s.name, "env", logger);
86
+ if (env === null)
87
+ continue;
88
+ out.push({
89
+ scenarios: s.scenarios ?? [],
90
+ spec: { name: s.name, transport: { kind: "stdio", command: s.transport.command, args: s.transport.args, ...(Object.keys(env).length ? { env } : {}) }, ...allow, ...elicit },
91
+ });
92
+ }
93
+ else {
94
+ const headers = resolveRefs(s.transport.headerRefs, s.name, "header", logger);
95
+ if (headers === null)
96
+ continue;
97
+ out.push({
98
+ scenarios: s.scenarios ?? [],
99
+ spec: { name: s.name, transport: { kind: "http", url: s.transport.url, ...(Object.keys(headers).length ? { headers } : {}), ...(s.transport.principalHeader ? { principalHeader: s.transport.principalHeader } : {}) }, ...allow, ...elicit },
100
+ });
101
+ }
102
+ }
103
+ if (out.length > 0)
104
+ logger?.info("sema_registry_mcp", { servers: out.map((s) => s.spec.name) });
105
+ return out;
106
+ }
107
+ export function mcpForScenario(servers, scenario) {
108
+ if (!servers || servers.length === 0)
109
+ return undefined;
110
+ const hit = servers.filter((s) => s.scenarios.length === 0 || s.scenarios.includes(scenario)).map((s) => s.spec);
111
+ return hit.length > 0 ? hit : undefined;
112
+ }
113
+ //# sourceMappingURL=skills-mcp.js.map
@@ -0,0 +1,143 @@
1
+ import type { CollabTemplateWire } from "../capabilities/collab-wire.js";
2
+ import type { Autonomy, CommandRule } from "../runtime-governance.js";
3
+ export interface CenterModel {
4
+ name: string;
5
+ id: string;
6
+ provider: string;
7
+ api: "openai-completions" | "anthropic-messages";
8
+ baseUrl?: string;
9
+ apiKeyEnv?: string;
10
+ sealedApiKey?: {
11
+ ciphertext: string;
12
+ publicKeyId: string;
13
+ alg: string;
14
+ setAt?: string;
15
+ };
16
+ tier?: string;
17
+ reasoning?: boolean;
18
+ vision?: boolean;
19
+ contextWindow?: number;
20
+ maxTokens?: number;
21
+ autoCompactTokens?: number;
22
+ charsPerToken?: number;
23
+ cost?: {
24
+ input: number;
25
+ output: number;
26
+ cacheRead?: number;
27
+ cacheWrite?: number;
28
+ };
29
+ quotaWeight?: number;
30
+ defaultThinking?: string;
31
+ reasoningEffortLevels?: string[];
32
+ extraBody?: Record<string, unknown>;
33
+ promptGuidance?: string[];
34
+ enabled?: boolean;
35
+ }
36
+ export type CenterRoleTarget = {
37
+ model: string;
38
+ } | {
39
+ select: unknown;
40
+ };
41
+ export interface CenterTeam {
42
+ name: string;
43
+ members: {
44
+ role: string;
45
+ modelRole?: string;
46
+ model?: string;
47
+ systemPrompt?: string;
48
+ }[];
49
+ rounds: number;
50
+ synthesizer?: {
51
+ role: string;
52
+ modelRole?: string;
53
+ systemPrompt?: string;
54
+ };
55
+ scenario?: string;
56
+ maxTranscriptTokens?: number;
57
+ enabled?: boolean;
58
+ }
59
+ export interface CenterSkillManifest {
60
+ name: string;
61
+ description: string;
62
+ scenarios: string[];
63
+ contentHash: string;
64
+ enabled?: boolean;
65
+ }
66
+ export interface CenterMcpServer {
67
+ name: string;
68
+ scenarios: string[];
69
+ enabled?: boolean;
70
+ allowTools?: string[];
71
+ elicitation?: boolean;
72
+ transport: {
73
+ kind: "stdio";
74
+ command: string;
75
+ args?: string[];
76
+ envRefs?: Record<string, string>;
77
+ } | {
78
+ kind: "http";
79
+ url: string;
80
+ headerRefs?: Record<string, string>;
81
+ principalHeader?: string;
82
+ };
83
+ }
84
+ export interface EffectiveConfig {
85
+ version: number;
86
+ updatedAt: string;
87
+ models: {
88
+ models: CenterModel[];
89
+ roles: Record<string, CenterRoleTarget>;
90
+ atModelAllowlist?: string[];
91
+ };
92
+ teams?: {
93
+ teams: CenterTeam[];
94
+ };
95
+ collab?: {
96
+ templates: CollabTemplateWire[];
97
+ };
98
+ skills?: {
99
+ skills: CenterSkillManifest[];
100
+ };
101
+ mcp?: {
102
+ servers: CenterMcpServer[];
103
+ };
104
+ scenarios?: {
105
+ scenarios: Array<{
106
+ name: string;
107
+ toolset: string;
108
+ enabled?: boolean;
109
+ }>;
110
+ };
111
+ runtime?: {
112
+ rateLimitPerMin?: number;
113
+ approvalRequire?: string[];
114
+ maxTaskCostUsd?: number;
115
+ maxTaskTokens?: number;
116
+ maxPrincipalCostUsd?: number;
117
+ costQuotaWindowSec?: number;
118
+ autonomy?: Autonomy;
119
+ commandPolicy?: CommandRule[];
120
+ };
121
+ projects?: {
122
+ projects?: Record<string, unknown>;
123
+ } | Record<string, unknown>;
124
+ governance?: {
125
+ autonomy?: Autonomy;
126
+ commandPolicy?: CommandRule[];
127
+ approvalRequire?: string[];
128
+ };
129
+ plugins?: {
130
+ plugins?: unknown[];
131
+ };
132
+ prompts?: unknown;
133
+ }
134
+ export interface ExecutionRuling {
135
+ required: boolean;
136
+ allowedLanes: string[];
137
+ sessionMirror?: SessionMirrorRuling;
138
+ }
139
+ export interface SessionMirrorRuling {
140
+ engineUrl: string;
141
+ required: boolean;
142
+ }
143
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -262,94 +262,78 @@ export function fleetBackgroundChildPublisher(bus, log) {
262
262
  return u.tokens;
263
263
  return undefined;
264
264
  };
265
- return (e) => {
266
- if (e.kind === "spawn") {
267
- const tomb = meta.get(e.taskId);
268
- const inheritParent = !e.parentTaskId && !e.parentSessionId && tomb?.done === true;
269
- const m = {
270
- ...(e.parentTaskId ? { parentTaskId: e.parentTaskId } : {}),
271
- ...(!e.parentTaskId && e.parentSessionId ? { parentSessionLink: e.parentSessionId } : {}),
272
- ...(inheritParent && tomb?.parentTaskId !== undefined ? { parentTaskId: tomb.parentTaskId } : {}),
273
- ...(inheritParent && tomb?.parentSessionLink !== undefined ? { parentSessionLink: tomb.parentSessionLink } : {}),
274
- ...(inheritParent && tomb?.resolvedParentId !== undefined ? { resolvedParentId: tomb.resolvedParentId } : {}),
275
- ...(e.sessionScoped && e.owner ? { hostSessionId: e.rootSessionId ?? e.owner } : {}),
276
- tenantScope: e.scope ?? "default",
277
- sessionScoped: e.sessionScoped,
278
- spawnedAt: e.startedAt ?? Date.now(),
279
- ...(e.rootSessionId ? { rootSessionId: e.rootSessionId } : {}),
280
- ...(e.parentToolCallId ? { parentToolCallId: e.parentToolCallId } : {}),
281
- ...(e.sessionId ? { aliasUuid: e.sessionId } : {}),
282
- ...(e.workflowRunId ? { workflowRunId: e.workflowRunId } : {}),
283
- ...(e.workflowRunId && !(e.sessionScoped && e.owner)
284
- ? (() => {
285
- if (e.rootSessionId)
286
- return { hostSessionId: e.rootSessionId };
287
- if (e.parentSessionId)
288
- return { hostSessionId: e.parentSessionId };
289
- const host = e.parentTaskId ? bus.snapshot().tasks.find((r) => r.id === e.parentTaskId && r.scope === (e.scope ?? "default")) : undefined;
290
- return host?.sessionId ? { hostSessionId: host.sessionId } : {};
291
- })()
292
- : {}),
293
- ...(!(e.sessionScoped && e.owner) && !e.workflowRunId && (e.rootSessionId ?? e.parentSessionId)
294
- ? (() => {
295
- if (e.rootSessionId)
296
- return { hostSessionId: e.rootSessionId };
297
- const childScope = e.scope ?? "default";
298
- for (const pm of meta.values()) {
299
- if (pm.aliasUuid === e.parentSessionId && (pm.tenantScope ?? "default") === childScope) {
300
- return pm.hostSessionId ? { hostSessionId: pm.hostSessionId } : {};
301
- }
302
- }
265
+ const handleSpawn = (e) => {
266
+ const tomb = meta.get(e.taskId);
267
+ const inheritParent = !e.parentTaskId && !e.parentSessionId && tomb?.done === true;
268
+ const m = {
269
+ ...(e.parentTaskId ? { parentTaskId: e.parentTaskId } : {}),
270
+ ...(!e.parentTaskId && e.parentSessionId ? { parentSessionLink: e.parentSessionId } : {}),
271
+ ...(inheritParent && tomb?.parentTaskId !== undefined ? { parentTaskId: tomb.parentTaskId } : {}),
272
+ ...(inheritParent && tomb?.parentSessionLink !== undefined ? { parentSessionLink: tomb.parentSessionLink } : {}),
273
+ ...(inheritParent && tomb?.resolvedParentId !== undefined ? { resolvedParentId: tomb.resolvedParentId } : {}),
274
+ ...(e.sessionScoped && e.owner ? { hostSessionId: e.rootSessionId ?? e.owner } : {}),
275
+ tenantScope: e.scope ?? "default",
276
+ sessionScoped: e.sessionScoped,
277
+ spawnedAt: e.startedAt ?? Date.now(),
278
+ ...(e.rootSessionId ? { rootSessionId: e.rootSessionId } : {}),
279
+ ...(e.parentToolCallId ? { parentToolCallId: e.parentToolCallId } : {}),
280
+ ...(e.sessionId ? { aliasUuid: e.sessionId } : {}),
281
+ ...(e.workflowRunId ? { workflowRunId: e.workflowRunId } : {}),
282
+ ...(e.workflowRunId && !(e.sessionScoped && e.owner)
283
+ ? (() => {
284
+ if (e.rootSessionId)
285
+ return { hostSessionId: e.rootSessionId };
286
+ if (e.parentSessionId)
303
287
  return { hostSessionId: e.parentSessionId };
304
- })()
305
- : {}),
306
- };
307
- remember(e.taskId, m);
308
- bus.publishTask({ id: e.taskId, name: redactSecrets(e.description ?? e.name ?? e.taskId), ...(e.agentType ? { agentType: redactSecrets(e.agentType) } : {}), ...rowTags(m), status: "running", tokens: 0, ...(e.transcriptId ? { transcriptId: e.transcriptId } : {}) });
309
- dlog("bg_child_event", { kind: "spawn", taskId: e.taskId, sessionScoped: e.sessionScoped, scope: m.tenantScope, hostSessionId: m.hostSessionId ?? null, parentTaskId: m.parentTaskId ?? null });
310
- return;
311
- }
312
- const m = meta.get(e.taskId) ?? { sessionScoped: e.sessionScoped, tenantScope: "default", spawnedAt: Date.now() };
313
- if (!meta.has(e.taskId)) {
314
- remember(e.taskId, m);
315
- dlog("bg_child_event", { kind: `${e.kind}-lazy-mint`, taskId: e.taskId, sessionScoped: e.sessionScoped });
316
- }
317
- else {
318
- remember(e.taskId, m);
319
- }
320
- if (m.done) {
321
- dlog("bg_child_event", { kind: `${e.kind}-after-terminal-ignored`, taskId: e.taskId });
322
- return;
323
- }
324
- if (m.parentToolCallId === undefined && e.parentToolCallId)
325
- m.parentToolCallId = e.parentToolCallId;
326
- if (e.kind === "tick") {
327
- if (!m.suppressedTwin && e.progressTaskId && (!e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink))) {
328
- const tail = ` ${e.progressTaskId}`;
329
- for (const row of bus.snapshot().tasks) {
330
- if (row.id.endsWith(tail))
331
- bus.removeTask(row.id);
332
- }
333
- m.suppressedTwin = true;
334
- }
335
- if (m.aliasUuid === undefined && e.progressTaskId && (!e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink))) {
336
- m.aliasUuid = e.progressTaskId;
337
- for (const [cid, cm] of meta) {
338
- if ((cm.parentTaskId ?? cm.parentSessionLink) === m.aliasUuid && cm.resolvedParentId === undefined && !cm.done) {
339
- bus.publishTask({ id: cid, ...rowTags(cm) });
288
+ const host = e.parentTaskId ? bus.snapshot().tasks.find((r) => r.id === e.parentTaskId && r.scope === (e.scope ?? "default")) : undefined;
289
+ return host?.sessionId ? { hostSessionId: host.sessionId } : {};
290
+ })()
291
+ : {}),
292
+ ...(!(e.sessionScoped && e.owner) && !e.workflowRunId && (e.rootSessionId ?? e.parentSessionId)
293
+ ? (() => {
294
+ if (e.rootSessionId)
295
+ return { hostSessionId: e.rootSessionId };
296
+ const childScope = e.scope ?? "default";
297
+ for (const pm of meta.values()) {
298
+ if (pm.aliasUuid === e.parentSessionId && (pm.tenantScope ?? "default") === childScope) {
299
+ return pm.hostSessionId ? { hostSessionId: pm.hostSessionId } : {};
300
+ }
340
301
  }
302
+ return { hostSessionId: e.parentSessionId };
303
+ })()
304
+ : {}),
305
+ };
306
+ remember(e.taskId, m);
307
+ bus.publishTask({ id: e.taskId, name: redactSecrets(e.description ?? e.name ?? e.taskId), ...(e.agentType ? { agentType: redactSecrets(e.agentType) } : {}), ...rowTags(m), status: "running", tokens: 0, ...(e.transcriptId ? { transcriptId: e.transcriptId } : {}) });
308
+ dlog("bg_child_event", { kind: "spawn", taskId: e.taskId, sessionScoped: e.sessionScoped, scope: m.tenantScope, hostSessionId: m.hostSessionId ?? null, parentTaskId: m.parentTaskId ?? null });
309
+ };
310
+ const handleTick = (e, m) => {
311
+ if (!m.suppressedTwin && e.progressTaskId && (!e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink))) {
312
+ const tail = ` ${e.progressTaskId}`;
313
+ for (const row of bus.snapshot().tasks) {
314
+ if (row.id.endsWith(tail))
315
+ bus.removeTask(row.id);
316
+ }
317
+ m.suppressedTwin = true;
318
+ }
319
+ if (m.aliasUuid === undefined && e.progressTaskId && (!e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink))) {
320
+ m.aliasUuid = e.progressTaskId;
321
+ for (const [cid, cm] of meta) {
322
+ if ((cm.parentTaskId ?? cm.parentSessionLink) === m.aliasUuid && cm.resolvedParentId === undefined && !cm.done) {
323
+ bus.publishTask({ id: cid, ...rowTags(cm) });
341
324
  }
342
325
  }
343
- const tokens = sumUsage(e.usage);
344
- const name = e.name ? redactSecrets(e.name) : undefined;
345
- const agentType = e.agentType ? redactSecrets(e.agentType) : name;
346
- const currentAction = e.currentAction ? redactSecrets(e.currentAction) : undefined;
347
- const currentTool = e.currentTool
348
- ? { toolName: e.currentTool.toolName, ...(e.currentTool.target !== undefined ? { target: redactSecrets(e.currentTool.target).slice(0, 300) } : {}) }
349
- : undefined;
350
- bus.publishTask({ id: e.taskId, ...rowTags(m), status: "running", ...(tokens !== undefined ? { tokens } : {}), ...(name ? { name } : {}), ...(agentType ? { agentType } : {}), ...(currentAction ? { currentAction } : {}), ...(currentTool ? { currentTool } : {}), ...(e.usage?.toolUses !== undefined ? { toolUses: e.usage.toolUses } : {}), ...(e.transcriptId ? { transcriptId: e.transcriptId } : {}) });
351
- return;
352
326
  }
327
+ const tokens = sumUsage(e.usage);
328
+ const name = e.name ? redactSecrets(e.name) : undefined;
329
+ const agentType = e.agentType ? redactSecrets(e.agentType) : name;
330
+ const currentAction = e.currentAction ? redactSecrets(e.currentAction) : undefined;
331
+ const currentTool = e.currentTool
332
+ ? { toolName: e.currentTool.toolName, ...(e.currentTool.target !== undefined ? { target: redactSecrets(e.currentTool.target).slice(0, 300) } : {}) }
333
+ : undefined;
334
+ bus.publishTask({ id: e.taskId, ...rowTags(m), status: "running", ...(tokens !== undefined ? { tokens } : {}), ...(name ? { name } : {}), ...(agentType ? { agentType } : {}), ...(currentAction ? { currentAction } : {}), ...(currentTool ? { currentTool } : {}), ...(e.usage?.toolUses !== undefined ? { toolUses: e.usage.toolUses } : {}), ...(e.transcriptId ? { transcriptId: e.transcriptId } : {}) });
335
+ };
336
+ const handleTerminal = (e, m) => {
353
337
  const status = e.status === "completed" ? "completed" : e.status === "killed" ? "killed" : "failed";
354
338
  bus.publishTask({
355
339
  id: e.taskId, ...rowTags(m), status,
@@ -420,6 +404,31 @@ export function fleetBackgroundChildPublisher(bus, log) {
420
404
  m.done = true;
421
405
  m.suppressedTwin = true;
422
406
  };
407
+ return (e) => {
408
+ if (e.kind === "spawn") {
409
+ handleSpawn(e);
410
+ return;
411
+ }
412
+ const m = meta.get(e.taskId) ?? { sessionScoped: e.sessionScoped, tenantScope: "default", spawnedAt: Date.now() };
413
+ if (!meta.has(e.taskId)) {
414
+ remember(e.taskId, m);
415
+ dlog("bg_child_event", { kind: `${e.kind}-lazy-mint`, taskId: e.taskId, sessionScoped: e.sessionScoped });
416
+ }
417
+ else {
418
+ remember(e.taskId, m);
419
+ }
420
+ if (m.done) {
421
+ dlog("bg_child_event", { kind: `${e.kind}-after-terminal-ignored`, taskId: e.taskId });
422
+ return;
423
+ }
424
+ if (m.parentToolCallId === undefined && e.parentToolCallId)
425
+ m.parentToolCallId = e.parentToolCallId;
426
+ if (e.kind === "tick") {
427
+ handleTick(e, m);
428
+ return;
429
+ }
430
+ handleTerminal(e, m);
431
+ };
423
432
  }
424
433
  export function fleetRunLabels(objective) {
425
434
  const oneLine = redactSecrets((objective ?? "").replace(/\s+/g, " ")).trim();
@@ -523,7 +523,7 @@ export function createTaskHooks(config, ctx) {
523
523
  const onceFired = new Set();
524
524
  const hooks = {};
525
525
  if (pre) {
526
- hooks.preToolUse = async (toolName, input, tctx) => {
526
+ const preToolUseHook = async (toolName, input, tctx) => {
527
527
  let currentInput = input;
528
528
  let rewritten = false;
529
529
  let asked;
@@ -608,9 +608,10 @@ export function createTaskHooks(config, ctx) {
608
608
  }
609
609
  return undefined;
610
610
  };
611
+ hooks.preToolUse = preToolUseHook;
611
612
  }
612
613
  if (post) {
613
- hooks.postToolUse = async (toolName, input, output, tctx) => {
614
+ const postToolUseHook = async (toolName, input, output, tctx) => {
614
615
  const contexts = [];
615
616
  const responseText = output.content
616
617
  .map((c) => (c && typeof c === "object" && typeof c.text === "string" ? c.text : ""))
@@ -657,9 +658,10 @@ export function createTaskHooks(config, ctx) {
657
658
  }
658
659
  return contexts.length > 0 ? { additionalContext: contexts.join("\n") } : undefined;
659
660
  };
661
+ hooks.postToolUse = postToolUseHook;
660
662
  }
661
663
  if (postFailure) {
662
- hooks.postToolUseFailure = async (toolName, input, f, tctx) => {
664
+ const postToolUseFailureHook = async (toolName, input, f, tctx) => {
663
665
  const contexts = [];
664
666
  const payload = {
665
667
  ...basePayload(ctx),
@@ -700,9 +702,10 @@ export function createTaskHooks(config, ctx) {
700
702
  }
701
703
  return contexts.length > 0 ? { additionalContext: contexts.join("\n") } : undefined;
702
704
  };
705
+ hooks.postToolUseFailure = postToolUseFailureHook;
703
706
  }
704
707
  if (postBatch) {
705
- hooks.postToolBatch = async (calls) => {
708
+ const postToolBatchHook = async (calls) => {
706
709
  const contexts = [];
707
710
  const payload = {
708
711
  ...basePayload(ctx),
@@ -740,9 +743,10 @@ export function createTaskHooks(config, ctx) {
740
743
  }
741
744
  return contexts.length > 0 ? { additionalContext: contexts.join("\n") } : undefined;
742
745
  };
746
+ hooks.postToolBatch = postToolBatchHook;
743
747
  }
744
748
  if (promptSubmit) {
745
- hooks.userPromptSubmit = async (prompt) => {
749
+ const userPromptSubmitHook = async (prompt) => {
746
750
  const contexts = [];
747
751
  const payload = { ...basePayload(ctx), hook_event_name: "UserPromptSubmit", prompt: clip(prompt, MAX_TOOL_INPUT_CHARS) };
748
752
  const singles = await runMatchingEntries("UserPromptSubmit", ignoreMatchers(promptSubmit), "", payload, ctx, onceFired, Date.now() + MAX_HOOK_EVENT_TOTAL_SECONDS * 1000);
@@ -777,9 +781,10 @@ export function createTaskHooks(config, ctx) {
777
781
  }
778
782
  return contexts.length > 0 ? { additionalContext: contexts.join("\n") } : undefined;
779
783
  };
784
+ hooks.userPromptSubmit = userPromptSubmitHook;
780
785
  }
781
786
  if (stopEntries) {
782
- hooks.stop = async (sctx) => {
787
+ const stopHook = async (sctx) => {
783
788
  const payload = { ...basePayload(ctx), hook_event_name: "Stop", stop_hook_active: sctx.stopHookActive };
784
789
  let llmExtra;
785
790
  const wantsPrompt = stopEntries.some((g) => g.hooks.some((h) => h.type === "prompt"));
@@ -867,9 +872,10 @@ export function createTaskHooks(config, ctx) {
867
872
  ...(contexts.length ? { additionalContext: contexts.join("\n") } : {}),
868
873
  };
869
874
  };
875
+ hooks.stop = stopHook;
870
876
  }
871
877
  if (stopFailureEntries) {
872
- hooks.stopFailure = async (fctx) => {
878
+ const stopFailureHook = async (fctx) => {
873
879
  const turnError = toAssistantTurnError(fctx.errorKind);
874
880
  const payload = {
875
881
  ...basePayload(ctx),
@@ -879,9 +885,10 @@ export function createTaskHooks(config, ctx) {
879
885
  };
880
886
  await runObserveOnlyEvent("StopFailure", stopFailureEntries, turnError, payload, ctx, onceFired);
881
887
  };
888
+ hooks.stopFailure = stopFailureHook;
882
889
  }
883
890
  if (preCompactEntries) {
884
- hooks.preCompact = async (pctx) => {
891
+ const preCompactHook = async (pctx) => {
885
892
  const payload = {
886
893
  ...basePayload(ctx),
887
894
  hook_event_name: "PreCompact",
@@ -911,9 +918,10 @@ export function createTaskHooks(config, ctx) {
911
918
  }
912
919
  return undefined;
913
920
  };
921
+ hooks.preCompact = preCompactHook;
914
922
  }
915
923
  if (postCompactEntries) {
916
- hooks.postCompact = async (cctx) => {
924
+ const postCompactHook = async (cctx) => {
917
925
  const payload = {
918
926
  ...basePayload(ctx),
919
927
  hook_event_name: "PostCompact",
@@ -922,6 +930,7 @@ export function createTaskHooks(config, ctx) {
922
930
  };
923
931
  await runObserveOnlyEvent("PostCompact", postCompactEntries, cctx.trigger, payload, ctx, onceFired);
924
932
  };
933
+ hooks.postCompact = postCompactHook;
925
934
  }
926
935
  return hooks;
927
936
  }