@sema-agent/server 1.314.0 → 1.316.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 (146) 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/idempotency.d.ts +1 -0
  16. package/dist/http/idempotency.js +3 -0
  17. package/dist/http/principal-gate.d.ts +12 -0
  18. package/dist/http/principal-gate.js +52 -0
  19. package/dist/http/route-ctx.d.ts +67 -0
  20. package/dist/http/route-ctx.js +2 -0
  21. package/dist/http/routes/attachments.d.ts +4 -0
  22. package/dist/http/routes/attachments.js +106 -0
  23. package/dist/http/routes/capabilities.d.ts +4 -0
  24. package/dist/http/routes/capabilities.js +111 -0
  25. package/dist/http/routes/images.d.ts +20 -0
  26. package/dist/http/routes/images.js +572 -0
  27. package/dist/http/routes/memory-policy.d.ts +4 -0
  28. package/dist/http/routes/memory-policy.js +105 -0
  29. package/dist/http/routes/observability.d.ts +4 -0
  30. package/dist/http/routes/observability.js +63 -0
  31. package/dist/http/routes/session-sync.d.ts +36 -0
  32. package/dist/http/routes/session-sync.js +513 -0
  33. package/dist/http/routes/sessions-list.d.ts +4 -0
  34. package/dist/http/routes/sessions-list.js +117 -0
  35. package/dist/http/routes/sessions.d.ts +17 -0
  36. package/dist/http/routes/sessions.js +746 -0
  37. package/dist/http/send.d.ts +6 -0
  38. package/dist/http/send.js +19 -0
  39. package/dist/http/server.d.ts +101 -76
  40. package/dist/http/server.js +129 -2410
  41. package/dist/http/sse-log.d.ts +25 -0
  42. package/dist/http/sse-log.js +59 -0
  43. package/dist/http/workspace-content.d.ts +3 -0
  44. package/dist/http/workspace-content.js +20 -0
  45. package/dist/index.d.ts +1 -1
  46. package/dist/leader/leader.js +5 -2
  47. package/dist/leader/wire.js +169 -165
  48. package/dist/main.js +462 -451
  49. package/dist/plugins/approval-store-sql.d.ts +52 -0
  50. package/dist/plugins/approval-store-sql.js +119 -0
  51. package/dist/plugins/breaker-state-sql.d.ts +29 -0
  52. package/dist/plugins/breaker-state-sql.js +104 -0
  53. package/dist/plugins/checkpoint-store-sql.d.ts +67 -0
  54. package/dist/plugins/checkpoint-store-sql.js +224 -0
  55. package/dist/plugins/file-snapshot-store-sql.d.ts +38 -0
  56. package/dist/plugins/file-snapshot-store-sql.js +210 -0
  57. package/dist/plugins/image-bake-store-sql.d.ts +53 -0
  58. package/dist/plugins/image-bake-store-sql.js +463 -0
  59. package/dist/plugins/image-index-sql.d.ts +33 -0
  60. package/dist/plugins/image-index-sql.js +328 -0
  61. package/dist/plugins/k8s-bg-scripts.d.ts +19 -0
  62. package/dist/plugins/k8s-bg-scripts.js +129 -0
  63. package/dist/plugins/k8s-exec-protocol.d.ts +20 -0
  64. package/dist/plugins/k8s-exec-protocol.js +87 -0
  65. package/dist/plugins/outcome-ledger-sql.d.ts +70 -0
  66. package/dist/plugins/outcome-ledger-sql.js +158 -0
  67. package/dist/plugins/pg-approval-store.d.ts +1 -27
  68. package/dist/plugins/pg-approval-store.js +1 -83
  69. package/dist/plugins/pg-breaker-state.d.ts +1 -19
  70. package/dist/plugins/pg-breaker-state.js +1 -88
  71. package/dist/plugins/pg-checkpoint-store.d.ts +1 -33
  72. package/dist/plugins/pg-checkpoint-store.js +1 -189
  73. package/dist/plugins/pg-cost-quota.js +3 -143
  74. package/dist/plugins/pg-file-snapshot-store.d.ts +1 -27
  75. package/dist/plugins/pg-file-snapshot-store.js +1 -190
  76. package/dist/plugins/pg-image-bake.d.ts +1 -40
  77. package/dist/plugins/pg-image-bake.js +1 -420
  78. package/dist/plugins/pg-image-index.d.ts +1 -21
  79. package/dist/plugins/pg-image-index.js +1 -217
  80. package/dist/plugins/pg-outcome-ledger.d.ts +2 -22
  81. package/dist/plugins/pg-outcome-ledger.js +1 -104
  82. package/dist/plugins/pg-rate-limiter.d.ts +2 -32
  83. package/dist/plugins/pg-rate-limiter.js +4 -147
  84. package/dist/plugins/pg-resume-anchor-store.d.ts +1 -13
  85. package/dist/plugins/pg-resume-anchor-store.js +1 -22
  86. package/dist/plugins/pg-run-store.d.ts +1 -75
  87. package/dist/plugins/pg-run-store.js +1 -287
  88. package/dist/plugins/pg-session-policy-store.d.ts +1 -11
  89. package/dist/plugins/pg-session-policy-store.js +1 -90
  90. package/dist/plugins/pg-tool-result-store.d.ts +1 -15
  91. package/dist/plugins/pg-tool-result-store.js +1 -52
  92. package/dist/plugins/pg-workflow-journal-store.d.ts +1 -20
  93. package/dist/plugins/pg-workflow-journal-store.js +1 -34
  94. package/dist/plugins/pg-workflow-run-store.d.ts +1 -55
  95. package/dist/plugins/pg-workflow-run-store.js +1 -220
  96. package/dist/plugins/remote-env-k8s.d.ts +5 -38
  97. package/dist/plugins/remote-env-k8s.js +7 -213
  98. package/dist/plugins/resume-anchor-store-sql.d.ts +23 -0
  99. package/dist/plugins/resume-anchor-store-sql.js +38 -0
  100. package/dist/plugins/run-store-sql.d.ts +89 -0
  101. package/dist/plugins/run-store-sql.js +397 -0
  102. package/dist/plugins/session-policy-store-sql.d.ts +22 -0
  103. package/dist/plugins/session-policy-store-sql.js +109 -0
  104. package/dist/plugins/sql-driver.d.ts +25 -0
  105. package/dist/plugins/sql-driver.js +59 -0
  106. package/dist/plugins/tidb-approval-store.d.ts +1 -39
  107. package/dist/plugins/tidb-approval-store.js +1 -71
  108. package/dist/plugins/tidb-breaker-state.d.ts +1 -17
  109. package/dist/plugins/tidb-breaker-state.js +1 -74
  110. package/dist/plugins/tidb-checkpoint-store.d.ts +1 -49
  111. package/dist/plugins/tidb-checkpoint-store.js +1 -191
  112. package/dist/plugins/tidb-file-snapshot-store.d.ts +1 -27
  113. package/dist/plugins/tidb-file-snapshot-store.js +1 -192
  114. package/dist/plugins/tidb-image-bake.d.ts +1 -38
  115. package/dist/plugins/tidb-image-bake.js +1 -348
  116. package/dist/plugins/tidb-image-index.d.ts +1 -19
  117. package/dist/plugins/tidb-image-index.js +1 -149
  118. package/dist/plugins/tidb-outcome-ledger.d.ts +1 -57
  119. package/dist/plugins/tidb-outcome-ledger.js +1 -97
  120. package/dist/plugins/tidb-resume-anchor-store.d.ts +1 -13
  121. package/dist/plugins/tidb-resume-anchor-store.js +1 -22
  122. package/dist/plugins/tidb-run-store.d.ts +1 -75
  123. package/dist/plugins/tidb-run-store.js +1 -306
  124. package/dist/plugins/tidb-session-policy-store.d.ts +1 -11
  125. package/dist/plugins/tidb-session-policy-store.js +1 -86
  126. package/dist/plugins/tidb-tool-result-store.d.ts +1 -13
  127. package/dist/plugins/tidb-tool-result-store.js +1 -38
  128. package/dist/plugins/tidb-workflow-journal-store.d.ts +1 -20
  129. package/dist/plugins/tidb-workflow-journal-store.js +1 -34
  130. package/dist/plugins/tidb-workflow-run-store.d.ts +1 -61
  131. package/dist/plugins/tidb-workflow-run-store.js +1 -231
  132. package/dist/plugins/tool-result-store-sql.d.ts +25 -0
  133. package/dist/plugins/tool-result-store-sql.js +69 -0
  134. package/dist/plugins/workflow-journal-store-sql.d.ts +30 -0
  135. package/dist/plugins/workflow-journal-store-sql.js +53 -0
  136. package/dist/plugins/workflow-run-store-sql.d.ts +85 -0
  137. package/dist/plugins/workflow-run-store-sql.js +299 -0
  138. package/dist/plugins/write-behind-counter.d.ts +14 -3
  139. package/dist/plugins/write-behind-counter.js +39 -12
  140. package/dist/principal-jwt.d.ts +44 -0
  141. package/dist/principal-jwt.js +95 -0
  142. package/dist/security.d.ts +2 -58
  143. package/dist/security.js +3 -118
  144. package/dist/sema-registry.d.ts +5 -200
  145. package/dist/sema-registry.js +4 -567
  146. 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
  }
@@ -9,4 +9,5 @@ export declare class IdempotencyCache<T> {
9
9
  private live;
10
10
  private maybeSweep;
11
11
  }
12
+ export declare function scopedIdempotencyKey(raw: string | undefined, source: string | null, principal: string | undefined): string | undefined;
12
13
  //# sourceMappingURL=idempotency.d.ts.map
@@ -46,4 +46,7 @@ export class IdempotencyCache {
46
46
  this.entries.delete(k);
47
47
  }
48
48
  }
49
+ export function scopedIdempotencyKey(raw, source, principal) {
50
+ return raw ? `${source ?? ""}\x1f${principal ?? ""}\x1f${raw}` : undefined;
51
+ }
49
52
  //# sourceMappingURL=idempotency.js.map
@@ -0,0 +1,12 @@
1
+ import type { IncomingMessage } from "node:http";
2
+ import type { ServiceConfig } from "../config-types.js";
3
+ export declare function headerStr(v: string | string[] | undefined): string | undefined;
4
+ export declare function safeEqual(a: string, b: string): boolean;
5
+ export declare function authorized(req: IncomingMessage, token: string): boolean;
6
+ export declare function systemFor(req: IncomingMessage, config: ServiceConfig): string | null | undefined;
7
+ export declare function bearerPresentedButUnverified(req: IncomingMessage, config: ServiceConfig): boolean;
8
+ export declare function gatedPrincipal(req: IncomingMessage, config: ServiceConfig): string | undefined;
9
+ export declare function explicitOperatorOk(principal: string | undefined, operatorPrincipals: readonly string[]): boolean;
10
+ export declare function isOperator(principal: string | undefined, operatorPrincipals: readonly string[]): boolean;
11
+ export declare function explicitOperator(principal: string | undefined, operatorPrincipals: readonly string[]): boolean;
12
+ //# sourceMappingURL=principal-gate.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+ import { verifiedPrincipal, ssoVerifiedPrincipal } from "../security.js";
3
+ export function headerStr(v) {
4
+ return Array.isArray(v) ? v[0] : v;
5
+ }
6
+ export function safeEqual(a, b) {
7
+ const ab = Buffer.from(a, "utf8");
8
+ const bb = Buffer.from(b, "utf8");
9
+ return ab.length === bb.length && timingSafeEqual(ab, bb);
10
+ }
11
+ export function authorized(req, token) {
12
+ const h = req.headers.authorization ?? "";
13
+ return safeEqual(h, `Bearer ${token}`) || safeEqual(h, `token ${token}`);
14
+ }
15
+ export function systemFor(req, config) {
16
+ for (const [tok, system] of Object.entries(config.authTokens ?? {})) {
17
+ if (authorized(req, tok))
18
+ return system;
19
+ }
20
+ if (config.authToken && authorized(req, config.authToken))
21
+ return null;
22
+ return undefined;
23
+ }
24
+ export function bearerPresentedButUnverified(req, config) {
25
+ const h = req.headers.authorization;
26
+ if (typeof h !== "string" || !/^(Bearer|token) /i.test(h))
27
+ return false;
28
+ if (ssoVerifiedPrincipal(req))
29
+ return false;
30
+ if (systemFor(req, config) !== undefined)
31
+ return false;
32
+ if (config.traceToken && authorized(req, config.traceToken))
33
+ return false;
34
+ return true;
35
+ }
36
+ export function gatedPrincipal(req, config) {
37
+ if (bearerPresentedButUnverified(req, config))
38
+ return undefined;
39
+ return verifiedPrincipal(req, config);
40
+ }
41
+ export function explicitOperatorOk(principal, operatorPrincipals) {
42
+ return operatorPrincipals.length > 0 && principal !== undefined && operatorPrincipals.includes(principal);
43
+ }
44
+ export function isOperator(principal, operatorPrincipals) {
45
+ if (operatorPrincipals.length === 0)
46
+ return true;
47
+ return principal !== undefined && operatorPrincipals.includes(principal);
48
+ }
49
+ export function explicitOperator(principal, operatorPrincipals) {
50
+ return operatorPrincipals.length > 0 && principal !== undefined && operatorPrincipals.includes(principal);
51
+ }
52
+ //# sourceMappingURL=principal-gate.js.map