@agentproto/runtime 5.13.0 → 5.14.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.
- package/dist/app-mcp-server.d.ts +69 -0
- package/dist/app-mcp-server.mjs +206 -0
- package/dist/app-mcp-server.mjs.map +1 -0
- package/dist/config-schema.mjs +12 -8
- package/dist/config-schema.mjs.map +1 -1
- package/dist/config.mjs +12 -8
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.ts +197 -19
- package/dist/index.mjs +1485 -327
- package/dist/index.mjs.map +1 -1
- package/dist/resume-strategies.mjs +12 -8
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/session-presence.mjs +12 -8
- package/dist/session-presence.mjs.map +1 -1
- package/docs/mcp-tools/agent_start.md +11 -0
- package/package.json +29 -24
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { ensureChromeDevtoolsMcp, resolveChrome, buildHeadlessBrowserMcpEntry, h
|
|
|
7
7
|
import { selectPricingTier, getModelProvider, resolveContextWindow, formatTokens, splitContextWindowHint, resolvePricing, LLM_PRICING_CATALOG, resolvePricingExact, MODEL_ALIASES, isKnownLlmId } from '@agentproto/model-catalog/llm';
|
|
8
8
|
import { resolveCustomRoute, registerCustomRoute, tryParseModelRef, resolveLlmModelRoute, formatModelRef, stripRouteSuffix, stripFixedNativeVendor } from '@agentproto/model-catalog/route-identity';
|
|
9
9
|
import { randomBytes, createHmac, randomUUID, timingSafeEqual, createHash } from 'crypto';
|
|
10
|
-
import { createReadStream, promises, readFileSync, mkdirSync, writeFileSync, renameSync, readdirSync, openSync, fstatSync, readSync, closeSync, existsSync, statSync, mkdtempSync, chmodSync, realpathSync, cpSync, appendFileSync, createWriteStream } from 'fs';
|
|
10
|
+
import { createReadStream, promises, readFileSync, mkdirSync, writeFileSync, renameSync, readdirSync, openSync, fstatSync, readSync, closeSync, existsSync, statSync, mkdtempSync, chmodSync, writeSync, fsyncSync, unlinkSync, realpathSync, cpSync, appendFileSync, createWriteStream } from 'fs';
|
|
11
11
|
import { createInterface } from 'readline';
|
|
12
12
|
import * as providers_store_star from '@agentproto/providers-store';
|
|
13
13
|
import { findAnthropicGatewayPreset, anthropicGatewayPresetList, getAnthropicGatewayPreset } from '@agentproto/provider-presets';
|
|
@@ -16,7 +16,7 @@ import { z, ZodError } from 'zod';
|
|
|
16
16
|
import { listAuthProfiles, eligibleProfiles, getAuthProfile, createAuthProfile, AuthProfileValidationError, deleteAuthProfile, updateAuthProfile, KeychainStore, removeAuthProfile, addAuthProfile, setAuthProfileEnabled, setAuthProfileModels, refreshAuthProfileModels, credentialIdentity } from '@agentproto/auth';
|
|
17
17
|
import { CatalogProviderSchema, getModelsByProvider, getStaticModelProvider } from '@agentproto/model-catalog';
|
|
18
18
|
import { resolvePairPageUrl, DEFAULT_PAIR_PAGE } from '@agentproto/secrets/pairing/browser';
|
|
19
|
-
import { ListToolsRequestSchema, CallToolRequestSchema, SUPPORTED_PROTOCOL_VERSIONS, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
|
|
19
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, McpError, ErrorCode, SUPPORTED_PROTOCOL_VERSIONS, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
|
|
20
20
|
import { makeCredsStore, makeAdapterResolver, makeAdapterLister, discoverAdapterPackages, makeSetupLedger, makeListTool, makeSetupTool } from '@agentproto/provider-kit';
|
|
21
21
|
import { syncPiModels, getConfiguredEndpoints, checkHarnessFit, connectorById } from '@agentproto/llm-endpoint';
|
|
22
22
|
import { createServer, request as request$1 } from 'http';
|
|
@@ -38,6 +38,7 @@ import { createBrainManager, parseKnowledgeConfig } from '@agentproto/workspace-
|
|
|
38
38
|
import { browserAdapters, getBrowserAdapter } from '@agentproto/adapter-browser';
|
|
39
39
|
import { defineHttpDriver } from '@agentproto/driver-http';
|
|
40
40
|
import matter2 from 'gray-matter';
|
|
41
|
+
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
|
|
41
42
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
42
43
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
43
44
|
import { WebSocketServer } from 'ws';
|
|
@@ -48,8 +49,8 @@ import { createReconnectLogGate } from '@agentproto/pairing-host';
|
|
|
48
49
|
export { createReconnectLogGate } from '@agentproto/pairing-host';
|
|
49
50
|
import { loadAppBundledTools, loadAppHandle, peekAppUi, unpackApp, safeId, versionSatisfies } from '@agentproto/app-kit';
|
|
50
51
|
import { loadAgent } from '@agentproto/agent';
|
|
51
|
-
import { normalizeToolId } from '@agentproto/driver';
|
|
52
|
-
import { compileWorkflow, runWorkflow, isCompilableJsonSchema, validateAgainstJsonSchema, validateWorkflowInput, buildAgentStep, StepOutcomeError, MissingArtifactError } from '@agentproto/workflow-runtime';
|
|
52
|
+
import { normalizeToolId, runTool } from '@agentproto/driver';
|
|
53
|
+
import { compileWorkflow, runWorkflow, isCompilableJsonSchema, validateAgainstJsonSchema, validateWorkflowInput, buildAgentStep, AgentSessionLostError, StepOutcomeError, MissingArtifactError } from '@agentproto/workflow-runtime';
|
|
53
54
|
import { loadWorkflowHandle } from '@agentproto/workflow-loader';
|
|
54
55
|
import { Cron } from 'croner';
|
|
55
56
|
import { brotliCompressSync, constants, gzipSync } from 'zlib';
|
|
@@ -145,15 +146,15 @@ function hasMarker(command, marker) {
|
|
|
145
146
|
return false;
|
|
146
147
|
}
|
|
147
148
|
function listProcesses() {
|
|
148
|
-
return new Promise((
|
|
149
|
+
return new Promise((resolve47) => {
|
|
149
150
|
execFile("ps", ["-axo", "pid=,command="], { maxBuffer: 32 * 1024 * 1024 }, (err, stdout) => {
|
|
150
|
-
if (err) return
|
|
151
|
+
if (err) return resolve47([]);
|
|
151
152
|
const out = [];
|
|
152
153
|
for (const line of stdout.split("\n")) {
|
|
153
154
|
const m = line.match(/^\s*(\d+)\s+(.*)$/);
|
|
154
155
|
if (m) out.push({ pid: Number(m[1]), command: m[2] ?? "" });
|
|
155
156
|
}
|
|
156
|
-
|
|
157
|
+
resolve47(out);
|
|
157
158
|
});
|
|
158
159
|
});
|
|
159
160
|
}
|
|
@@ -523,7 +524,7 @@ function resolveSessionPricing(model) {
|
|
|
523
524
|
function tokenCost(tokens, pricePer1M) {
|
|
524
525
|
return tokens === void 0 ? 0 : tokens * pricePer1M / 1e6;
|
|
525
526
|
}
|
|
526
|
-
function deriveSessionUsage(input,
|
|
527
|
+
function deriveSessionUsage(input, resolve47 = defaultResolver) {
|
|
527
528
|
const contextUsed = plausibleContextUsed(input.contextSize, input.contextUsed);
|
|
528
529
|
const base = {
|
|
529
530
|
...input.model !== void 0 ? { model: input.model } : {},
|
|
@@ -538,7 +539,7 @@ function deriveSessionUsage(input, resolve45 = defaultResolver) {
|
|
|
538
539
|
}
|
|
539
540
|
const hasTokens = input.tokensIn !== void 0 || input.tokensOut !== void 0 || input.cacheReadTokens !== void 0 || input.cacheWriteTokens !== void 0;
|
|
540
541
|
if (hasTokens) {
|
|
541
|
-
const basePricing = input.model !== void 0 ?
|
|
542
|
+
const basePricing = input.model !== void 0 ? resolve47(input.model) : void 0;
|
|
542
543
|
if (!basePricing) {
|
|
543
544
|
return { ...base, source: "no-pricing" };
|
|
544
545
|
}
|
|
@@ -1045,8 +1046,8 @@ function createTranscriptWriter(opts) {
|
|
|
1045
1046
|
const state = states.get(sessionId);
|
|
1046
1047
|
if (!state) return Promise.resolve();
|
|
1047
1048
|
flushBuffers(sessionId, state);
|
|
1048
|
-
return new Promise((
|
|
1049
|
-
state.stream.write("", () =>
|
|
1049
|
+
return new Promise((resolve47) => {
|
|
1050
|
+
state.stream.write("", () => resolve47());
|
|
1050
1051
|
});
|
|
1051
1052
|
},
|
|
1052
1053
|
close(sessionId) {
|
|
@@ -1054,8 +1055,8 @@ function createTranscriptWriter(opts) {
|
|
|
1054
1055
|
if (!state) return Promise.resolve();
|
|
1055
1056
|
flushBuffers(sessionId, state);
|
|
1056
1057
|
states.delete(sessionId);
|
|
1057
|
-
return new Promise((
|
|
1058
|
-
state.stream.end(() =>
|
|
1058
|
+
return new Promise((resolve47) => {
|
|
1059
|
+
state.stream.end(() => resolve47());
|
|
1059
1060
|
});
|
|
1060
1061
|
},
|
|
1061
1062
|
closeAll() {
|
|
@@ -1064,7 +1065,7 @@ function createTranscriptWriter(opts) {
|
|
|
1064
1065
|
const state = states.get(sessionId);
|
|
1065
1066
|
if (!state) continue;
|
|
1066
1067
|
flushBuffers(sessionId, state);
|
|
1067
|
-
closings.push(new Promise((
|
|
1068
|
+
closings.push(new Promise((resolve47) => state.stream.end(() => resolve47())));
|
|
1068
1069
|
}
|
|
1069
1070
|
states.clear();
|
|
1070
1071
|
return Promise.all(closings).then(() => void 0);
|
|
@@ -1225,9 +1226,9 @@ async function exportClaudeCodeSession(adapterSessionId, cwd, configDir) {
|
|
|
1225
1226
|
let stream;
|
|
1226
1227
|
try {
|
|
1227
1228
|
stream = createReadStream(filePath, { encoding: "utf8" });
|
|
1228
|
-
await new Promise((
|
|
1229
|
+
await new Promise((resolve47, reject) => {
|
|
1229
1230
|
stream.once("error", reject);
|
|
1230
|
-
stream.once("open",
|
|
1231
|
+
stream.once("open", resolve47);
|
|
1231
1232
|
});
|
|
1232
1233
|
} catch (err) {
|
|
1233
1234
|
const code = err.code;
|
|
@@ -1501,7 +1502,7 @@ async function discoverHermesSessions(cwd, since, expectedId) {
|
|
|
1501
1502
|
}
|
|
1502
1503
|
async function defaultHermesRunner(adapterSessionId) {
|
|
1503
1504
|
const { spawn: spawn8 } = await import('child_process');
|
|
1504
|
-
return new Promise((
|
|
1505
|
+
return new Promise((resolve47, reject) => {
|
|
1505
1506
|
const chunks = [];
|
|
1506
1507
|
const errChunks = [];
|
|
1507
1508
|
const proc = spawn8(
|
|
@@ -1520,7 +1521,7 @@ async function defaultHermesRunner(adapterSessionId) {
|
|
|
1520
1521
|
)
|
|
1521
1522
|
);
|
|
1522
1523
|
} else {
|
|
1523
|
-
|
|
1524
|
+
resolve47(Buffer.concat(chunks).toString("utf8"));
|
|
1524
1525
|
}
|
|
1525
1526
|
});
|
|
1526
1527
|
});
|
|
@@ -1557,9 +1558,9 @@ async function exportDaemonEventsSession(sessionId, desc, baseDir) {
|
|
|
1557
1558
|
let stream;
|
|
1558
1559
|
try {
|
|
1559
1560
|
stream = createReadStream(filePath, { encoding: "utf8" });
|
|
1560
|
-
await new Promise((
|
|
1561
|
+
await new Promise((resolve47, reject) => {
|
|
1561
1562
|
stream.once("error", reject);
|
|
1562
|
-
stream.once("open",
|
|
1563
|
+
stream.once("open", resolve47);
|
|
1563
1564
|
});
|
|
1564
1565
|
} catch (err) {
|
|
1565
1566
|
const code = err.code;
|
|
@@ -1781,7 +1782,11 @@ async function readFirstJsonLine(path) {
|
|
|
1781
1782
|
function codexHome() {
|
|
1782
1783
|
return process.env.CODEX_HOME ?? join(homedir(), ".codex");
|
|
1783
1784
|
}
|
|
1784
|
-
function codexSessionsDir() {
|
|
1785
|
+
function codexSessionsDir(configDir) {
|
|
1786
|
+
if (configDir) {
|
|
1787
|
+
const isolated = join(configDir, "sessions");
|
|
1788
|
+
if (existsSync(isolated)) return isolated;
|
|
1789
|
+
}
|
|
1785
1790
|
return join(codexHome(), "sessions");
|
|
1786
1791
|
}
|
|
1787
1792
|
async function walkCodexRollouts(dir) {
|
|
@@ -1816,8 +1821,8 @@ function codexBlocksText(content) {
|
|
|
1816
1821
|
}
|
|
1817
1822
|
return acc;
|
|
1818
1823
|
}
|
|
1819
|
-
async function findCodexRolloutFile(conversationId) {
|
|
1820
|
-
const files = await walkCodexRollouts(codexSessionsDir());
|
|
1824
|
+
async function findCodexRolloutFile(conversationId, configDir) {
|
|
1825
|
+
const files = await walkCodexRollouts(codexSessionsDir(configDir));
|
|
1821
1826
|
const byName = files.find((f) => f.endsWith(`-${conversationId}.jsonl`));
|
|
1822
1827
|
if (byName) return byName;
|
|
1823
1828
|
for (const f of files) {
|
|
@@ -1834,11 +1839,11 @@ async function findCodexRolloutFile(conversationId) {
|
|
|
1834
1839
|
}
|
|
1835
1840
|
return void 0;
|
|
1836
1841
|
}
|
|
1837
|
-
async function exportCodexSession(conversationId) {
|
|
1838
|
-
const file = await findCodexRolloutFile(conversationId);
|
|
1842
|
+
async function exportCodexSession(conversationId, configDir) {
|
|
1843
|
+
const file = await findCodexRolloutFile(conversationId, configDir);
|
|
1839
1844
|
if (!file) {
|
|
1840
1845
|
throw new Error(
|
|
1841
|
-
`codex: no rollout file for conversation "${conversationId}" under ${codexSessionsDir()}.
|
|
1846
|
+
`codex: no rollout file for conversation "${conversationId}" under ${codexSessionsDir(configDir)}.
|
|
1842
1847
|
The session may predate persistence, or CODEX_HOME points elsewhere.`
|
|
1843
1848
|
);
|
|
1844
1849
|
}
|
|
@@ -2488,7 +2493,7 @@ var init_transcript_export = __esm({
|
|
|
2488
2493
|
exportSession: (id) => exportHermesSession(id)
|
|
2489
2494
|
},
|
|
2490
2495
|
codex: {
|
|
2491
|
-
exportSession: (id) => exportCodexSession(id)
|
|
2496
|
+
exportSession: (id, _cwd, configDir) => exportCodexSession(id, configDir)
|
|
2492
2497
|
},
|
|
2493
2498
|
opencode: {
|
|
2494
2499
|
exportSession: (id) => exportOpenCodeSession(id)
|
|
@@ -3907,8 +3912,8 @@ async function enrichWithRemainingQuota(rollup, opts) {
|
|
|
3907
3912
|
})
|
|
3908
3913
|
);
|
|
3909
3914
|
const capMs = opts.timeoutMs ?? DEFAULT_ENRICH_CAP_MS;
|
|
3910
|
-
const cap = new Promise((
|
|
3911
|
-
setTimeout(() =>
|
|
3915
|
+
const cap = new Promise((resolve47) => {
|
|
3916
|
+
setTimeout(() => resolve47(null), capMs);
|
|
3912
3917
|
});
|
|
3913
3918
|
const settled = await Promise.race([work, cap]);
|
|
3914
3919
|
if (settled === null) return rollup;
|
|
@@ -3972,8 +3977,8 @@ async function enrichWithAccountCredits(rollup, opts) {
|
|
|
3972
3977
|
})
|
|
3973
3978
|
);
|
|
3974
3979
|
const capMs = opts.timeoutMs ?? DEFAULT_ENRICH_CAP_MS;
|
|
3975
|
-
const cap = new Promise((
|
|
3976
|
-
setTimeout(() =>
|
|
3980
|
+
const cap = new Promise((resolve47) => {
|
|
3981
|
+
setTimeout(() => resolve47(null), capMs);
|
|
3977
3982
|
});
|
|
3978
3983
|
const settled = await Promise.race([work, cap]);
|
|
3979
3984
|
if (settled === null) return rollup;
|
|
@@ -4228,14 +4233,14 @@ function parseProcStat(statLine, cmdline, uid, ctx) {
|
|
|
4228
4233
|
};
|
|
4229
4234
|
}
|
|
4230
4235
|
function execPs(platform, timeoutMs) {
|
|
4231
|
-
return new Promise((
|
|
4236
|
+
return new Promise((resolve47, reject) => {
|
|
4232
4237
|
execFile(
|
|
4233
4238
|
"ps",
|
|
4234
4239
|
psArgs(platform),
|
|
4235
4240
|
// LC_ALL=C pins the decimal separator of `pcpu` to `.` regardless of the
|
|
4236
4241
|
// operator's locale.
|
|
4237
4242
|
{ maxBuffer: 32 * 1024 * 1024, timeout: timeoutMs, env: { ...process.env, LC_ALL: "C" } },
|
|
4238
|
-
(err, stdout) => err ? reject(new Error(`ps failed${err.killed ? " (timed out, host overloaded?)" : ""}: ${err.message.trim()}`)) :
|
|
4243
|
+
(err, stdout) => err ? reject(new Error(`ps failed${err.killed ? " (timed out, host overloaded?)" : ""}: ${err.message.trim()}`)) : resolve47(stdout)
|
|
4239
4244
|
);
|
|
4240
4245
|
});
|
|
4241
4246
|
}
|
|
@@ -4539,8 +4544,8 @@ function parseVmStatAvailable(text13) {
|
|
|
4539
4544
|
return total * Number(size[1]);
|
|
4540
4545
|
}
|
|
4541
4546
|
function execText(cmd, args) {
|
|
4542
|
-
return new Promise((
|
|
4543
|
-
execFile(cmd, args, { timeout: 3e3 }, (err, stdout) => err ? reject(err) :
|
|
4547
|
+
return new Promise((resolve47, reject) => {
|
|
4548
|
+
execFile(cmd, args, { timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve47(stdout));
|
|
4544
4549
|
});
|
|
4545
4550
|
}
|
|
4546
4551
|
function createProcessStatsService(opts = {}) {
|
|
@@ -4566,14 +4571,14 @@ function createProcessStatsService(opts = {}) {
|
|
|
4566
4571
|
nowMs: now()
|
|
4567
4572
|
}).claimedPids;
|
|
4568
4573
|
const byPid = new Map(rows.map((r) => [r.pid, r]));
|
|
4569
|
-
const
|
|
4574
|
+
const keyOf3 = (pid) => `${pid}:${Math.floor((now() - (byPid.get(pid)?.elapsedSec ?? 0) * 1e3) / 2e3)}`;
|
|
4570
4575
|
const candidates = strayEnvCandidates(rows, claimed, uid);
|
|
4571
|
-
const unread = candidates.filter((p) => !envMemo.has(
|
|
4576
|
+
const unread = candidates.filter((p) => !envMemo.has(keyOf3(p)));
|
|
4572
4577
|
const read = await readEnv(unread);
|
|
4573
|
-
for (const p of unread) envMemo.set(
|
|
4578
|
+
for (const p of unread) envMemo.set(keyOf3(p), read.get(p) ?? null);
|
|
4574
4579
|
const envHints = /* @__PURE__ */ new Map();
|
|
4575
4580
|
for (const p of candidates) {
|
|
4576
|
-
const h = envMemo.get(
|
|
4581
|
+
const h = envMemo.get(keyOf3(p));
|
|
4577
4582
|
if (h) envHints.set(p, h);
|
|
4578
4583
|
}
|
|
4579
4584
|
if (envMemo.size > 4096) envMemo.clear();
|
|
@@ -5419,9 +5424,9 @@ async function readFirstTurn(sessionId) {
|
|
|
5419
5424
|
let stream;
|
|
5420
5425
|
try {
|
|
5421
5426
|
stream = createReadStream(sessionEventsPath(sessionId), { encoding: "utf8" });
|
|
5422
|
-
await new Promise((
|
|
5427
|
+
await new Promise((resolve47, reject) => {
|
|
5423
5428
|
stream.once("error", reject);
|
|
5424
|
-
stream.once("open",
|
|
5429
|
+
stream.once("open", resolve47);
|
|
5425
5430
|
});
|
|
5426
5431
|
} catch {
|
|
5427
5432
|
return null;
|
|
@@ -9271,7 +9276,7 @@ async function* pollAgentOutputFallback(host, remoteSessionId, since) {
|
|
|
9271
9276
|
`sandbox proxy: ${consecutivePollFailures} consecutive poll failures against the box daemon (session "${remoteSessionId}") \u2014 giving up. Last error: ${pollErr instanceof Error ? pollErr.message : String(pollErr)}`
|
|
9272
9277
|
);
|
|
9273
9278
|
}
|
|
9274
|
-
await new Promise((
|
|
9279
|
+
await new Promise((resolve47) => setTimeout(resolve47, POLL_RETRY_DELAY_MS));
|
|
9275
9280
|
continue;
|
|
9276
9281
|
}
|
|
9277
9282
|
if (result.timedOut) continue;
|
|
@@ -9506,19 +9511,19 @@ async function startDeviceSandboxBridge(opts) {
|
|
|
9506
9511
|
}
|
|
9507
9512
|
}
|
|
9508
9513
|
const port = await getFreePort();
|
|
9509
|
-
await new Promise((
|
|
9514
|
+
await new Promise((resolve47, reject) => {
|
|
9510
9515
|
server.once("error", reject);
|
|
9511
|
-
server.listen(port, "127.0.0.1", () =>
|
|
9516
|
+
server.listen(port, "127.0.0.1", () => resolve47());
|
|
9512
9517
|
});
|
|
9513
9518
|
return {
|
|
9514
9519
|
mcpUrl: `http://127.0.0.1:${port}/mcp`,
|
|
9515
9520
|
async close() {
|
|
9516
|
-
await new Promise((
|
|
9521
|
+
await new Promise((resolve47) => server.close(() => resolve47()));
|
|
9517
9522
|
}
|
|
9518
9523
|
};
|
|
9519
9524
|
}
|
|
9520
9525
|
async function getFreePort() {
|
|
9521
|
-
return new Promise((
|
|
9526
|
+
return new Promise((resolve47, reject) => {
|
|
9522
9527
|
const srv = createServer$1();
|
|
9523
9528
|
srv.once("error", reject);
|
|
9524
9529
|
srv.listen(0, "127.0.0.1", () => {
|
|
@@ -9528,7 +9533,7 @@ async function getFreePort() {
|
|
|
9528
9533
|
return;
|
|
9529
9534
|
}
|
|
9530
9535
|
const { port } = address;
|
|
9531
|
-
srv.close(() =>
|
|
9536
|
+
srv.close(() => resolve47(port));
|
|
9532
9537
|
});
|
|
9533
9538
|
});
|
|
9534
9539
|
}
|
|
@@ -9673,7 +9678,7 @@ async function pollServeReady(url, opts) {
|
|
|
9673
9678
|
for (; ; ) {
|
|
9674
9679
|
if (await probe(url)) return true;
|
|
9675
9680
|
if (Date.now() >= deadline) return false;
|
|
9676
|
-
await new Promise((
|
|
9681
|
+
await new Promise((resolve47) => setTimeout(resolve47, intervalMs));
|
|
9677
9682
|
}
|
|
9678
9683
|
}
|
|
9679
9684
|
async function seedAllowlist(client) {
|
|
@@ -9798,7 +9803,7 @@ var init_sandbox_app_serve = __esm({
|
|
|
9798
9803
|
}
|
|
9799
9804
|
});
|
|
9800
9805
|
async function getFreePort2() {
|
|
9801
|
-
return new Promise((
|
|
9806
|
+
return new Promise((resolve47, reject) => {
|
|
9802
9807
|
const srv = createServer$1();
|
|
9803
9808
|
srv.once("error", reject);
|
|
9804
9809
|
srv.listen(0, "127.0.0.1", () => {
|
|
@@ -9808,7 +9813,7 @@ async function getFreePort2() {
|
|
|
9808
9813
|
return;
|
|
9809
9814
|
}
|
|
9810
9815
|
const { port } = address;
|
|
9811
|
-
srv.close(() =>
|
|
9816
|
+
srv.close(() => resolve47(port));
|
|
9812
9817
|
});
|
|
9813
9818
|
});
|
|
9814
9819
|
}
|
|
@@ -9821,7 +9826,7 @@ async function probeHealth(url, timeoutMs) {
|
|
|
9821
9826
|
} catch {
|
|
9822
9827
|
}
|
|
9823
9828
|
if (Date.now() >= deadline) return false;
|
|
9824
|
-
await new Promise((
|
|
9829
|
+
await new Promise((resolve47) => setTimeout(resolve47, POLL_INTERVAL_MS));
|
|
9825
9830
|
}
|
|
9826
9831
|
}
|
|
9827
9832
|
var HEALTH_TIMEOUT_MS, POLL_INTERVAL_MS, localSandboxProvider;
|
|
@@ -11398,8 +11403,8 @@ async function spawnAgentSession(deps2, input) {
|
|
|
11398
11403
|
}
|
|
11399
11404
|
let resolveClaim;
|
|
11400
11405
|
claims.set(key, {
|
|
11401
|
-
result: new Promise((
|
|
11402
|
-
resolveClaim =
|
|
11406
|
+
result: new Promise((resolve47) => {
|
|
11407
|
+
resolveClaim = resolve47;
|
|
11403
11408
|
}),
|
|
11404
11409
|
// An implicit claim expires sooner than an explicit one — see
|
|
11405
11410
|
// `IMPLICIT_SPAWN_CLAIM_WINDOW_MS`'s docblock.
|
|
@@ -11958,13 +11963,13 @@ async function isSharedDirtyCwd(cwd) {
|
|
|
11958
11963
|
const identity = resolveWorktreeIdentity(cwd);
|
|
11959
11964
|
if (identity?.worktreeId !== void 0) return false;
|
|
11960
11965
|
const { spawn: spawn8 } = await import('child_process');
|
|
11961
|
-
return await new Promise((
|
|
11966
|
+
return await new Promise((resolve47) => {
|
|
11962
11967
|
let stdout = "";
|
|
11963
11968
|
let settled = false;
|
|
11964
11969
|
const done = (v) => {
|
|
11965
11970
|
if (!settled) {
|
|
11966
11971
|
settled = true;
|
|
11967
|
-
|
|
11972
|
+
resolve47(v);
|
|
11968
11973
|
}
|
|
11969
11974
|
};
|
|
11970
11975
|
const child = spawn8("git", ["-C", cwd, "status", "--porcelain"], {
|
|
@@ -11979,15 +11984,15 @@ async function isSharedDirtyCwd(cwd) {
|
|
|
11979
11984
|
}
|
|
11980
11985
|
async function resolveMcpCredentialHeaders(mcpServers) {
|
|
11981
11986
|
if (!mcpServers || mcpServers.length === 0) return mcpServers;
|
|
11982
|
-
const { resolveMcpCredentialHeaders:
|
|
11983
|
-
if (!
|
|
11987
|
+
const { resolveMcpCredentialHeaders: resolve47 } = getMcpCredentialDeps();
|
|
11988
|
+
if (!resolve47) return mcpServers;
|
|
11984
11989
|
return Promise.all(
|
|
11985
11990
|
mcpServers.map(async (entry) => {
|
|
11986
11991
|
const ref = entry.credentialRef;
|
|
11987
11992
|
if (!ref) return entry;
|
|
11988
11993
|
let brokered;
|
|
11989
11994
|
try {
|
|
11990
|
-
brokered = await
|
|
11995
|
+
brokered = await resolve47({ credentialRef: ref });
|
|
11991
11996
|
} catch (err) {
|
|
11992
11997
|
console.warn(
|
|
11993
11998
|
`[agent_start] credentialRef resolution failed for "${entry.name}" (${ref}): ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -12083,7 +12088,7 @@ async function startDeviceSessionWithRetry(host, args, target) {
|
|
|
12083
12088
|
lastErr = err;
|
|
12084
12089
|
if (!isDeviceTransportError(err)) throw err;
|
|
12085
12090
|
if (attempt < attempts) {
|
|
12086
|
-
await new Promise((
|
|
12091
|
+
await new Promise((resolve47) => setTimeout(resolve47, DEVICE_SPAWN_RETRY_DELAY_MS));
|
|
12087
12092
|
}
|
|
12088
12093
|
}
|
|
12089
12094
|
}
|
|
@@ -12335,10 +12340,10 @@ function markFailedBootLedger(opts) {
|
|
|
12335
12340
|
}
|
|
12336
12341
|
}
|
|
12337
12342
|
async function resolveSandboxSecret(slug) {
|
|
12338
|
-
const { resolveSandboxSecret:
|
|
12339
|
-
if (!
|
|
12343
|
+
const { resolveSandboxSecret: resolve47 } = getMcpCredentialDeps();
|
|
12344
|
+
if (!resolve47) return null;
|
|
12340
12345
|
try {
|
|
12341
|
-
return await
|
|
12346
|
+
return await resolve47(slug);
|
|
12342
12347
|
} catch (err) {
|
|
12343
12348
|
console.warn(
|
|
12344
12349
|
`[agent_start] sandbox secret resolution failed for "${slug}": ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -13044,8 +13049,8 @@ async function readLogTailSafe(dir, n) {
|
|
|
13044
13049
|
async function resolveAppUiBuildState(input) {
|
|
13045
13050
|
const { dir, uiPath } = input;
|
|
13046
13051
|
const pending = peekInFlightBuild(uiPath) ?? ensureAppUiBuilt(input);
|
|
13047
|
-
const timeout = new Promise((
|
|
13048
|
-
const timer = setTimeout(() =>
|
|
13052
|
+
const timeout = new Promise((resolve47) => {
|
|
13053
|
+
const timer = setTimeout(() => resolve47(RESOLVE_TIMEOUT), RESOLVE_FAST_PATH_MS);
|
|
13049
13054
|
timer.unref();
|
|
13050
13055
|
});
|
|
13051
13056
|
const raced = await Promise.race([pending, timeout]);
|
|
@@ -16402,8 +16407,8 @@ function createTerminalTranscriptWriter(opts) {
|
|
|
16402
16407
|
const stream = streams.get(sessionId);
|
|
16403
16408
|
if (!stream) return Promise.resolve();
|
|
16404
16409
|
streams.delete(sessionId);
|
|
16405
|
-
return new Promise((
|
|
16406
|
-
stream.end(() =>
|
|
16410
|
+
return new Promise((resolve47) => {
|
|
16411
|
+
stream.end(() => resolve47());
|
|
16407
16412
|
});
|
|
16408
16413
|
},
|
|
16409
16414
|
closeAll() {
|
|
@@ -16412,8 +16417,8 @@ function createTerminalTranscriptWriter(opts) {
|
|
|
16412
16417
|
const stream = streams.get(sessionId);
|
|
16413
16418
|
if (!stream) continue;
|
|
16414
16419
|
closings.push(
|
|
16415
|
-
new Promise((
|
|
16416
|
-
stream.end(() =>
|
|
16420
|
+
new Promise((resolve47) => {
|
|
16421
|
+
stream.end(() => resolve47());
|
|
16417
16422
|
})
|
|
16418
16423
|
);
|
|
16419
16424
|
}
|
|
@@ -16860,8 +16865,8 @@ function createRegistryHandoffAsker(registry, desc, baseDir) {
|
|
|
16860
16865
|
const turn = registry.sendPrompt(sessionId, prompt, { source: HANDOFF_PROMPT_SOURCE });
|
|
16861
16866
|
let timer;
|
|
16862
16867
|
const timedOut = /* @__PURE__ */ Symbol("timeout");
|
|
16863
|
-
const deadline = new Promise((
|
|
16864
|
-
timer = setTimeout(() =>
|
|
16868
|
+
const deadline = new Promise((resolve47) => {
|
|
16869
|
+
timer = setTimeout(() => resolve47(timedOut), timeoutMs);
|
|
16865
16870
|
});
|
|
16866
16871
|
try {
|
|
16867
16872
|
const outcome = await Promise.race([turn, deadline]);
|
|
@@ -16876,7 +16881,7 @@ function createRegistryHandoffAsker(registry, desc, baseDir) {
|
|
|
16876
16881
|
for (let attempt = 0; attempt < REPLY_POLL_ATTEMPTS; attempt++) {
|
|
16877
16882
|
const reply = readLastAssistantTextSync(eventsPath2);
|
|
16878
16883
|
if (reply && reply !== before) return reply;
|
|
16879
|
-
await new Promise((
|
|
16884
|
+
await new Promise((resolve47) => setTimeout(resolve47, REPLY_POLL_MS));
|
|
16880
16885
|
}
|
|
16881
16886
|
throw new Error("source session produced no reply");
|
|
16882
16887
|
};
|
|
@@ -16980,14 +16985,14 @@ function buildRecentDigest(messages) {
|
|
|
16980
16985
|
}
|
|
16981
16986
|
async function captureGitStatus(cwd) {
|
|
16982
16987
|
if (!cwd) return void 0;
|
|
16983
|
-
return new Promise((
|
|
16988
|
+
return new Promise((resolve47) => {
|
|
16984
16989
|
execFile("git", ["status", "--porcelain"], { cwd }, (err, stdout) => {
|
|
16985
16990
|
if (err) {
|
|
16986
|
-
|
|
16991
|
+
resolve47(void 0);
|
|
16987
16992
|
return;
|
|
16988
16993
|
}
|
|
16989
16994
|
const trimmed = stdout.trim();
|
|
16990
|
-
|
|
16995
|
+
resolve47(trimmed || "(working tree clean)");
|
|
16991
16996
|
});
|
|
16992
16997
|
});
|
|
16993
16998
|
}
|
|
@@ -19135,11 +19140,11 @@ function createSessionsRegistry(opts) {
|
|
|
19135
19140
|
};
|
|
19136
19141
|
const waitForTurnSettled = (rt, id, caller) => {
|
|
19137
19142
|
if (!rt.busy) return Promise.resolve();
|
|
19138
|
-
return new Promise((
|
|
19143
|
+
return new Promise((resolve47, reject) => {
|
|
19139
19144
|
const onBusy = (busy) => {
|
|
19140
19145
|
if (busy) return;
|
|
19141
19146
|
cleanup();
|
|
19142
|
-
|
|
19147
|
+
resolve47();
|
|
19143
19148
|
};
|
|
19144
19149
|
const cleanup = () => {
|
|
19145
19150
|
clearTimeout(timer);
|
|
@@ -19217,9 +19222,9 @@ function createSessionsRegistry(opts) {
|
|
|
19217
19222
|
);
|
|
19218
19223
|
return;
|
|
19219
19224
|
}
|
|
19220
|
-
const
|
|
19221
|
-
if (
|
|
19222
|
-
await answerStructuredQuestion(liveRt,
|
|
19225
|
+
const answer2 = isChildPromptSource(next.source) ? void 0 : matchStructuredQuestionAnswer(liveRt, next.message);
|
|
19226
|
+
if (answer2) {
|
|
19227
|
+
await answerStructuredQuestion(liveRt, answer2);
|
|
19223
19228
|
return;
|
|
19224
19229
|
}
|
|
19225
19230
|
await runAgentTurn(
|
|
@@ -23034,14 +23039,14 @@ var init_pr_provenance_stamp = __esm({
|
|
|
23034
23039
|
init_pr_provenance();
|
|
23035
23040
|
defaultGhRunner = async (args, cwd) => {
|
|
23036
23041
|
const { spawn: spawn8 } = await import('child_process');
|
|
23037
|
-
return await new Promise((
|
|
23042
|
+
return await new Promise((resolve47) => {
|
|
23038
23043
|
let stdout = "";
|
|
23039
23044
|
const child = spawn8("gh", [...args], { cwd, shell: false });
|
|
23040
23045
|
child.stdout?.on("data", (d) => {
|
|
23041
23046
|
stdout += d.toString("utf8");
|
|
23042
23047
|
});
|
|
23043
|
-
child.on("error", () =>
|
|
23044
|
-
child.on("close", (code) =>
|
|
23048
|
+
child.on("error", () => resolve47({ exitCode: 1, stdout }));
|
|
23049
|
+
child.on("close", (code) => resolve47({ exitCode: code ?? 1, stdout }));
|
|
23045
23050
|
});
|
|
23046
23051
|
};
|
|
23047
23052
|
}
|
|
@@ -23575,6 +23580,19 @@ var init_command_tools = __esm({
|
|
|
23575
23580
|
}
|
|
23576
23581
|
});
|
|
23577
23582
|
|
|
23583
|
+
// src/liveness-tick-guard.ts
|
|
23584
|
+
function createLivenessTickGuard(intervalMs, graceMs, now = Date.now) {
|
|
23585
|
+
let last = now();
|
|
23586
|
+
return {
|
|
23587
|
+
shouldSkip() {
|
|
23588
|
+
const t = now();
|
|
23589
|
+
const late = t - last - intervalMs;
|
|
23590
|
+
last = t;
|
|
23591
|
+
return late > graceMs;
|
|
23592
|
+
}
|
|
23593
|
+
};
|
|
23594
|
+
}
|
|
23595
|
+
|
|
23578
23596
|
// src/index.ts
|
|
23579
23597
|
init_browser_mount();
|
|
23580
23598
|
async function writeRuntimeMeta(workspace, meta) {
|
|
@@ -25319,10 +25337,10 @@ function sandboxAuthForBox(auth) {
|
|
|
25319
25337
|
};
|
|
25320
25338
|
}
|
|
25321
25339
|
async function resolveSandboxSecretFromBroker(slug) {
|
|
25322
|
-
const { resolveSandboxSecret:
|
|
25323
|
-
if (!
|
|
25340
|
+
const { resolveSandboxSecret: resolve47 } = getMcpCredentialDeps();
|
|
25341
|
+
if (!resolve47) return null;
|
|
25324
25342
|
try {
|
|
25325
|
-
return await
|
|
25343
|
+
return await resolve47(slug);
|
|
25326
25344
|
} catch (err) {
|
|
25327
25345
|
console.warn(
|
|
25328
25346
|
`[restartAgentSession] sandbox secret resolution failed for "${slug}": ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -25916,6 +25934,12 @@ function createMcpObservationStore(opts = {}) {
|
|
|
25916
25934
|
const obs = touch(sessionId);
|
|
25917
25935
|
obs.httpError = { at: obs.lastSeenAt, status };
|
|
25918
25936
|
},
|
|
25937
|
+
recordResult(sessionId, method, message, clientProtocolVersion) {
|
|
25938
|
+
try {
|
|
25939
|
+
record2(sessionId, method, message, clientProtocolVersion);
|
|
25940
|
+
} catch {
|
|
25941
|
+
}
|
|
25942
|
+
},
|
|
25919
25943
|
get: (sessionId) => bySession.get(sessionId),
|
|
25920
25944
|
delete: (sessionId) => {
|
|
25921
25945
|
bySession.delete(sessionId);
|
|
@@ -26240,7 +26264,7 @@ async function runContinueOnBootPass(opts) {
|
|
|
26240
26264
|
|
|
26241
26265
|
// src/session-tools.ts
|
|
26242
26266
|
init_session_outcome();
|
|
26243
|
-
var defaultPsExecutor = () => new Promise((
|
|
26267
|
+
var defaultPsExecutor = () => new Promise((resolve47, reject) => {
|
|
26244
26268
|
if (process.platform === "win32") {
|
|
26245
26269
|
reject(new Error("processTreeRss: ps is not available on win32"));
|
|
26246
26270
|
return;
|
|
@@ -26251,7 +26275,7 @@ var defaultPsExecutor = () => new Promise((resolve45, reject) => {
|
|
|
26251
26275
|
{ maxBuffer: 16 * 1024 * 1024 },
|
|
26252
26276
|
(err, stdout) => {
|
|
26253
26277
|
if (err) reject(err);
|
|
26254
|
-
else
|
|
26278
|
+
else resolve47(stdout);
|
|
26255
26279
|
}
|
|
26256
26280
|
);
|
|
26257
26281
|
});
|
|
@@ -26646,15 +26670,15 @@ function computeHostWarnings(input) {
|
|
|
26646
26670
|
function createDefaultHostProbes() {
|
|
26647
26671
|
const platform = process.platform;
|
|
26648
26672
|
const own = /* @__PURE__ */ new Set();
|
|
26649
|
-
const run = (cmd, args, timeoutMs) => new Promise((
|
|
26673
|
+
const run = (cmd, args, timeoutMs) => new Promise((resolve47, reject) => {
|
|
26650
26674
|
const child = execFile(
|
|
26651
26675
|
cmd,
|
|
26652
26676
|
args,
|
|
26653
26677
|
{ maxBuffer: 16 * 1024 * 1024, timeout: timeoutMs, env: { ...process.env, LC_ALL: "C" } },
|
|
26654
26678
|
(err, stdout) => {
|
|
26655
|
-
if (!err) return
|
|
26679
|
+
if (!err) return resolve47(stdout);
|
|
26656
26680
|
if (err.killed) return reject(new Error(`${cmd} timed out after ${timeoutMs}ms`));
|
|
26657
|
-
return stdout ?
|
|
26681
|
+
return stdout ? resolve47(stdout) : reject(err);
|
|
26658
26682
|
}
|
|
26659
26683
|
);
|
|
26660
26684
|
if (child.pid !== void 0) own.add(child.pid);
|
|
@@ -27419,9 +27443,9 @@ async function callJevSystemOne(state, questions, opts) {
|
|
|
27419
27443
|
const answers = {};
|
|
27420
27444
|
const answerErrors = {};
|
|
27421
27445
|
for (const [key, value] of Object.entries(parsed.data.answers)) {
|
|
27422
|
-
const
|
|
27423
|
-
if (
|
|
27424
|
-
else answerErrors[key] = describeZodIssues(
|
|
27446
|
+
const answer2 = jevChoiceAnswerSchema.safeParse(value);
|
|
27447
|
+
if (answer2.success) answers[key] = answer2.data;
|
|
27448
|
+
else answerErrors[key] = describeZodIssues(answer2.error);
|
|
27425
27449
|
}
|
|
27426
27450
|
return {
|
|
27427
27451
|
ok: true,
|
|
@@ -27505,24 +27529,24 @@ async function judgeSessionWithJev(input) {
|
|
|
27505
27529
|
}
|
|
27506
27530
|
);
|
|
27507
27531
|
if (!outcome.ok) return fail4(outcome.error);
|
|
27508
|
-
const
|
|
27509
|
-
if (!
|
|
27532
|
+
const answer2 = outcome.answers[VERDICT_QUESTION_KEY];
|
|
27533
|
+
if (!answer2) {
|
|
27510
27534
|
const why = outcome.answerErrors?.[VERDICT_QUESTION_KEY];
|
|
27511
27535
|
return fail4(`response missing a valid verdict answer${why ? ` \u2014 ${why}` : ""}`);
|
|
27512
27536
|
}
|
|
27513
|
-
if (!WRAPUP_VERDICTS.includes(
|
|
27514
|
-
return fail4(`unknown verdict choice '${
|
|
27537
|
+
if (!WRAPUP_VERDICTS.includes(answer2.choice)) {
|
|
27538
|
+
return fail4(`unknown verdict choice '${answer2.choice}'`);
|
|
27515
27539
|
}
|
|
27516
|
-
const confidence =
|
|
27540
|
+
const confidence = answer2.confidence ?? answer2.probabilities[answer2.choice];
|
|
27517
27541
|
if (typeof confidence !== "number" || !Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
|
|
27518
27542
|
return fail4("no usable confidence for the chosen verdict");
|
|
27519
27543
|
}
|
|
27520
27544
|
return {
|
|
27521
27545
|
ok: true,
|
|
27522
27546
|
sessionId: input.sessionId,
|
|
27523
|
-
verdict:
|
|
27547
|
+
verdict: answer2.choice,
|
|
27524
27548
|
confidence,
|
|
27525
|
-
probabilities:
|
|
27549
|
+
probabilities: answer2.probabilities,
|
|
27526
27550
|
model: outcome.model ?? model
|
|
27527
27551
|
};
|
|
27528
27552
|
}
|
|
@@ -27723,7 +27747,6 @@ function createBackgroundJobRegistry(opts) {
|
|
|
27723
27747
|
jobId: job.id,
|
|
27724
27748
|
status: "running",
|
|
27725
27749
|
startedAt: job.startedAt,
|
|
27726
|
-
resultPath: resultPathFor(job.id),
|
|
27727
27750
|
followUp: { tool: followUp.tool, args: { jobId: job.id }, pollAfterMs: JOB_POLL_AFTER_MS, hint: followUp.hint }
|
|
27728
27751
|
}),
|
|
27729
27752
|
progressView: (job) => job.status === "failed" ? { jobId: job.id, status: job.status, endedAt: job.endedAt, error: job.error } : {
|
|
@@ -27731,22 +27754,86 @@ function createBackgroundJobRegistry(opts) {
|
|
|
27731
27754
|
status: job.status,
|
|
27732
27755
|
startedAt: job.startedAt,
|
|
27733
27756
|
elapsedMs: Date.now() - job.startedMs,
|
|
27734
|
-
resultPath: resultPathFor(job.id),
|
|
27735
27757
|
followUp: { pollAfterMs: JOB_POLL_AFTER_MS }
|
|
27736
27758
|
}
|
|
27737
27759
|
};
|
|
27738
27760
|
}
|
|
27739
27761
|
function timedOutWaiting(promise, waitMs) {
|
|
27740
|
-
return new Promise((
|
|
27741
|
-
const handle = setTimeout(() =>
|
|
27762
|
+
return new Promise((resolve47) => {
|
|
27763
|
+
const handle = setTimeout(() => resolve47(true), waitMs);
|
|
27742
27764
|
const settled = () => {
|
|
27743
27765
|
clearTimeout(handle);
|
|
27744
|
-
|
|
27766
|
+
resolve47(false);
|
|
27745
27767
|
};
|
|
27746
27768
|
promise.then(settled, settled);
|
|
27747
27769
|
});
|
|
27748
27770
|
}
|
|
27749
27771
|
|
|
27772
|
+
// src/branch-gc.ts
|
|
27773
|
+
function summarizeBranchGcApply(result) {
|
|
27774
|
+
const zero = () => ({ deleted: 0, skipped: 0, failed: 0 });
|
|
27775
|
+
const byScope = { local: zero(), remote: zero(), orphan: zero() };
|
|
27776
|
+
const totals = zero();
|
|
27777
|
+
const byResult = {};
|
|
27778
|
+
let aborted = 0;
|
|
27779
|
+
for (const o of result.outcomes) {
|
|
27780
|
+
byResult[o.result] = (byResult[o.result] ?? 0) + 1;
|
|
27781
|
+
const bucket = o.result === "deleted" ? "deleted" : o.result === "failed" ? "failed" : "skipped";
|
|
27782
|
+
byScope[o.kind][bucket]++;
|
|
27783
|
+
totals[bucket]++;
|
|
27784
|
+
if (o.result.startsWith("aborted-")) aborted++;
|
|
27785
|
+
}
|
|
27786
|
+
const status = totals.deleted === 0 ? totals.failed > 0 ? "failed" : "noop" : totals.failed > 0 || aborted > 0 ? "partial" : "ok";
|
|
27787
|
+
return { status, totals, byScope, byResult, restoreLog: result.restoreLog ?? null };
|
|
27788
|
+
}
|
|
27789
|
+
function withBranchGcApplySummary(result) {
|
|
27790
|
+
if (result.mode !== "apply") return result;
|
|
27791
|
+
const applySummary = summarizeBranchGcApply(result);
|
|
27792
|
+
return { ...result, status: applySummary.status, applySummary };
|
|
27793
|
+
}
|
|
27794
|
+
var BRANCH_GC_PAGE_DEFAULT = 100;
|
|
27795
|
+
var BRANCH_GC_PAGE_MAX = 500;
|
|
27796
|
+
var encodeOffset = (n) => Buffer.from(`o:${n}`).toString("base64url");
|
|
27797
|
+
function decodeOffset(cursor) {
|
|
27798
|
+
const m = /^o:(\d+)$/.exec(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
27799
|
+
if (!m) throw new Error("branch_gc_status: invalid `cursor`");
|
|
27800
|
+
return Number(m[1]);
|
|
27801
|
+
}
|
|
27802
|
+
function sliceBranchGcResult(result, opts) {
|
|
27803
|
+
const section = opts.section ?? (result.mode === "apply" ? "outcomes" : "entries");
|
|
27804
|
+
const scopeOk = (kind) => !opts.scopes?.length || opts.scopes.includes(kind);
|
|
27805
|
+
let rows;
|
|
27806
|
+
if (section === "outcomes") {
|
|
27807
|
+
if (result.mode !== "apply") throw new Error("branch_gc_status: `section: outcomes` is only available on an apply result");
|
|
27808
|
+
rows = result.outcomes.filter((o) => scopeOk(o.kind) && (!opts.results?.length || opts.results.includes(o.result)));
|
|
27809
|
+
} else {
|
|
27810
|
+
rows = result.plan.entries.filter(
|
|
27811
|
+
(e) => scopeOk(e.kind) && (!opts.classes?.length || opts.classes.includes(e.class))
|
|
27812
|
+
);
|
|
27813
|
+
}
|
|
27814
|
+
const limit = Math.min(Math.max(Math.trunc(opts.limit ?? BRANCH_GC_PAGE_DEFAULT), 1), BRANCH_GC_PAGE_MAX);
|
|
27815
|
+
const start = opts.cursor !== void 0 ? decodeOffset(opts.cursor) : 0;
|
|
27816
|
+
const pageRows = rows.slice(start, start + limit);
|
|
27817
|
+
const next = start + limit;
|
|
27818
|
+
const page = {
|
|
27819
|
+
section,
|
|
27820
|
+
total: rows.length,
|
|
27821
|
+
returned: pageRows.length,
|
|
27822
|
+
...next < rows.length ? { nextCursor: encodeOffset(next) } : {}
|
|
27823
|
+
};
|
|
27824
|
+
const { plan, ...rest } = result;
|
|
27825
|
+
const { entries: _entries, ...planMeta } = plan;
|
|
27826
|
+
const { outcomes: _outcomes, ...restNoOutcomes } = rest;
|
|
27827
|
+
return {
|
|
27828
|
+
page,
|
|
27829
|
+
result: {
|
|
27830
|
+
...restNoOutcomes,
|
|
27831
|
+
plan: section === "entries" ? { ...planMeta, entries: pageRows } : planMeta,
|
|
27832
|
+
...section === "outcomes" ? { outcomes: pageRows } : {}
|
|
27833
|
+
}
|
|
27834
|
+
};
|
|
27835
|
+
}
|
|
27836
|
+
|
|
27750
27837
|
// src/session-tools.ts
|
|
27751
27838
|
init_command_allowlist();
|
|
27752
27839
|
init_agent_tools();
|
|
@@ -28366,25 +28453,27 @@ var sessionWrapupApplyJobs = createBackgroundJobRegistry({
|
|
|
28366
28453
|
var BACKGROUND_DEFAULT_WAIT_MS = 25e3;
|
|
28367
28454
|
var branchGcBackgroundView = (job) => branchGcJobs.backgroundView(job, {
|
|
28368
28455
|
tool: "branch_gc_status",
|
|
28369
|
-
hint: "Running in the background; a plan on a large repo takes a few minutes. Call branch_gc_status with this jobId about every 30 s. When done it returns the summary
|
|
28456
|
+
hint: "Running in the background; a plan on a large repo takes a few minutes. Call branch_gc_status with this jobId about every 30 s. When done it returns the summary and, once the file exists, a resultPath holding the full result (pass full: true to get a filtered/paged slice inline)."
|
|
28370
28457
|
});
|
|
28371
|
-
var branchGcDoneView = (jobId, resultPath, result,
|
|
28458
|
+
var branchGcDoneView = (jobId, resultPath, result, slice, endedAt) => ({
|
|
28372
28459
|
jobId,
|
|
28373
28460
|
status: "done",
|
|
28374
28461
|
...endedAt !== void 0 ? { endedAt } : {},
|
|
28375
|
-
resultPath,
|
|
28462
|
+
...resultPath !== void 0 ? { resultPath } : {},
|
|
28376
28463
|
summary: result.summary,
|
|
28377
|
-
// Apply results carry the restore log path
|
|
28378
|
-
// exactly what a caller needs
|
|
28379
|
-
// full ~MB result with `full: true`.
|
|
28464
|
+
// Apply results carry the restore log path, a per-outcome tally and the
|
|
28465
|
+
// per-scope deleted/skipped/failed summary — exactly what a caller needs
|
|
28466
|
+
// to decide "safe?" without fetching the full ~MB result with `full: true`.
|
|
28467
|
+
// Result files written before `applySummary` existed are summarised here.
|
|
28380
28468
|
...result.mode === "apply" ? {
|
|
28381
28469
|
restoreLog: result.restoreLog ?? null,
|
|
28382
28470
|
outcomeCounts: result.outcomes.reduce((acc, o) => {
|
|
28383
28471
|
acc[o.result] = (acc[o.result] ?? 0) + 1;
|
|
28384
28472
|
return acc;
|
|
28385
|
-
}, {})
|
|
28473
|
+
}, {}),
|
|
28474
|
+
applySummary: result.applySummary ?? summarizeBranchGcApply(result)
|
|
28386
28475
|
} : {},
|
|
28387
|
-
...
|
|
28476
|
+
...slice ? sliceBranchGcResult(result, slice) : {}
|
|
28388
28477
|
});
|
|
28389
28478
|
var worktreeGcBackgroundView = (job) => worktreeGcJobs.backgroundView(job, {
|
|
28390
28479
|
tool: "worktree_gc_status",
|
|
@@ -28424,7 +28513,7 @@ var backgroundStatusResult = async (toolName, jobs, jobId) => {
|
|
|
28424
28513
|
jobId: job.id,
|
|
28425
28514
|
status: "done",
|
|
28426
28515
|
endedAt: job.endedAt,
|
|
28427
|
-
resultPath:
|
|
28516
|
+
...job.resultPath !== void 0 ? { resultPath: job.resultPath } : {},
|
|
28428
28517
|
result: job.result
|
|
28429
28518
|
})
|
|
28430
28519
|
}
|
|
@@ -28471,7 +28560,8 @@ function registerSessionTools(rawServer, opts) {
|
|
|
28471
28560
|
project: args.project,
|
|
28472
28561
|
keyOf: args.keyOf,
|
|
28473
28562
|
maxLimit: 200,
|
|
28474
|
-
itemKey: args.itemKey
|
|
28563
|
+
itemKey: args.itemKey,
|
|
28564
|
+
...args.defaultLimit !== void 0 ? { defaultLimit: args.defaultLimit } : {}
|
|
28475
28565
|
})
|
|
28476
28566
|
]
|
|
28477
28567
|
});
|
|
@@ -29218,7 +29308,7 @@ function registerSessionTools(rawServer, opts) {
|
|
|
29218
29308
|
});
|
|
29219
29309
|
registerPaginatedListTool({
|
|
29220
29310
|
id: "terminal_sessions_list",
|
|
29221
|
-
description: "List terminal/PTY sessions tracked by the daemon. Equivalent to `session_list({kind: 'terminal'})`. Each entry includes `kind`, `pty`, `status`, age, etc. Use this when you only want the terminal subset. COMPACT BY DEFAULT: each entry is session_list's slim projection; pass `full: true` (or `compact: false`) for the complete, unprojected per-session record.",
|
|
29311
|
+
description: "List terminal/PTY sessions tracked by the daemon. Equivalent to `session_list({kind: 'terminal'})`. Each entry includes `kind`, `pty`, `status`, age, etc. Use this when you only want the terminal subset. COMPACT BY DEFAULT: each entry is session_list's slim projection; pass `full: true` (or `compact: false`) for the complete, unprojected per-session record. Without `limit`/`cursor` at most 50 rows come back; when there are more the reply carries `total`, `truncated: true` and a `nextCursor` \u2014 pass it as `cursor` (with a `limit`) for the rest, or filter with `onlyAlive` / `status`.",
|
|
29222
29312
|
schema: terminalSessionsListSchema,
|
|
29223
29313
|
body: async (input) => {
|
|
29224
29314
|
let rows = registry.list({ includeArchived: true });
|
|
@@ -29242,7 +29332,10 @@ function registerSessionTools(rawServer, opts) {
|
|
|
29242
29332
|
},
|
|
29243
29333
|
project: compactSessionItemWithProvenance,
|
|
29244
29334
|
keyOf: (s) => s.id,
|
|
29245
|
-
itemKey: "sessions"
|
|
29335
|
+
itemKey: "sessions",
|
|
29336
|
+
// Dead terminals pile up: an unpaged call used to return every row
|
|
29337
|
+
// (65k+ chars, over the MCP output cap). Cap it and say so.
|
|
29338
|
+
defaultLimit: 50
|
|
29246
29339
|
});
|
|
29247
29340
|
const commandListSchema = z.object({
|
|
29248
29341
|
kind: z.enum(["terminal", "agent-cli", "command", "all"]).optional().describe(
|
|
@@ -30124,7 +30217,7 @@ function registerSessionTools(rawServer, opts) {
|
|
|
30124
30217
|
const branchGcKind = z.enum(["local", "remote", "orphan"]);
|
|
30125
30218
|
server.tool(
|
|
30126
30219
|
"branch_gc",
|
|
30127
|
-
"Garbage-collect a repo's branches. DEFAULTS TO A DRY RUN: returns a plan classifying every local branch, base-remote branch and orphan tracking ref (refs/remotes/<ns>/* of a removed remote) as `reclaim` (work provably in base: the head commit of a merged PR, merged, squash-merged, patch-merged or content-merged), `review` (unmerged, old enough, not protected \u2014 carries coverage + the files not provably in base for a reviewer), or `hold` (base/protected, checked out in a worktree or its remote twin, open PR head, PR check unavailable, or younger than `minAgeDays`). `apply: true` (requires explicit `scopes`) deletes only `reclaim` entries, re-classifying each right before deleting it, and returns the path of a restore log (sha + re-create command per deleted ref). A plan can take minutes on a big repo: as an MCP caller, pass `wait: false` (or `waitMs: 40000`) and poll `branch_gc_status` with the returned jobId instead of blocking. A `wait: false` (or `waitMs` timed-out) response returns a jobId plus a `followUp` block naming the poll tool and cadence \u2014 poll `branch_gc_status` with that jobId.",
|
|
30220
|
+
"Garbage-collect a repo's branches. DEFAULTS TO A DRY RUN: returns a plan classifying every local branch, base-remote branch and orphan tracking ref (refs/remotes/<ns>/* of a removed remote) as `reclaim` (work provably in base: the head commit of a merged PR, merged, squash-merged, patch-merged or content-merged), `review` (unmerged, old enough, not protected \u2014 carries coverage + the files not provably in base for a reviewer), or `hold` (base/protected, checked out in a worktree or its remote twin, open PR head, PR check unavailable, or younger than `minAgeDays`). `apply: true` (requires explicit `scopes`) deletes only `reclaim` entries, re-classifying each right before deleting it, and returns the path of a restore log (sha + re-create command per deleted ref) plus a top-level `status` and an `applySummary` (deleted / skipped / failed counts per scope, and the restore log path). A plan can take minutes on a big repo: as an MCP caller, pass `wait: false` (or `waitMs: 40000`) and poll `branch_gc_status` with the returned jobId instead of blocking. A `wait: false` (or `waitMs` timed-out) response returns a jobId plus a `followUp` block naming the poll tool and cadence \u2014 poll `branch_gc_status` with that jobId.",
|
|
30128
30221
|
{
|
|
30129
30222
|
repoRoot: z.string().optional().describe("Absolute path to the git repo. Wins over `workspaceSlug`."),
|
|
30130
30223
|
workspaceSlug: z.string().optional().describe("Workspace slug from `agentproto workspace list`. The active workspace when omitted."),
|
|
@@ -30174,7 +30267,7 @@ function registerSessionTools(rawServer, opts) {
|
|
|
30174
30267
|
...input.minAgeDays !== void 0 ? { minAgeDays: input.minAgeDays } : {},
|
|
30175
30268
|
...input.anchor ? { anchor: input.anchor } : {}
|
|
30176
30269
|
};
|
|
30177
|
-
const { job, promise } = branchGcJobs.start(() => runBranchGc(runInput));
|
|
30270
|
+
const { job, promise } = branchGcJobs.start(async () => withBranchGcApplySummary(await runBranchGc(runInput)));
|
|
30178
30271
|
if (input.wait === false) {
|
|
30179
30272
|
return { content: [{ type: "text", text: JSON.stringify(branchGcBackgroundView(job)) }] };
|
|
30180
30273
|
}
|
|
@@ -30193,12 +30286,36 @@ function registerSessionTools(rawServer, opts) {
|
|
|
30193
30286
|
);
|
|
30194
30287
|
server.tool(
|
|
30195
30288
|
"branch_gc_status",
|
|
30196
|
-
|
|
30289
|
+
'Poll a branch_gc run started with `wait: false` (or one that fell back to the background via `waitMs`). While running: status + elapsed time. When done: the plan\'s own summary (plus, for an apply, `applySummary` \u2014 deleted/skipped/failed per scope and the restore log path) and the path of the full result saved on disk (`resultPath`). The full result is too big to return whole, so `full: true` (or any of `section`, `classes`, `scopes`, `results`, `limit`, `cursor`) returns ONE filtered page of it: `result` (summary + plan metadata + the selected list) and `page { section, total, returned, nextCursor }` \u2014 default 100 rows, pass `nextCursor` back as `cursor` for the next page. Use `classes: ["reclaim"]` to see only what an apply would delete. While running the view carries `followUp.pollAfterMs` (poll every 30 s). When failed: the error.',
|
|
30197
30290
|
{
|
|
30198
30291
|
jobId: z.string().describe("Job id returned by `branch_gc` (`bgc_\u2026`)."),
|
|
30199
|
-
full: mcpBool2.optional().describe("Include the full result
|
|
30292
|
+
full: mcpBool2.optional().describe("Include a filtered/paged slice of the full result (see description). Implied by any other slice param. Default false."),
|
|
30293
|
+
section: z.enum(["entries", "outcomes"]).optional().describe("Which list to return: plan `entries` or apply `outcomes`. Default `entries` for a plan, `outcomes` for an apply."),
|
|
30294
|
+
classes: z.array(z.enum(["reclaim", "review", "hold"])).optional().describe('Entries only: keep these classes (e.g. ["reclaim"]).'),
|
|
30295
|
+
scopes: z.array(branchGcKind).optional().describe("Keep these ref kinds (local, remote, orphan)."),
|
|
30296
|
+
results: z.array(
|
|
30297
|
+
z.enum(["deleted", "held", "skipped-review", "aborted-moved", "aborted-vanished", "aborted-reclassified", "failed"])
|
|
30298
|
+
).optional().describe("Outcomes only: keep these outcome results."),
|
|
30299
|
+
limit: mcpNumber.optional().describe(`Rows per page. Default 100, max ${BRANCH_GC_PAGE_MAX}.`),
|
|
30300
|
+
cursor: z.string().optional().describe("`page.nextCursor` from the previous page.")
|
|
30200
30301
|
},
|
|
30201
30302
|
async (input) => {
|
|
30303
|
+
const wantsSlice = input.full === true || input.section !== void 0 || input.classes !== void 0 || input.scopes !== void 0 || input.results !== void 0 || input.limit !== void 0 || input.cursor !== void 0;
|
|
30304
|
+
const slice = wantsSlice ? {
|
|
30305
|
+
...input.section ? { section: input.section } : {},
|
|
30306
|
+
...input.classes ? { classes: input.classes } : {},
|
|
30307
|
+
...input.scopes ? { scopes: input.scopes } : {},
|
|
30308
|
+
...input.results ? { results: input.results } : {},
|
|
30309
|
+
...input.limit !== void 0 ? { limit: input.limit } : {},
|
|
30310
|
+
...input.cursor !== void 0 ? { cursor: input.cursor } : {}
|
|
30311
|
+
} : void 0;
|
|
30312
|
+
const doneView = (...args) => {
|
|
30313
|
+
try {
|
|
30314
|
+
return { content: [{ type: "text", text: JSON.stringify(branchGcDoneView(...args)) }] };
|
|
30315
|
+
} catch (err) {
|
|
30316
|
+
return { content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }], isError: true };
|
|
30317
|
+
}
|
|
30318
|
+
};
|
|
30202
30319
|
const job = branchGcJobs.get(input.jobId);
|
|
30203
30320
|
if (!job) {
|
|
30204
30321
|
const parsed = await branchGcJobs.readResultFile(input.jobId);
|
|
@@ -30213,14 +30330,12 @@ function registerSessionTools(rawServer, opts) {
|
|
|
30213
30330
|
isError: true
|
|
30214
30331
|
};
|
|
30215
30332
|
}
|
|
30216
|
-
|
|
30217
|
-
return { content: [{ type: "text", text: JSON.stringify(view3) }] };
|
|
30333
|
+
return doneView(input.jobId, branchGcJobs.resultPathFor(input.jobId), parsed, slice);
|
|
30218
30334
|
}
|
|
30219
30335
|
if (job.status !== "done") {
|
|
30220
30336
|
return { content: [{ type: "text", text: JSON.stringify(branchGcJobs.progressView(job)) }] };
|
|
30221
30337
|
}
|
|
30222
|
-
|
|
30223
|
-
return { content: [{ type: "text", text: JSON.stringify(view2) }] };
|
|
30338
|
+
return doneView(job.id, job.resultPath, job.result, slice, job.endedAt);
|
|
30224
30339
|
}
|
|
30225
30340
|
);
|
|
30226
30341
|
const branchVerdictEnum = z.enum(["obsolete", "superseded", "salvage", "in-progress", "unclear"]);
|
|
@@ -32318,7 +32433,7 @@ function createWorkspaceBrainSubscriber(opts) {
|
|
|
32318
32433
|
}
|
|
32319
32434
|
};
|
|
32320
32435
|
}
|
|
32321
|
-
function makeBrowserHandle(entry,
|
|
32436
|
+
function makeBrowserHandle(entry, resolve47) {
|
|
32322
32437
|
return {
|
|
32323
32438
|
slug: entry.id,
|
|
32324
32439
|
name: entry.name,
|
|
@@ -32329,7 +32444,7 @@ function makeBrowserHandle(entry, resolve45) {
|
|
|
32329
32444
|
// check() is available for on-demand health probes but is never called
|
|
32330
32445
|
// by the lister (kit invariant OQ-5). Returns true when the adapter
|
|
32331
32446
|
// is present in the injected resolver map, false otherwise.
|
|
32332
|
-
check: async () =>
|
|
32447
|
+
check: async () => resolve47 ? resolve47(entry.id) != null : true
|
|
32333
32448
|
};
|
|
32334
32449
|
}
|
|
32335
32450
|
var noopLedger = {
|
|
@@ -34936,7 +35051,7 @@ function startHeartbeat(opts) {
|
|
|
34936
35051
|
let timer = null;
|
|
34937
35052
|
let currentEveryMs = null;
|
|
34938
35053
|
let firing = false;
|
|
34939
|
-
async function
|
|
35054
|
+
async function load2() {
|
|
34940
35055
|
if (!existsSync(path)) return null;
|
|
34941
35056
|
let source;
|
|
34942
35057
|
try {
|
|
@@ -34967,7 +35082,7 @@ function startHeartbeat(opts) {
|
|
|
34967
35082
|
firing = true;
|
|
34968
35083
|
let agentId;
|
|
34969
35084
|
try {
|
|
34970
|
-
const hb = await
|
|
35085
|
+
const hb = await load2();
|
|
34971
35086
|
if (!hb || !hb.enabled) return;
|
|
34972
35087
|
agentId = hb.agent;
|
|
34973
35088
|
const agent = await opts.buildAgent(hb.agent);
|
|
@@ -35055,7 +35170,7 @@ function startHeartbeat(opts) {
|
|
|
35055
35170
|
return {
|
|
35056
35171
|
start() {
|
|
35057
35172
|
if (timer) return;
|
|
35058
|
-
void
|
|
35173
|
+
void load2().then((hb) => {
|
|
35059
35174
|
const everyMs = hb?.everyMs ?? 6e4;
|
|
35060
35175
|
reschedule(everyMs);
|
|
35061
35176
|
});
|
|
@@ -35104,6 +35219,356 @@ function preview(text13, max = 120) {
|
|
|
35104
35219
|
// src/http-server.ts
|
|
35105
35220
|
init_process_stats();
|
|
35106
35221
|
init_browser_mount();
|
|
35222
|
+
|
|
35223
|
+
// src/mcp-modern/constants.ts
|
|
35224
|
+
var MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
35225
|
+
var DEFAULT_SUPPORTED_VERSIONS = [MODERN_PROTOCOL_VERSION];
|
|
35226
|
+
var META_PROTOCOL_VERSION = "io.modelcontextprotocol/protocolVersion";
|
|
35227
|
+
var META_CLIENT_INFO = "io.modelcontextprotocol/clientInfo";
|
|
35228
|
+
var META_CLIENT_CAPABILITIES = "io.modelcontextprotocol/clientCapabilities";
|
|
35229
|
+
var META_SERVER_INFO = "io.modelcontextprotocol/serverInfo";
|
|
35230
|
+
var ERR_PARSE = -32700;
|
|
35231
|
+
var ERR_INVALID_REQUEST = -32600;
|
|
35232
|
+
var ERR_METHOD_NOT_FOUND = -32601;
|
|
35233
|
+
var ERR_INVALID_PARAMS = -32602;
|
|
35234
|
+
var ERR_INTERNAL = -32603;
|
|
35235
|
+
var ERR_HEADER_MISMATCH = -32020;
|
|
35236
|
+
var ERR_UNSUPPORTED_VERSION = -32022;
|
|
35237
|
+
var FORWARDED_METHODS = /* @__PURE__ */ new Set([
|
|
35238
|
+
"tools/list",
|
|
35239
|
+
"tools/call",
|
|
35240
|
+
"events/list",
|
|
35241
|
+
"events/subscribe",
|
|
35242
|
+
"events/unsubscribe",
|
|
35243
|
+
"resources/list",
|
|
35244
|
+
"resources/templates/list",
|
|
35245
|
+
"resources/read",
|
|
35246
|
+
"prompts/list",
|
|
35247
|
+
"prompts/get"
|
|
35248
|
+
]);
|
|
35249
|
+
var ALLOWED_METHODS = /* @__PURE__ */ new Set([...FORWARDED_METHODS, "server/discover"]);
|
|
35250
|
+
var CACHE_HINT_METHODS = /* @__PURE__ */ new Set([
|
|
35251
|
+
"server/discover",
|
|
35252
|
+
"tools/list",
|
|
35253
|
+
"prompts/list",
|
|
35254
|
+
"resources/list",
|
|
35255
|
+
"resources/templates/list",
|
|
35256
|
+
"resources/read"
|
|
35257
|
+
]);
|
|
35258
|
+
var NAME_HEADER_SOURCE = /* @__PURE__ */ new Map([
|
|
35259
|
+
["tools/call", "name"],
|
|
35260
|
+
["prompts/get", "name"],
|
|
35261
|
+
["resources/read", "uri"]
|
|
35262
|
+
]);
|
|
35263
|
+
|
|
35264
|
+
// src/mcp-modern/bridge.ts
|
|
35265
|
+
var HANDSHAKE_VERSION = "2025-11-25";
|
|
35266
|
+
var BridgeError = class extends Error {
|
|
35267
|
+
code;
|
|
35268
|
+
data;
|
|
35269
|
+
constructor(code, message, data) {
|
|
35270
|
+
super(message);
|
|
35271
|
+
this.code = code;
|
|
35272
|
+
this.data = data;
|
|
35273
|
+
}
|
|
35274
|
+
};
|
|
35275
|
+
function forwardParams(params) {
|
|
35276
|
+
const { _meta, ...rest } = params;
|
|
35277
|
+
if (typeof _meta !== "object" || _meta === null || Array.isArray(_meta)) return rest;
|
|
35278
|
+
const handshake = /* @__PURE__ */ new Set([META_PROTOCOL_VERSION, META_CLIENT_INFO, META_CLIENT_CAPABILITIES]);
|
|
35279
|
+
const kept = Object.fromEntries(Object.entries(_meta).filter(([key]) => !handshake.has(key)));
|
|
35280
|
+
return Object.keys(kept).length > 0 ? { ...rest, _meta: kept } : rest;
|
|
35281
|
+
}
|
|
35282
|
+
var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
35283
|
+
async function openBridge(server) {
|
|
35284
|
+
const [clientSide, serverSide] = InMemoryTransport.createLinkedPair();
|
|
35285
|
+
const pending = /* @__PURE__ */ new Map();
|
|
35286
|
+
let nextId = 1;
|
|
35287
|
+
clientSide.onmessage = (message) => {
|
|
35288
|
+
if (!("id" in message) || typeof message.id !== "number") return;
|
|
35289
|
+
const entry = pending.get(message.id);
|
|
35290
|
+
if (!entry) return;
|
|
35291
|
+
if ("error" in message) {
|
|
35292
|
+
pending.delete(message.id);
|
|
35293
|
+
entry.reject(new BridgeError(message.error.code, message.error.message, message.error.data));
|
|
35294
|
+
} else if ("result" in message) {
|
|
35295
|
+
pending.delete(message.id);
|
|
35296
|
+
entry.resolve(isRecord7(message.result) ? message.result : {});
|
|
35297
|
+
}
|
|
35298
|
+
};
|
|
35299
|
+
const close = async () => {
|
|
35300
|
+
for (const entry of pending.values()) entry.reject(new Error("bridge closed"));
|
|
35301
|
+
pending.clear();
|
|
35302
|
+
await clientSide.close().catch(() => {
|
|
35303
|
+
});
|
|
35304
|
+
await server.close().catch(() => {
|
|
35305
|
+
});
|
|
35306
|
+
};
|
|
35307
|
+
const call = (method, params, signal) => new Promise((resolve47, reject) => {
|
|
35308
|
+
if (signal?.aborted) {
|
|
35309
|
+
reject(signal.reason ?? new Error("aborted"));
|
|
35310
|
+
return;
|
|
35311
|
+
}
|
|
35312
|
+
const id = nextId++;
|
|
35313
|
+
const onAbort = () => {
|
|
35314
|
+
pending.delete(id);
|
|
35315
|
+
void clientSide.send({ jsonrpc: "2.0", method: "notifications/cancelled", params: { requestId: id, reason: "client disconnected" } }).catch(() => {
|
|
35316
|
+
});
|
|
35317
|
+
reject(signal?.reason ?? new Error("aborted"));
|
|
35318
|
+
};
|
|
35319
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
35320
|
+
pending.set(id, {
|
|
35321
|
+
resolve: (value) => {
|
|
35322
|
+
signal?.removeEventListener("abort", onAbort);
|
|
35323
|
+
resolve47(value);
|
|
35324
|
+
},
|
|
35325
|
+
reject: (error) => {
|
|
35326
|
+
signal?.removeEventListener("abort", onAbort);
|
|
35327
|
+
reject(error);
|
|
35328
|
+
}
|
|
35329
|
+
});
|
|
35330
|
+
clientSide.send({ jsonrpc: "2.0", id, method, params }).catch((error) => {
|
|
35331
|
+
pending.delete(id);
|
|
35332
|
+
signal?.removeEventListener("abort", onAbort);
|
|
35333
|
+
reject(error);
|
|
35334
|
+
});
|
|
35335
|
+
});
|
|
35336
|
+
try {
|
|
35337
|
+
await server.connect(serverSide);
|
|
35338
|
+
await clientSide.start();
|
|
35339
|
+
const init = await call("initialize", {
|
|
35340
|
+
protocolVersion: HANDSHAKE_VERSION,
|
|
35341
|
+
capabilities: {},
|
|
35342
|
+
clientInfo: { name: "agentproto-modern-bridge", version: "0.0.1" }
|
|
35343
|
+
});
|
|
35344
|
+
await clientSide.send({ jsonrpc: "2.0", method: "notifications/initialized" });
|
|
35345
|
+
const info = isRecord7(init.serverInfo) ? init.serverInfo : {};
|
|
35346
|
+
return {
|
|
35347
|
+
capabilities: isRecord7(init.capabilities) ? { ...init.capabilities } : {},
|
|
35348
|
+
serverInfo: {
|
|
35349
|
+
name: typeof info.name === "string" ? info.name : "agentproto",
|
|
35350
|
+
version: typeof info.version === "string" ? info.version : "0"
|
|
35351
|
+
},
|
|
35352
|
+
instructions: typeof init.instructions === "string" ? init.instructions : void 0,
|
|
35353
|
+
request: call,
|
|
35354
|
+
close
|
|
35355
|
+
};
|
|
35356
|
+
} catch (error) {
|
|
35357
|
+
await close();
|
|
35358
|
+
throw error;
|
|
35359
|
+
}
|
|
35360
|
+
}
|
|
35361
|
+
|
|
35362
|
+
// src/mcp-modern/validate.ts
|
|
35363
|
+
var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
35364
|
+
function normalizeHeaders(raw) {
|
|
35365
|
+
const out = {};
|
|
35366
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
35367
|
+
if (value === void 0) continue;
|
|
35368
|
+
const joined = (Array.isArray(value) ? value.join(", ") : value).trim();
|
|
35369
|
+
const key = name.toLowerCase();
|
|
35370
|
+
const previous = out[key];
|
|
35371
|
+
out[key] = previous === void 0 ? joined : `${previous}, ${joined}`;
|
|
35372
|
+
}
|
|
35373
|
+
return out;
|
|
35374
|
+
}
|
|
35375
|
+
function acceptsJson(accept) {
|
|
35376
|
+
if (accept === void 0) return false;
|
|
35377
|
+
return accept.split(",").some((part) => {
|
|
35378
|
+
const type = (part.split(";")[0] ?? "").trim().toLowerCase();
|
|
35379
|
+
return type === "application/json" || type === "application/*" || type === "*/*";
|
|
35380
|
+
});
|
|
35381
|
+
}
|
|
35382
|
+
function isJsonContentType(contentType) {
|
|
35383
|
+
if (contentType === void 0) return false;
|
|
35384
|
+
return (contentType.split(";")[0] ?? "").trim().toLowerCase() === "application/json";
|
|
35385
|
+
}
|
|
35386
|
+
function decodeHeaderValue(raw) {
|
|
35387
|
+
const match = /^=\?base64\?(.*)\?=$/.exec(raw);
|
|
35388
|
+
if (!match) return raw;
|
|
35389
|
+
return Buffer.from(match[1] ?? "", "base64").toString("utf8");
|
|
35390
|
+
}
|
|
35391
|
+
function parseBody(body) {
|
|
35392
|
+
const fail4 = (status, code, message) => ({ ok: false, error: { status, code, message, id: null } });
|
|
35393
|
+
let value;
|
|
35394
|
+
try {
|
|
35395
|
+
value = JSON.parse(body);
|
|
35396
|
+
} catch {
|
|
35397
|
+
return fail4(400, ERR_PARSE, "Parse error");
|
|
35398
|
+
}
|
|
35399
|
+
if (Array.isArray(value)) return fail4(400, ERR_INVALID_REQUEST, "Batch requests are not supported");
|
|
35400
|
+
if (!isRecord8(value)) return fail4(400, ERR_INVALID_REQUEST, "The body must be a single JSON-RPC request or notification");
|
|
35401
|
+
const method = value.method;
|
|
35402
|
+
if (typeof method !== "string" && ("result" in value || "error" in value)) {
|
|
35403
|
+
return fail4(400, ERR_INVALID_REQUEST, "JSON-RPC responses must not be sent to the server");
|
|
35404
|
+
}
|
|
35405
|
+
if (value.jsonrpc !== "2.0" || typeof method !== "string") return fail4(400, ERR_INVALID_REQUEST, "Not a JSON-RPC 2.0 request");
|
|
35406
|
+
const hasId = "id" in value;
|
|
35407
|
+
const id = value.id;
|
|
35408
|
+
if (hasId && typeof id !== "string" && typeof id !== "number") return fail4(400, ERR_INVALID_REQUEST, "`id` must be a string or a number");
|
|
35409
|
+
if (value.params !== void 0 && !isRecord8(value.params)) return fail4(400, ERR_INVALID_PARAMS, "`params` must be an object");
|
|
35410
|
+
return {
|
|
35411
|
+
ok: true,
|
|
35412
|
+
request: {
|
|
35413
|
+
id: hasId ? id : void 0,
|
|
35414
|
+
method,
|
|
35415
|
+
params: isRecord8(value.params) ? value.params : {}
|
|
35416
|
+
}
|
|
35417
|
+
};
|
|
35418
|
+
}
|
|
35419
|
+
function validateRequest(request3, headers, supported, allowed) {
|
|
35420
|
+
const id = request3.id ?? null;
|
|
35421
|
+
const err = (status, code, message, data) => ({
|
|
35422
|
+
status,
|
|
35423
|
+
code,
|
|
35424
|
+
message,
|
|
35425
|
+
id,
|
|
35426
|
+
...data !== void 0 ? { data } : {}
|
|
35427
|
+
});
|
|
35428
|
+
const { method, params } = request3;
|
|
35429
|
+
if (method === "initialize") {
|
|
35430
|
+
const requested = typeof params.protocolVersion === "string" ? params.protocolVersion : "unknown";
|
|
35431
|
+
return err(404, ERR_METHOD_NOT_FOUND, "Method not found: initialize (this endpoint is stateless, send server/discover)", {
|
|
35432
|
+
supported: [...supported],
|
|
35433
|
+
requested
|
|
35434
|
+
});
|
|
35435
|
+
}
|
|
35436
|
+
const meta = params._meta;
|
|
35437
|
+
const missing = [];
|
|
35438
|
+
if (!isRecord8(meta) || typeof meta[META_PROTOCOL_VERSION] !== "string") missing.push(META_PROTOCOL_VERSION);
|
|
35439
|
+
if (!isRecord8(meta) || !isRecord8(meta[META_CLIENT_CAPABILITIES])) missing.push(META_CLIENT_CAPABILITIES);
|
|
35440
|
+
if (!isRecord8(meta) || missing.length > 0) return err(400, ERR_INVALID_PARAMS, `Missing required _meta field(s): ${missing.join(", ")}`);
|
|
35441
|
+
const version = String(meta[META_PROTOCOL_VERSION]);
|
|
35442
|
+
if (!supported.includes(version)) {
|
|
35443
|
+
return err(400, ERR_UNSUPPORTED_VERSION, "Unsupported protocol version", { supported: [...supported], requested: version });
|
|
35444
|
+
}
|
|
35445
|
+
const headerVersion = headers["mcp-protocol-version"];
|
|
35446
|
+
if (headerVersion === void 0) return err(400, ERR_HEADER_MISMATCH, "Header mismatch: MCP-Protocol-Version header is missing");
|
|
35447
|
+
if (headerVersion !== version) {
|
|
35448
|
+
return err(400, ERR_HEADER_MISMATCH, `Header mismatch: MCP-Protocol-Version ${headerVersion} does not match _meta ${version}`);
|
|
35449
|
+
}
|
|
35450
|
+
const headerMethod = headers["mcp-method"];
|
|
35451
|
+
if (headerMethod === void 0) return err(400, ERR_HEADER_MISMATCH, "Header mismatch: Mcp-Method header is missing");
|
|
35452
|
+
if (headerMethod !== method) {
|
|
35453
|
+
return err(400, ERR_HEADER_MISMATCH, `Header mismatch: Mcp-Method ${headerMethod} does not match body ${method}`);
|
|
35454
|
+
}
|
|
35455
|
+
const source = NAME_HEADER_SOURCE.get(method);
|
|
35456
|
+
if (source !== void 0) {
|
|
35457
|
+
const expected = params[source];
|
|
35458
|
+
if (typeof expected !== "string") return err(400, ERR_INVALID_PARAMS, `Missing required params.${source}`);
|
|
35459
|
+
const rawName = headers["mcp-name"];
|
|
35460
|
+
if (rawName === void 0) return err(400, ERR_HEADER_MISMATCH, "Header mismatch: Mcp-Name header is missing");
|
|
35461
|
+
if (decodeHeaderValue(rawName) !== expected) {
|
|
35462
|
+
return err(400, ERR_HEADER_MISMATCH, `Header mismatch: Mcp-Name does not match params.${source}`);
|
|
35463
|
+
}
|
|
35464
|
+
}
|
|
35465
|
+
if (!allowed.has(method)) return err(404, ERR_METHOD_NOT_FOUND, `Method not found: ${method}`);
|
|
35466
|
+
return null;
|
|
35467
|
+
}
|
|
35468
|
+
|
|
35469
|
+
// src/mcp-modern/index.ts
|
|
35470
|
+
var DEFAULT_CACHE_POLICY = () => ({ ttlMs: 0, cacheScope: "private" });
|
|
35471
|
+
var JSON_HEADERS = { "content-type": "application/json" };
|
|
35472
|
+
function errorResponse(error, extraHeaders = {}) {
|
|
35473
|
+
return {
|
|
35474
|
+
status: error.status,
|
|
35475
|
+
headers: { ...JSON_HEADERS, ...extraHeaders },
|
|
35476
|
+
body: JSON.stringify({
|
|
35477
|
+
jsonrpc: "2.0",
|
|
35478
|
+
id: error.id,
|
|
35479
|
+
error: { code: error.code, message: error.message, ...error.data !== void 0 ? { data: error.data } : {} }
|
|
35480
|
+
})
|
|
35481
|
+
};
|
|
35482
|
+
}
|
|
35483
|
+
function okResponse(id, result) {
|
|
35484
|
+
return { status: 200, headers: { ...JSON_HEADERS }, body: JSON.stringify({ jsonrpc: "2.0", id, result }) };
|
|
35485
|
+
}
|
|
35486
|
+
function decorate(method, result, serverInfo, hints) {
|
|
35487
|
+
const meta = typeof result._meta === "object" && result._meta !== null && !Array.isArray(result._meta) ? result._meta : {};
|
|
35488
|
+
const resultType = typeof result.resultType === "string" ? result.resultType : "complete";
|
|
35489
|
+
const decorated = {
|
|
35490
|
+
...result,
|
|
35491
|
+
resultType,
|
|
35492
|
+
_meta: { ...meta, [META_SERVER_INFO]: meta[META_SERVER_INFO] ?? serverInfo }
|
|
35493
|
+
};
|
|
35494
|
+
if (resultType === "complete" && CACHE_HINT_METHODS.has(method)) {
|
|
35495
|
+
decorated.ttlMs = typeof result.ttlMs === "number" ? result.ttlMs : hints.ttlMs;
|
|
35496
|
+
decorated.cacheScope = typeof result.cacheScope === "string" ? result.cacheScope : hints.cacheScope;
|
|
35497
|
+
}
|
|
35498
|
+
return decorated;
|
|
35499
|
+
}
|
|
35500
|
+
function fromThrown(error, id) {
|
|
35501
|
+
if (error instanceof BridgeError) {
|
|
35502
|
+
const message = error.message.replace(/^(?:MCP error -?\d+: )+/, "");
|
|
35503
|
+
const status = error.code === ERR_METHOD_NOT_FOUND ? 404 : 200;
|
|
35504
|
+
return errorResponse({ status, code: error.code, message, id, ...error.data !== void 0 ? { data: error.data } : {} });
|
|
35505
|
+
}
|
|
35506
|
+
return errorResponse({ status: 500, code: ERR_INTERNAL, message: "Internal error", id });
|
|
35507
|
+
}
|
|
35508
|
+
async function answer(request3, bridge, supported, hints, signal) {
|
|
35509
|
+
if (request3.method === "server/discover") {
|
|
35510
|
+
const capabilities = { ...bridge.capabilities };
|
|
35511
|
+
delete capabilities.logging;
|
|
35512
|
+
return decorate(
|
|
35513
|
+
"server/discover",
|
|
35514
|
+
{
|
|
35515
|
+
supportedVersions: [...supported],
|
|
35516
|
+
capabilities,
|
|
35517
|
+
...bridge.instructions ? { instructions: bridge.instructions } : {}
|
|
35518
|
+
},
|
|
35519
|
+
bridge.serverInfo,
|
|
35520
|
+
hints
|
|
35521
|
+
);
|
|
35522
|
+
}
|
|
35523
|
+
return decorate(request3.method, await bridge.request(request3.method, forwardParams(request3.params), signal), bridge.serverInfo, hints);
|
|
35524
|
+
}
|
|
35525
|
+
async function handleModernRequest(input, deps2) {
|
|
35526
|
+
const supported = deps2.supportedVersions ?? DEFAULT_SUPPORTED_VERSIONS;
|
|
35527
|
+
const cachePolicy = deps2.cachePolicy ?? DEFAULT_CACHE_POLICY;
|
|
35528
|
+
const headers = normalizeHeaders(input.headers);
|
|
35529
|
+
if (input.method !== "POST") {
|
|
35530
|
+
return errorResponse({ status: 405, code: ERR_INVALID_REQUEST, message: "Only POST is supported", id: null }, { allow: "POST" });
|
|
35531
|
+
}
|
|
35532
|
+
if (!acceptsJson(headers["accept"])) {
|
|
35533
|
+
return errorResponse({ status: 406, code: ERR_INVALID_REQUEST, message: "Accept must allow application/json", id: null });
|
|
35534
|
+
}
|
|
35535
|
+
if (!isJsonContentType(headers["content-type"])) {
|
|
35536
|
+
return errorResponse({ status: 415, code: ERR_INVALID_REQUEST, message: "Content-Type must be application/json", id: null });
|
|
35537
|
+
}
|
|
35538
|
+
const parsed = parseBody(input.body);
|
|
35539
|
+
if (!parsed.ok) return errorResponse(parsed.error);
|
|
35540
|
+
const request3 = parsed.request;
|
|
35541
|
+
if (request3.id === void 0) return { status: 202, headers: {} };
|
|
35542
|
+
const invalid = validateRequest(request3, headers, supported, ALLOWED_METHODS);
|
|
35543
|
+
if (invalid) return errorResponse(invalid);
|
|
35544
|
+
const id = request3.id;
|
|
35545
|
+
let bridge;
|
|
35546
|
+
try {
|
|
35547
|
+
bridge = await openBridge(await deps2.createServer());
|
|
35548
|
+
const result = await answer({ ...request3, id }, bridge, supported, cachePolicy(request3.method), deps2.signal);
|
|
35549
|
+
if (deps2.signal?.aborted) return { status: 499, headers: {} };
|
|
35550
|
+
const response = okResponse(id, result);
|
|
35551
|
+
if ((request3.method === "server/discover" || request3.method === "tools/list") && deps2.onObserved) {
|
|
35552
|
+
try {
|
|
35553
|
+
deps2.onObserved(request3.method, { jsonrpc: "2.0", id, result });
|
|
35554
|
+
} catch {
|
|
35555
|
+
}
|
|
35556
|
+
}
|
|
35557
|
+
return response;
|
|
35558
|
+
} catch (error) {
|
|
35559
|
+
if (deps2.signal?.aborted) return { status: 499, headers: {} };
|
|
35560
|
+
const response = fromThrown(error, id);
|
|
35561
|
+
if ((request3.method === "server/discover" || request3.method === "tools/list") && deps2.onObserved && response.body) {
|
|
35562
|
+
try {
|
|
35563
|
+
deps2.onObserved(request3.method, JSON.parse(response.body));
|
|
35564
|
+
} catch {
|
|
35565
|
+
}
|
|
35566
|
+
}
|
|
35567
|
+
return response;
|
|
35568
|
+
} finally {
|
|
35569
|
+
await bridge?.close();
|
|
35570
|
+
}
|
|
35571
|
+
}
|
|
35107
35572
|
init_sessions();
|
|
35108
35573
|
init_session_retirement();
|
|
35109
35574
|
init_session_message();
|
|
@@ -35795,7 +36260,7 @@ function createSentinelStore(opts) {
|
|
|
35795
36260
|
const persist = opts?.persist ?? opts?.filePath !== void 0;
|
|
35796
36261
|
let persistTimer = null;
|
|
35797
36262
|
let secretsPersistTimer = null;
|
|
35798
|
-
const
|
|
36263
|
+
const load2 = () => {
|
|
35799
36264
|
const out = /* @__PURE__ */ new Map();
|
|
35800
36265
|
if (!persist) return out;
|
|
35801
36266
|
let raw;
|
|
@@ -35819,7 +36284,7 @@ function createSentinelStore(opts) {
|
|
|
35819
36284
|
}
|
|
35820
36285
|
return out;
|
|
35821
36286
|
};
|
|
35822
|
-
const sentinels =
|
|
36287
|
+
const sentinels = load2();
|
|
35823
36288
|
const loadSecrets = () => {
|
|
35824
36289
|
const out = /* @__PURE__ */ new Map();
|
|
35825
36290
|
if (!persist) return out;
|
|
@@ -36039,6 +36504,15 @@ function createSentinelStore(opts) {
|
|
|
36039
36504
|
function singleMatch(subject, types) {
|
|
36040
36505
|
return [{ subject, ...types ? { types } : {} }];
|
|
36041
36506
|
}
|
|
36507
|
+
var SentinelBackingExpiredError = class extends Error {
|
|
36508
|
+
code = "backing_subscription_expired";
|
|
36509
|
+
remoteId;
|
|
36510
|
+
constructor(message, remoteId) {
|
|
36511
|
+
super(message);
|
|
36512
|
+
this.name = "SentinelBackingExpiredError";
|
|
36513
|
+
if (remoteId !== void 0) this.remoteId = remoteId;
|
|
36514
|
+
}
|
|
36515
|
+
};
|
|
36042
36516
|
function deliveryPreferenceFor(provider, intervalMs) {
|
|
36043
36517
|
if (provider.preferredDelivery) return provider.preferredDelivery(intervalMs);
|
|
36044
36518
|
return provider.capabilities.poll ? { mode: "poll", intervalMs } : { mode: "push" };
|
|
@@ -36602,7 +37076,7 @@ function compactPrState(snapshot, extra) {
|
|
|
36602
37076
|
const slim = snapshot.state !== "open" && extra.closedEmitted ? { fetchedAt: snapshot.fetchedAt, state: snapshot.state, reviews: [], checks: [] } : snapshot;
|
|
36603
37077
|
return { snapshot: slim, ...extra };
|
|
36604
37078
|
}
|
|
36605
|
-
function
|
|
37079
|
+
function decorate2(events, pr) {
|
|
36606
37080
|
const title = pr.title.length > 80 ? `${pr.title.slice(0, 77)}...` : pr.title;
|
|
36607
37081
|
return events.map((e) => ({
|
|
36608
37082
|
...e,
|
|
@@ -36666,7 +37140,7 @@ function diffRepoPr(prev, pr, repo) {
|
|
|
36666
37140
|
closedEmitted = true;
|
|
36667
37141
|
}
|
|
36668
37142
|
return {
|
|
36669
|
-
events:
|
|
37143
|
+
events: decorate2(events, pr),
|
|
36670
37144
|
next: compactPrState(now, { draft: pr.draft, closedEmitted, ...ciReported ? { ciReported } : {} })
|
|
36671
37145
|
};
|
|
36672
37146
|
}
|
|
@@ -36698,7 +37172,7 @@ function diffRepo(cursor, prs, repo, fetchedAt) {
|
|
|
36698
37172
|
})
|
|
36699
37173
|
];
|
|
36700
37174
|
if (closed) fresh.push(closedEvent(pr.snapshot, { repo, number: pr.number, subject }, false));
|
|
36701
|
-
events.push(...
|
|
37175
|
+
events.push(...decorate2(fresh, pr));
|
|
36702
37176
|
}
|
|
36703
37177
|
const settled = verdict === "success" || verdict === "failure" || verdict === "neutral";
|
|
36704
37178
|
next[key] = compactPrState(pr.snapshot, {
|
|
@@ -37636,11 +38110,11 @@ function verifySignatureV2(secret, headers, body, nowMs, skewMs = SIGNATURE_V2_S
|
|
|
37636
38110
|
if (a.length !== b.length || !timingSafeEqual(a, b)) return { ok: false, reason: "signature_mismatch" };
|
|
37637
38111
|
return { ok: true, timestampSec };
|
|
37638
38112
|
}
|
|
37639
|
-
var
|
|
38113
|
+
var isRecord9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
37640
38114
|
function toSentinelEvent(raw, seq) {
|
|
37641
|
-
if (!
|
|
38115
|
+
if (!isRecord9(raw)) return null;
|
|
37642
38116
|
const { id, source, type, subject, time, data, summary, subjects, terminal, consumerref } = raw;
|
|
37643
|
-
if (raw.specversion !== "1.0" || typeof id !== "string" || id === "" || typeof source !== "string" || typeof type !== "string" || type === "" || typeof subject !== "string" || subject === "" || typeof time !== "string" || !
|
|
38117
|
+
if (raw.specversion !== "1.0" || typeof id !== "string" || id === "" || typeof source !== "string" || typeof type !== "string" || type === "" || typeof subject !== "string" || subject === "" || typeof time !== "string" || !isRecord9(data) || typeof summary !== "string" || !Array.isArray(subjects) || !subjects.every((s) => typeof s === "string") || typeof terminal !== "boolean") {
|
|
37644
38118
|
return null;
|
|
37645
38119
|
}
|
|
37646
38120
|
const envSeq = typeof raw.seq === "number" ? raw.seq : seq;
|
|
@@ -37686,9 +38160,36 @@ function stateOf(handle) {
|
|
|
37686
38160
|
mode: s.mode === "push" ? "push" : "poll",
|
|
37687
38161
|
...typeof s.consumerRef === "string" ? { consumerRef: s.consumerRef } : {},
|
|
37688
38162
|
...typeof s.hookKey === "string" ? { hookKey: s.hookKey } : {},
|
|
37689
|
-
...typeof s.callbackSecret === "string" ? { callbackSecret: s.callbackSecret } : {}
|
|
38163
|
+
...typeof s.callbackSecret === "string" ? { callbackSecret: s.callbackSecret } : {},
|
|
38164
|
+
...s.signature === "v2" ? { signature: "v2" } : {}
|
|
37690
38165
|
};
|
|
37691
38166
|
}
|
|
38167
|
+
function excerptOf(envelope) {
|
|
38168
|
+
if (!isRecord9(envelope)) return void 0;
|
|
38169
|
+
const cap = (v) => typeof v === "string" ? v.slice(0, 200) : void 0;
|
|
38170
|
+
const out = {};
|
|
38171
|
+
const id = cap(envelope.id);
|
|
38172
|
+
const type = cap(envelope.type);
|
|
38173
|
+
const subject = cap(envelope.subject);
|
|
38174
|
+
const source = cap(envelope.source);
|
|
38175
|
+
if (id !== void 0) out.id = id;
|
|
38176
|
+
if (type !== void 0) out.type = type;
|
|
38177
|
+
if (subject !== void 0) out.subject = subject;
|
|
38178
|
+
if (source !== void 0) out.source = source;
|
|
38179
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
38180
|
+
}
|
|
38181
|
+
function whyNotEnvelope(envelope) {
|
|
38182
|
+
if (envelope === void 0 || envelope === null) return "item has no envelope";
|
|
38183
|
+
if (!isRecord9(envelope)) return "envelope is not a JSON object";
|
|
38184
|
+
const missing = [];
|
|
38185
|
+
if (envelope.specversion !== "1.0") missing.push("specversion");
|
|
38186
|
+
for (const k of ["id", "type", "subject"]) if (typeof envelope[k] !== "string" || envelope[k] === "") missing.push(k);
|
|
38187
|
+
for (const k of ["source", "time", "summary"]) if (typeof envelope[k] !== "string") missing.push(k);
|
|
38188
|
+
if (!isRecord9(envelope.data)) missing.push("data");
|
|
38189
|
+
if (!Array.isArray(envelope.subjects) || !envelope.subjects.every((x) => typeof x === "string")) missing.push("subjects");
|
|
38190
|
+
if (typeof envelope.terminal !== "boolean") missing.push("terminal");
|
|
38191
|
+
return `envelope failed validation (invalid or missing: ${missing.join(", ") || "unknown"})`;
|
|
38192
|
+
}
|
|
37692
38193
|
var SUBJECT_SCHEME_RE = /^([A-Za-z][A-Za-z0-9_-]*):/;
|
|
37693
38194
|
function defaultTypesFor(subject) {
|
|
37694
38195
|
return subject.startsWith("github:") ? [...GITHUB_DEFAULT_PR_TYPES] : ["*"];
|
|
@@ -37746,7 +38247,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37746
38247
|
json3 = void 0;
|
|
37747
38248
|
}
|
|
37748
38249
|
if (!res.ok) {
|
|
37749
|
-
const detail =
|
|
38250
|
+
const detail = isRecord9(json3) && typeof json3.error === "string" ? json3.error : text13.slice(0, 200);
|
|
37750
38251
|
throw new AgentpushHttpError(res.status, `agentpush ${method} ${path} \u2192 HTTP ${res.status}${detail ? `: ${detail}` : ""}`);
|
|
37751
38252
|
}
|
|
37752
38253
|
return json3;
|
|
@@ -37779,6 +38280,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37779
38280
|
// Credentials come from `setup_sentinel_provider` OR an imported alias, so
|
|
37780
38281
|
// "set up" is decided by `readiness()`, not the kit's ledger/creds check.
|
|
37781
38282
|
requiresSetup: false,
|
|
38283
|
+
exclusiveRemote: true,
|
|
37782
38284
|
capabilities: {
|
|
37783
38285
|
subjects: ["*"],
|
|
37784
38286
|
push: true,
|
|
@@ -37832,7 +38334,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37832
38334
|
...push ? { callback_url: callbackUrl2(delivery.callbackUrl, hookKey), callback_secret: callbackSecret } : {}
|
|
37833
38335
|
}
|
|
37834
38336
|
});
|
|
37835
|
-
const id =
|
|
38337
|
+
const id = isRecord9(json3) && isRecord9(json3.subscription) ? json3.subscription.id : void 0;
|
|
37836
38338
|
if (typeof id !== "string" || id === "") throw new Error("agentpush: create returned no subscription id");
|
|
37837
38339
|
return {
|
|
37838
38340
|
provider: AGENTPUSH_SLUG,
|
|
@@ -37841,6 +38343,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37841
38343
|
state: {
|
|
37842
38344
|
mode: push ? "push" : "poll",
|
|
37843
38345
|
consumerRef,
|
|
38346
|
+
signature: "v2",
|
|
37844
38347
|
...push ? { hookKey, callbackSecret } : {}
|
|
37845
38348
|
}
|
|
37846
38349
|
};
|
|
@@ -37859,7 +38362,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37859
38362
|
let sub;
|
|
37860
38363
|
try {
|
|
37861
38364
|
const json3 = await api("GET", subPath(handle));
|
|
37862
|
-
sub =
|
|
38365
|
+
sub = isRecord9(json3) && isRecord9(json3.subscription) ? json3.subscription : void 0;
|
|
37863
38366
|
} catch (err) {
|
|
37864
38367
|
if (isHttp(err, 404)) {
|
|
37865
38368
|
throw new Error(`agentpush subscription ${handle.remoteId} no longer exists \u2014 re-create the sentinel`);
|
|
@@ -37887,10 +38390,34 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37887
38390
|
if (!isHttp(err, 404)) throw err;
|
|
37888
38391
|
}
|
|
37889
38392
|
},
|
|
38393
|
+
/**
|
|
38394
|
+
* Extend the remote subscription's lifetime. `PATCH` accepts `until`
|
|
38395
|
+
* without rejecting an already-expired row, so the returned `status` is
|
|
38396
|
+
* checked: anything but `active` (or a 404) means the backing subscription
|
|
38397
|
+
* is gone and must be recreated — never silently re-provisioned here.
|
|
38398
|
+
*/
|
|
38399
|
+
async renew(handle, until) {
|
|
38400
|
+
if (!handle.remoteId) throw new SentinelBackingExpiredError("agentpush: handle has no subscription id");
|
|
38401
|
+
let json3;
|
|
38402
|
+
try {
|
|
38403
|
+
json3 = await api("PATCH", subPath(handle), { body: { until } });
|
|
38404
|
+
} catch (err) {
|
|
38405
|
+
if (isHttp(err, 404)) {
|
|
38406
|
+
throw new SentinelBackingExpiredError(`the agentpush subscription ${handle.remoteId} was deleted`, handle.remoteId);
|
|
38407
|
+
}
|
|
38408
|
+
throw err;
|
|
38409
|
+
}
|
|
38410
|
+
const sub = isRecord9(json3) && isRecord9(json3.subscription) ? json3.subscription : void 0;
|
|
38411
|
+
const status = sub && typeof sub.status === "string" ? sub.status : void 0;
|
|
38412
|
+
if (status === "expired" || status === "deleted") {
|
|
38413
|
+
throw new SentinelBackingExpiredError(`the agentpush subscription ${handle.remoteId} is ${status}`, handle.remoteId);
|
|
38414
|
+
}
|
|
38415
|
+
return { ...handle };
|
|
38416
|
+
},
|
|
37890
38417
|
async status(handle) {
|
|
37891
38418
|
try {
|
|
37892
38419
|
const json3 = await api("GET", subPath(handle));
|
|
37893
|
-
const sub =
|
|
38420
|
+
const sub = isRecord9(json3) && isRecord9(json3.subscription) ? json3.subscription : void 0;
|
|
37894
38421
|
const status = sub && typeof sub.status === "string" ? sub.status : "unknown";
|
|
37895
38422
|
if (status === "active") return { ok: true };
|
|
37896
38423
|
return { ok: false, detail: `the agentpush subscription is ${status}` };
|
|
@@ -37902,18 +38429,35 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37902
38429
|
const after = handle.cursor ?? "0";
|
|
37903
38430
|
if (stateOf(handle).mode === "push") return { events: [], cursor: after };
|
|
37904
38431
|
const json3 = await api("GET", `${subPath(handle)}/events`, { query: { after, limit: Math.max(1, Math.min(limit, 1e3)) } });
|
|
37905
|
-
const items =
|
|
38432
|
+
const items = isRecord9(json3) && Array.isArray(json3.items) ? json3.items : [];
|
|
37906
38433
|
const events = [];
|
|
38434
|
+
const malformed = [];
|
|
37907
38435
|
let cursor = Number(after);
|
|
37908
38436
|
if (!Number.isFinite(cursor)) cursor = 0;
|
|
37909
38437
|
for (const item of items) {
|
|
37910
|
-
|
|
37911
|
-
const seq = typeof item.seq === "number" ? item.seq : void 0;
|
|
38438
|
+
const seq = isRecord9(item) && typeof item.seq === "number" ? item.seq : void 0;
|
|
37912
38439
|
if (seq !== void 0 && seq > cursor) cursor = seq;
|
|
37913
|
-
const
|
|
37914
|
-
|
|
38440
|
+
const envelope = isRecord9(item) ? item.envelope : void 0;
|
|
38441
|
+
const event = toSentinelEvent(envelope, seq);
|
|
38442
|
+
if (event) {
|
|
38443
|
+
events.push(event);
|
|
38444
|
+
continue;
|
|
38445
|
+
}
|
|
38446
|
+
let serialized = "";
|
|
38447
|
+
try {
|
|
38448
|
+
serialized = JSON.stringify(item) ?? "";
|
|
38449
|
+
} catch {
|
|
38450
|
+
}
|
|
38451
|
+
const excerpt = excerptOf(envelope);
|
|
38452
|
+
malformed.push({
|
|
38453
|
+
...seq !== void 0 ? { seq } : {},
|
|
38454
|
+
...isRecord9(item) && typeof item.delivery_id === "string" ? { remoteDeliveryId: item.delivery_id } : {},
|
|
38455
|
+
error: isRecord9(item) ? whyNotEnvelope(envelope) : "poll item is not a JSON object",
|
|
38456
|
+
...excerpt ? { excerpt } : {},
|
|
38457
|
+
...serialized ? { digest: createHash("sha256").update(serialized).digest("hex"), bytes: Buffer.byteLength(serialized) } : {}
|
|
38458
|
+
});
|
|
37915
38459
|
}
|
|
37916
|
-
return { events, cursor: String(cursor) };
|
|
38460
|
+
return { events, cursor: String(cursor), ...malformed.length > 0 ? { malformed } : {} };
|
|
37917
38461
|
},
|
|
37918
38462
|
/** Called by the runtime after a polled batch is delivered. Nothing new
|
|
37919
38463
|
* (cursor unchanged) is a no-op — no request on an empty tick. */
|
|
@@ -37930,6 +38474,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
37930
38474
|
const signature = headerValue3(req.headers, "x-agentpush-signature");
|
|
37931
38475
|
if (!signature || signature.trim() === "") return { ok: false, reason: "missing_signature" };
|
|
37932
38476
|
if (signature.trim().startsWith("sha256=")) {
|
|
38477
|
+
if (st.signature === "v2") return { ok: false, reason: "legacy_signature_rejected" };
|
|
37933
38478
|
const legacy = verifyInboundSignature("agentpush", {
|
|
37934
38479
|
rawBody: req.rawBody,
|
|
37935
38480
|
headers: req.headers,
|
|
@@ -38360,6 +38905,13 @@ async function createSentinelWatch(deps2, input) {
|
|
|
38360
38905
|
async function cancelSentinelWatch(deps2, id) {
|
|
38361
38906
|
const sentinel = deps2.store.get(id);
|
|
38362
38907
|
if (!sentinel) return false;
|
|
38908
|
+
if (deps2.tombstones) {
|
|
38909
|
+
try {
|
|
38910
|
+
await deps2.tombstones.cancel(sentinel.handle, () => deps2.store.remove(id));
|
|
38911
|
+
return true;
|
|
38912
|
+
} catch {
|
|
38913
|
+
}
|
|
38914
|
+
}
|
|
38363
38915
|
const provider = await deps2.resolveProvider(sentinel.provider);
|
|
38364
38916
|
if (provider) {
|
|
38365
38917
|
try {
|
|
@@ -38402,7 +38954,7 @@ var fail2 = (code, message) => ({
|
|
|
38402
38954
|
var urgencyField2 = z.enum(MESSAGE_URGENCIES);
|
|
38403
38955
|
var untilField = z.enum(["subject_terminal", "never"]);
|
|
38404
38956
|
function registerSentinelTools(server, opts) {
|
|
38405
|
-
const { store, runtime, resolveProvider, isSessionAlive, callerSessionId, activeIntervalMs } = opts;
|
|
38957
|
+
const { store, runtime, resolveProvider, isSessionAlive, callerSessionId, activeIntervalMs, tombstones } = opts;
|
|
38406
38958
|
server.tool(
|
|
38407
38959
|
"sentinel_watch",
|
|
38408
38960
|
"Watch a subject \u2014 a GitHub PR/repo (default) or ANOTHER SESSION's own lifecycle \u2014 and deliver matching events as a `system`/`notice` message into a session's AIP-46 inbox. Provide either `prUrl` (sugar: `https://github.com/o/r/pull/N` -> subject `github:o/r#N`, the default PR type set, and `until: subject_terminal`) or a raw `subject`: a GitHub one (`github:o/r#N`, `github:o/r`), or `session:<id>` to watch another session \u2014 woken on its turn-end, awaiting-input, or exit, even if it never calls `message_parent`, with the watch self-expiring once it exits (`until` defaults to `subject_terminal` for this scheme too). Prefer this over `session_follow` for a single, known target that should auto-expire on exit; prefer `session_follow` for a broad selector (`all`/`cwdPrefix`) with coalesced digests across many sessions. `sessionId` (the DELIVERY target) defaults to the calling session \u2014 distinct from the `<id>` inside a `session:<id>` subject (the WATCHED session). `provider` picks the backend: `local-gh` (poll every ~15-60s over the host's authenticated `gh` CLI, zero infra), `webhook` (near-real-time push via a GitHub repo hook; needs a public daemon URL \u2014 a named tunnel or AGENTPROTO_PUBLIC_URL \u2014 and a `gh` token with admin:repo_hook), `agentpush` (hosted, durable subscription: events queue server-side across daemon downtime; needs an agentpush API key; one subject per sentinel) or `session` (in-process, zero infra, no credentials \u2014 the only backend that understands a `session:<id>` subject, and picked automatically for one); see `list_sentinel_adapters` for readiness. Omitted for a GitHub subject, it defaults to `agentpush` when set up, else `webhook` when a stable public URL exists and webhook is ready, else `local-gh`.",
|
|
@@ -38434,7 +38986,7 @@ function registerSentinelTools(server, opts) {
|
|
|
38434
38986
|
"Stop a sentinel: best-effort cancels the provider-side watch, then removes the record. Idempotent-ish: an unknown id is reported, not thrown.",
|
|
38435
38987
|
{ id: z.string().describe("Sentinel id (sen_...).") },
|
|
38436
38988
|
async ({ id }) => {
|
|
38437
|
-
const removed = await cancelSentinelWatch({ store, resolveProvider }, id);
|
|
38989
|
+
const removed = await cancelSentinelWatch({ store, resolveProvider, ...tombstones ? { tombstones } : {} }, id);
|
|
38438
38990
|
if (!removed) return fail2("not_found", `sentinel_unwatch: no sentinel "${id}"`);
|
|
38439
38991
|
return ok2({ removed: true, id });
|
|
38440
38992
|
}
|
|
@@ -38495,7 +39047,7 @@ function createSessionFollowStore(opts) {
|
|
|
38495
39047
|
const debounceMs = opts?.debounceMs ?? PERSIST_DEBOUNCE_MS4;
|
|
38496
39048
|
const persist = opts?.persist ?? true;
|
|
38497
39049
|
let persistTimer = null;
|
|
38498
|
-
const
|
|
39050
|
+
const load2 = () => {
|
|
38499
39051
|
const out = /* @__PURE__ */ new Map();
|
|
38500
39052
|
if (!persist) return out;
|
|
38501
39053
|
let raw;
|
|
@@ -38521,7 +39073,7 @@ function createSessionFollowStore(opts) {
|
|
|
38521
39073
|
}
|
|
38522
39074
|
return out;
|
|
38523
39075
|
};
|
|
38524
|
-
const follows =
|
|
39076
|
+
const follows = load2();
|
|
38525
39077
|
const snapshot = () => {
|
|
38526
39078
|
const out = {};
|
|
38527
39079
|
for (const [id, follow] of follows.entries()) out[id] = follow;
|
|
@@ -38803,7 +39355,7 @@ function createHostRegistry(deps2) {
|
|
|
38803
39355
|
let probesRunning = 0;
|
|
38804
39356
|
const probeWaiters = [];
|
|
38805
39357
|
async function withProbeSlot(fn) {
|
|
38806
|
-
if (probesRunning >= probeConcurrency) await new Promise((
|
|
39358
|
+
if (probesRunning >= probeConcurrency) await new Promise((resolve47) => probeWaiters.push(resolve47));
|
|
38807
39359
|
probesRunning++;
|
|
38808
39360
|
try {
|
|
38809
39361
|
return await fn();
|
|
@@ -39342,7 +39894,7 @@ function createHostRegistry(deps2) {
|
|
|
39342
39894
|
};
|
|
39343
39895
|
}
|
|
39344
39896
|
async function awaitTunnelHello(client, sink, record2, closeReason) {
|
|
39345
|
-
return new Promise((
|
|
39897
|
+
return new Promise((resolve47, reject) => {
|
|
39346
39898
|
if (!sink.isOpen) {
|
|
39347
39899
|
reject(
|
|
39348
39900
|
new Error(
|
|
@@ -39361,7 +39913,7 @@ async function awaitTunnelHello(client, sink, record2, closeReason) {
|
|
|
39361
39913
|
client.ready().then(
|
|
39362
39914
|
() => {
|
|
39363
39915
|
offClose();
|
|
39364
|
-
|
|
39916
|
+
resolve47();
|
|
39365
39917
|
},
|
|
39366
39918
|
(err) => {
|
|
39367
39919
|
offClose();
|
|
@@ -39406,13 +39958,13 @@ function isLegacyJoinedShape(rec) {
|
|
|
39406
39958
|
return rec.addedVia === void 0 && rec.name === rec.fingerprint && rec.provider === void 0 && rec.sandboxId === void 0 && rec.labels === void 0 && rec.lastSeen === rec.createdAt;
|
|
39407
39959
|
}
|
|
39408
39960
|
function withTimeout(p, ms, what) {
|
|
39409
|
-
return new Promise((
|
|
39961
|
+
return new Promise((resolve47, reject) => {
|
|
39410
39962
|
const timer = setTimeout(() => reject(new Error(`${what} timed out after ${ms}ms`)), ms);
|
|
39411
39963
|
if (typeof timer.unref === "function") timer.unref();
|
|
39412
39964
|
p.then(
|
|
39413
39965
|
(v) => {
|
|
39414
39966
|
clearTimeout(timer);
|
|
39415
|
-
|
|
39967
|
+
resolve47(v);
|
|
39416
39968
|
},
|
|
39417
39969
|
(e) => {
|
|
39418
39970
|
clearTimeout(timer);
|
|
@@ -39641,7 +40193,7 @@ function isValidPrompt(prompt) {
|
|
|
39641
40193
|
return prompt !== null && typeof prompt === "object";
|
|
39642
40194
|
}
|
|
39643
40195
|
function sleep(ms) {
|
|
39644
|
-
return new Promise((
|
|
40196
|
+
return new Promise((resolve47) => setTimeout(resolve47, ms));
|
|
39645
40197
|
}
|
|
39646
40198
|
function httpErrorMessage(body) {
|
|
39647
40199
|
const raw = Buffer.from(body).toString("utf8");
|
|
@@ -40374,6 +40926,8 @@ init_transcript_export();
|
|
|
40374
40926
|
init_spawn_defaults();
|
|
40375
40927
|
init_app_boundary();
|
|
40376
40928
|
var WORKFLOW_PROMPT_SOURCE = "workflow:agent-step";
|
|
40929
|
+
var TRANSPORT_END_REASONS = /* @__PURE__ */ new Set([void 0, "crashed", "daemon-restart"]);
|
|
40930
|
+
var TRANSPORT_CLOSED_RE = /\bACP connection closed\b/i;
|
|
40377
40931
|
function withReviewWorktreeZones(boundary, cwd) {
|
|
40378
40932
|
const zones = reviewWorktreeReadZones(cwd);
|
|
40379
40933
|
if (!zones) return boundary;
|
|
@@ -40681,7 +41235,35 @@ var SessionsRegistryAgentHost = class {
|
|
|
40681
41235
|
* synchronously, before the event bus can fire the rejection asynchronously.
|
|
40682
41236
|
*/
|
|
40683
41237
|
async sendPromptAndWait(sessionId, prompt) {
|
|
40684
|
-
await Promise.all([
|
|
41238
|
+
await Promise.all([
|
|
41239
|
+
this.waitTurnEnd(sessionId),
|
|
41240
|
+
this.registry.sendPrompt(sessionId, prompt, { source: WORKFLOW_PROMPT_SOURCE }).catch((err) => {
|
|
41241
|
+
throw this.classifyPromptFailure(sessionId, err);
|
|
41242
|
+
})
|
|
41243
|
+
]);
|
|
41244
|
+
}
|
|
41245
|
+
/** True when `sessionId` dying (with `reason`) is the session's transport
|
|
41246
|
+
* failing under the step — not this host's own cancel/release, and not a
|
|
41247
|
+
* deliberate end (see {@link TRANSPORT_END_REASONS}). */
|
|
41248
|
+
diedUnderStep(sessionId, reason) {
|
|
41249
|
+
if (this.opts?.signal?.aborted) return false;
|
|
41250
|
+
if (!this.unreleased.has(sessionId)) return false;
|
|
41251
|
+
return TRANSPORT_END_REASONS.has(reason);
|
|
41252
|
+
}
|
|
41253
|
+
/** The error a wait rejects with when the session ends mid-turn. */
|
|
41254
|
+
sessionEndedError(sessionId, status, reason) {
|
|
41255
|
+
const message = `session ${sessionId} ended with status '${status}'${reason ? ` (${reason})` : ""}`;
|
|
41256
|
+
return this.diedUnderStep(sessionId, reason) ? new AgentSessionLostError(sessionId, message) : new Error(message);
|
|
41257
|
+
}
|
|
41258
|
+
/** `registry.sendPrompt` rejected: a closed ACP connection or an already-
|
|
41259
|
+
* dead session is a transport loss ({@link AgentSessionLostError});
|
|
41260
|
+
* anything else propagates unchanged. */
|
|
41261
|
+
classifyPromptFailure(sessionId, err) {
|
|
41262
|
+
if (!(err instanceof Error)) return err;
|
|
41263
|
+
const desc = this.registry.get(sessionId);
|
|
41264
|
+
const dead = err instanceof SessionNotAliveError || TRANSPORT_CLOSED_RE.test(err.message) || desc?.status === "killed" || desc?.status === "error";
|
|
41265
|
+
if (!dead || !this.diedUnderStep(sessionId, desc?.endedReason)) return err;
|
|
41266
|
+
return new AgentSessionLostError(sessionId, `session ${sessionId} lost before its turn ended \u2014 ${err.message}`, err);
|
|
40685
41267
|
}
|
|
40686
41268
|
resolveByLabel(stepId) {
|
|
40687
41269
|
return this.sessionsByLabel.get(stepId);
|
|
@@ -40769,15 +41351,15 @@ var SessionsRegistryAgentHost = class {
|
|
|
40769
41351
|
}
|
|
40770
41352
|
// ── Internal helpers ──────────────────────────────────────────────────
|
|
40771
41353
|
waitTurnEnd(sessionId) {
|
|
40772
|
-
return new Promise((
|
|
41354
|
+
return new Promise((resolve47, reject) => {
|
|
40773
41355
|
const unsubs = [];
|
|
40774
41356
|
const done = () => {
|
|
40775
41357
|
for (const u of unsubs) u();
|
|
40776
|
-
|
|
41358
|
+
resolve47();
|
|
40777
41359
|
};
|
|
40778
41360
|
const fail4 = (reason) => {
|
|
40779
41361
|
for (const u of unsubs) u();
|
|
40780
|
-
reject(new Error(reason));
|
|
41362
|
+
reject(typeof reason === "string" ? new Error(reason) : reason);
|
|
40781
41363
|
};
|
|
40782
41364
|
unsubs.push(
|
|
40783
41365
|
this.sessionEvents.on("session:turn-end", (ev) => {
|
|
@@ -40804,7 +41386,7 @@ var SessionsRegistryAgentHost = class {
|
|
|
40804
41386
|
this.sessionEvents.on("session:exited", (ev) => {
|
|
40805
41387
|
if (ev.sessionId !== sessionId) return;
|
|
40806
41388
|
if (ev.status === "killed" || ev.status === "error") {
|
|
40807
|
-
fail4(
|
|
41389
|
+
fail4(this.sessionEndedError(sessionId, ev.status, ev.reason));
|
|
40808
41390
|
} else {
|
|
40809
41391
|
done();
|
|
40810
41392
|
}
|
|
@@ -40814,7 +41396,7 @@ var SessionsRegistryAgentHost = class {
|
|
|
40814
41396
|
if (desc?.status === "exited" || desc?.awaitingInput === true) {
|
|
40815
41397
|
done();
|
|
40816
41398
|
} else if (desc?.status === "killed" || desc?.status === "error") {
|
|
40817
|
-
fail4(
|
|
41399
|
+
fail4(this.sessionEndedError(sessionId, desc.status, desc.endedReason));
|
|
40818
41400
|
}
|
|
40819
41401
|
});
|
|
40820
41402
|
}
|
|
@@ -40824,11 +41406,11 @@ function sanitize(cacheKey) {
|
|
|
40824
41406
|
const cleaned = cacheKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
40825
41407
|
return cleaned.length > 0 ? cleaned : "default";
|
|
40826
41408
|
}
|
|
40827
|
-
function
|
|
41409
|
+
function isRecord10(v) {
|
|
40828
41410
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
40829
41411
|
}
|
|
40830
41412
|
function isEntry2(v) {
|
|
40831
|
-
return
|
|
41413
|
+
return isRecord10(v) && typeof v.resolvedInputHash === "string" && "output" in v;
|
|
40832
41414
|
}
|
|
40833
41415
|
function createFileStepCache(cacheKey, opts) {
|
|
40834
41416
|
const dir = opts?.dir ?? DEFAULT_CACHE_DIR();
|
|
@@ -40841,7 +41423,7 @@ function createFileStepCache(cacheKey, opts) {
|
|
|
40841
41423
|
} catch {
|
|
40842
41424
|
return {};
|
|
40843
41425
|
}
|
|
40844
|
-
if (!
|
|
41426
|
+
if (!isRecord10(parsed)) return {};
|
|
40845
41427
|
const out = {};
|
|
40846
41428
|
for (const [k, v] of Object.entries(parsed)) if (isEntry2(v)) out[k] = v;
|
|
40847
41429
|
return out;
|
|
@@ -41137,6 +41719,7 @@ function findStepDef(defs, stepId) {
|
|
|
41137
41719
|
var DEFAULT_PERSIST_PATH2 = () => join(homedir(), ".agentproto", "workflow-runs.json");
|
|
41138
41720
|
var DEFAULT_LEASE_TTL_MS = 6e4;
|
|
41139
41721
|
var DEFAULT_HEARTBEAT_INTERVAL_MS = 15e3;
|
|
41722
|
+
var DEFAULT_PERSIST_MIN_INTERVAL_MS = 2e3;
|
|
41140
41723
|
function cancelledStageStatus(stage) {
|
|
41141
41724
|
return stage.steps.some((s) => s.status === "failed") ? "failed" : "cancelled";
|
|
41142
41725
|
}
|
|
@@ -41228,9 +41811,7 @@ function saveRuns(runs, persistPath) {
|
|
|
41228
41811
|
try {
|
|
41229
41812
|
mkdirSync(dirname(persistPath), { recursive: true });
|
|
41230
41813
|
const payload = JSON.stringify(
|
|
41231
|
-
Array.from(runs.values()).map((s) => s.run)
|
|
41232
|
-
null,
|
|
41233
|
-
2
|
|
41814
|
+
Array.from(runs.values()).map((s) => s.run)
|
|
41234
41815
|
) + "\n";
|
|
41235
41816
|
const tmp = `${persistPath}.tmp.${process.pid}`;
|
|
41236
41817
|
writeFileSync(tmp, payload, "utf8");
|
|
@@ -41306,7 +41887,7 @@ function createOnEscalate(state, persist) {
|
|
|
41306
41887
|
state.run.status = "awaiting-input";
|
|
41307
41888
|
persist();
|
|
41308
41889
|
try {
|
|
41309
|
-
return await new Promise((
|
|
41890
|
+
return await new Promise((resolve47, reject) => {
|
|
41310
41891
|
const timeoutMs = policy.timeoutMs ?? 3e5;
|
|
41311
41892
|
const timer = setTimeout(() => {
|
|
41312
41893
|
state.pendingResolve = void 0;
|
|
@@ -41318,7 +41899,7 @@ function createOnEscalate(state, persist) {
|
|
|
41318
41899
|
resolver: (response) => {
|
|
41319
41900
|
clearTimeout(timer);
|
|
41320
41901
|
state.pendingResolve = void 0;
|
|
41321
|
-
|
|
41902
|
+
resolve47(response);
|
|
41322
41903
|
}
|
|
41323
41904
|
};
|
|
41324
41905
|
});
|
|
@@ -41454,7 +42035,7 @@ async function executeRunWorkflow(state, runtimeWf, agents, signal, sessionEvent
|
|
|
41454
42035
|
// `resolveApproval` (wired to `workflow_escalation_resolve`'s approval
|
|
41455
42036
|
// form); the decision lands on the app ledger (`kind: "approval"`,
|
|
41456
42037
|
// `by: "human"`) per the trame rule.
|
|
41457
|
-
approve: (req) => new Promise((
|
|
42038
|
+
approve: (req) => new Promise((resolve47) => {
|
|
41458
42039
|
const approvalId = `wfappr_${randomUUID()}`;
|
|
41459
42040
|
const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
41460
42041
|
state.run.status = "awaiting-approval";
|
|
@@ -41511,7 +42092,7 @@ async function executeRunWorkflow(state, runtimeWf, agents, signal, sessionEvent
|
|
|
41511
42092
|
runId: state.run.runId
|
|
41512
42093
|
}
|
|
41513
42094
|
});
|
|
41514
|
-
|
|
42095
|
+
resolve47(decision);
|
|
41515
42096
|
};
|
|
41516
42097
|
if (req.timeoutMs !== void 0) {
|
|
41517
42098
|
timer = setTimeout(() => {
|
|
@@ -41528,7 +42109,7 @@ async function executeRunWorkflow(state, runtimeWf, agents, signal, sessionEvent
|
|
|
41528
42109
|
// resumes through `resumeSuspend` (workflow_escalation_resolve's
|
|
41529
42110
|
// suspend form); after a daemon restart the run stays suspended and
|
|
41530
42111
|
// the pending entry is re-registered below.
|
|
41531
|
-
resume: (req) => new Promise((
|
|
42112
|
+
resume: (req) => new Promise((resolve47) => {
|
|
41532
42113
|
const since = (/* @__PURE__ */ new Date()).toISOString();
|
|
41533
42114
|
state.run.status = "awaiting-input";
|
|
41534
42115
|
state.run.awaitingSuspend = {
|
|
@@ -41566,7 +42147,7 @@ async function executeRunWorkflow(state, runtimeWf, agents, signal, sessionEvent
|
|
|
41566
42147
|
});
|
|
41567
42148
|
eventLog?.append({ stepId: req.stepId, type: "step.resumed", data: {} });
|
|
41568
42149
|
eventLog?.append({ type: "run.resumed", data: { stepId: req.stepId } });
|
|
41569
|
-
|
|
42150
|
+
resolve47(payload);
|
|
41570
42151
|
};
|
|
41571
42152
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
41572
42153
|
state.pendingSuspend = { stepId: req.stepId, resolve: finish };
|
|
@@ -41582,7 +42163,7 @@ async function executeRunWorkflow(state, runtimeWf, agents, signal, sessionEvent
|
|
|
41582
42163
|
// read of the turn's text). On resume, `execAgentStep` sends the
|
|
41583
42164
|
// validated payload back to the SAME session as its next prompt and
|
|
41584
42165
|
// re-applies the outcome rule — this hook only parks and resolves.
|
|
41585
|
-
onInputRequired: (req) => new Promise((
|
|
42166
|
+
onInputRequired: (req) => new Promise((resolve47) => {
|
|
41586
42167
|
const since = (/* @__PURE__ */ new Date()).toISOString();
|
|
41587
42168
|
const suspend = {
|
|
41588
42169
|
reason: "input-required",
|
|
@@ -41635,7 +42216,7 @@ async function executeRunWorkflow(state, runtimeWf, agents, signal, sessionEvent
|
|
|
41635
42216
|
});
|
|
41636
42217
|
eventLog?.append({ stepId: req.stepId, type: "step.resumed", data: {} });
|
|
41637
42218
|
eventLog?.append({ type: "run.resumed", data: { stepId: req.stepId } });
|
|
41638
|
-
|
|
42219
|
+
resolve47(payload);
|
|
41639
42220
|
};
|
|
41640
42221
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
41641
42222
|
state.pendingSuspend = { stepId: req.stepId, resolve: finish };
|
|
@@ -41671,6 +42252,19 @@ async function executeRunWorkflow(state, runtimeWf, agents, signal, sessionEvent
|
|
|
41671
42252
|
}
|
|
41672
42253
|
}
|
|
41673
42254
|
},
|
|
42255
|
+
onAgentRetry: (ev) => {
|
|
42256
|
+
eventLog?.append({
|
|
42257
|
+
stepId: ev.stepId,
|
|
42258
|
+
type: "step.retrying",
|
|
42259
|
+
data: {
|
|
42260
|
+
attempt: ev.attempt,
|
|
42261
|
+
maxAttempts: ev.maxAttempts,
|
|
42262
|
+
error: ev.error,
|
|
42263
|
+
delayMs: ev.delayMs,
|
|
42264
|
+
...ev.sessionId !== void 0 ? { sessionId: ev.sessionId } : {}
|
|
42265
|
+
}
|
|
42266
|
+
});
|
|
42267
|
+
},
|
|
41674
42268
|
onStepStart: (stepId, info) => {
|
|
41675
42269
|
const cached = info?.cached === true;
|
|
41676
42270
|
if (nonLeafStepIds.has(stepId)) return;
|
|
@@ -41974,8 +42568,44 @@ function createWorkflowRunner(opts) {
|
|
|
41974
42568
|
});
|
|
41975
42569
|
};
|
|
41976
42570
|
const runs = shouldPersist ? loadRuns(persistPath, runsRoot) : /* @__PURE__ */ new Map();
|
|
42571
|
+
const persistMinIntervalMs = opts.persistMinIntervalMs ?? DEFAULT_PERSIST_MIN_INTERVAL_MS;
|
|
42572
|
+
let lastFlushAt = 0;
|
|
42573
|
+
let lastStatusSig = "";
|
|
42574
|
+
let trailingFlush;
|
|
42575
|
+
let dirty = false;
|
|
42576
|
+
const flushRuns = () => {
|
|
42577
|
+
if (trailingFlush) {
|
|
42578
|
+
clearTimeout(trailingFlush);
|
|
42579
|
+
trailingFlush = void 0;
|
|
42580
|
+
}
|
|
42581
|
+
dirty = false;
|
|
42582
|
+
lastFlushAt = Date.now();
|
|
42583
|
+
saveRuns(runs, persistPath);
|
|
42584
|
+
};
|
|
42585
|
+
const statusSig = () => {
|
|
42586
|
+
let sig = "";
|
|
42587
|
+
for (const st of runs.values()) sig += `${st.run.runId}:${st.run.status}|`;
|
|
42588
|
+
return sig;
|
|
42589
|
+
};
|
|
42590
|
+
if (shouldPersist && persistMinIntervalMs > 0) {
|
|
42591
|
+
process.once("exit", () => {
|
|
42592
|
+
if (dirty) flushRuns();
|
|
42593
|
+
});
|
|
42594
|
+
}
|
|
41977
42595
|
const persist = () => {
|
|
41978
|
-
if (shouldPersist)
|
|
42596
|
+
if (!shouldPersist) return;
|
|
42597
|
+
if (persistMinIntervalMs <= 0) return flushRuns();
|
|
42598
|
+
const sig = statusSig();
|
|
42599
|
+
const wait = lastFlushAt + persistMinIntervalMs - Date.now();
|
|
42600
|
+
if (sig !== lastStatusSig || wait <= 0) {
|
|
42601
|
+
lastStatusSig = sig;
|
|
42602
|
+
return flushRuns();
|
|
42603
|
+
}
|
|
42604
|
+
dirty = true;
|
|
42605
|
+
if (!trailingFlush) {
|
|
42606
|
+
trailingFlush = setTimeout(flushRuns, wait);
|
|
42607
|
+
trailingFlush.unref?.();
|
|
42608
|
+
}
|
|
41979
42609
|
};
|
|
41980
42610
|
const newEventLog = (runId) => shouldPersist ? createRunEventLog(runId, runsRoot) : void 0;
|
|
41981
42611
|
const workspaceRunsRoot = () => shouldPersist ? runsRoot : void 0;
|
|
@@ -43628,14 +44258,14 @@ function createSupervisorTaskGateRunner(opts) {
|
|
|
43628
44258
|
const { supervisor, registry, workspace } = opts;
|
|
43629
44259
|
const exec = opts.runCommand ?? runCommand;
|
|
43630
44260
|
const settleTimeoutMs = opts.settleTimeoutMs ?? DEFAULT_VERIFY_SETTLE_TIMEOUT_MS;
|
|
43631
|
-
const waitForSettle = (policyId) => new Promise((
|
|
44261
|
+
const waitForSettle = (policyId) => new Promise((resolve47) => {
|
|
43632
44262
|
let settled = false;
|
|
43633
44263
|
const finish = (outcome) => {
|
|
43634
44264
|
if (settled) return;
|
|
43635
44265
|
settled = true;
|
|
43636
44266
|
clearTimeout(timer);
|
|
43637
44267
|
unsub();
|
|
43638
|
-
|
|
44268
|
+
resolve47(outcome);
|
|
43639
44269
|
};
|
|
43640
44270
|
const read = () => {
|
|
43641
44271
|
const state = supervisor.getStatus(policyId);
|
|
@@ -44982,7 +45612,7 @@ async function monitorSessionWait(opts) {
|
|
|
44982
45612
|
};
|
|
44983
45613
|
}
|
|
44984
45614
|
}
|
|
44985
|
-
return new Promise((
|
|
45615
|
+
return new Promise((resolve47) => {
|
|
44986
45616
|
const unsubs = [];
|
|
44987
45617
|
let settled = false;
|
|
44988
45618
|
const watcherLabel = callerScope?.ownerSessionId ? registry.get(callerScope.ownerSessionId)?.label ?? registry.get(callerScope.ownerSessionId)?.title : void 0;
|
|
@@ -45022,7 +45652,7 @@ async function monitorSessionWait(opts) {
|
|
|
45022
45652
|
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
45023
45653
|
});
|
|
45024
45654
|
}
|
|
45025
|
-
|
|
45655
|
+
resolve47(result);
|
|
45026
45656
|
};
|
|
45027
45657
|
const relevantTypes = targetEvent === "any" ? ["session:turn-end", "session:awaiting-input", "session:exited"] : targetEvent === "turn-end" ? ["session:turn-end", "session:awaiting-input"] : targetEvent === "awaiting-input" ? ["session:awaiting-input"] : ["session:exited"];
|
|
45028
45658
|
const idSet = new Set(resolvedIds);
|
|
@@ -45063,13 +45693,13 @@ async function monitorPolicyWait(opts) {
|
|
|
45063
45693
|
if (isSettledStatus(initial.status)) {
|
|
45064
45694
|
return { timedOut: false, state: initial };
|
|
45065
45695
|
}
|
|
45066
|
-
return new Promise((
|
|
45696
|
+
return new Promise((resolve47) => {
|
|
45067
45697
|
let settled = false;
|
|
45068
45698
|
const timer = setTimeout(() => {
|
|
45069
45699
|
if (settled) return;
|
|
45070
45700
|
settled = true;
|
|
45071
45701
|
unsub();
|
|
45072
|
-
|
|
45702
|
+
resolve47({ timedOut: true });
|
|
45073
45703
|
}, timeoutMs);
|
|
45074
45704
|
const unsub = supervisor.onSettle((id) => {
|
|
45075
45705
|
if (id !== policyId) return;
|
|
@@ -45079,7 +45709,7 @@ async function monitorPolicyWait(opts) {
|
|
|
45079
45709
|
settled = true;
|
|
45080
45710
|
clearTimeout(timer);
|
|
45081
45711
|
unsub();
|
|
45082
|
-
|
|
45712
|
+
resolve47({ timedOut: false, state });
|
|
45083
45713
|
});
|
|
45084
45714
|
});
|
|
45085
45715
|
}
|
|
@@ -46994,7 +47624,7 @@ async function waitForSessionTerminal(registry, sessionId) {
|
|
|
46994
47624
|
for (let attempt = 0; attempt < MAX_SEQUENTIAL_POLLS; attempt++) {
|
|
46995
47625
|
const status = registry.get(sessionId)?.status;
|
|
46996
47626
|
if (isSessionTerminal(status)) return;
|
|
46997
|
-
await new Promise((
|
|
47627
|
+
await new Promise((resolve47) => setTimeout(resolve47, SEQUENTIAL_POLL_INTERVAL_MS));
|
|
46998
47628
|
}
|
|
46999
47629
|
}
|
|
47000
47630
|
var MODEL_ROUTED_ADAPTER = "claude-code";
|
|
@@ -47160,7 +47790,7 @@ function buildAppInstallPreview(args) {
|
|
|
47160
47790
|
runsBuildCommand: !isAgentapp && args.allowBuild === true
|
|
47161
47791
|
};
|
|
47162
47792
|
}
|
|
47163
|
-
async function dispatchAllowlistedAppTool(declaredAllowlist, input, deps2) {
|
|
47793
|
+
async function dispatchAllowlistedAppTool(declaredAllowlist, input, deps2, appDir) {
|
|
47164
47794
|
const effectiveAllowlist = [...declaredAllowlist, ...APP_UI_DISCOVERY_TOOLS];
|
|
47165
47795
|
if (!effectiveAllowlist.includes(input.tool)) {
|
|
47166
47796
|
return errorResult2(
|
|
@@ -47168,8 +47798,14 @@ async function dispatchAllowlistedAppTool(declaredAllowlist, input, deps2) {
|
|
|
47168
47798
|
);
|
|
47169
47799
|
}
|
|
47170
47800
|
const args = input.args ?? {};
|
|
47171
|
-
|
|
47172
|
-
|
|
47801
|
+
let dispatchArgs = args;
|
|
47802
|
+
if (input.tool === "app_install") {
|
|
47803
|
+
const cls = appInstallConfirmationClass(args);
|
|
47804
|
+
if (cls?.confirmed === false) return textResult2(buildAppInstallPreview(args));
|
|
47805
|
+
if (cls?.confirmed === true) {
|
|
47806
|
+
const { confirm: _confirmNonce, ...rest } = args;
|
|
47807
|
+
dispatchArgs = rest;
|
|
47808
|
+
}
|
|
47173
47809
|
}
|
|
47174
47810
|
try {
|
|
47175
47811
|
if (input.tool.startsWith("imported:")) {
|
|
@@ -47181,11 +47817,19 @@ async function dispatchAllowlistedAppTool(declaredAllowlist, input, deps2) {
|
|
|
47181
47817
|
`app_tool_call: malformed imported tool id "${input.tool}" \u2014 expected "imported:<alias>/<toolName>".`
|
|
47182
47818
|
);
|
|
47183
47819
|
}
|
|
47184
|
-
const result2 = await deps2.callImportedTool(rest.slice(0, slash), rest.slice(slash + 1),
|
|
47820
|
+
const result2 = await deps2.callImportedTool(rest.slice(0, slash), rest.slice(slash + 1), dispatchArgs);
|
|
47185
47821
|
return textResult2(result2);
|
|
47186
47822
|
}
|
|
47823
|
+
if (appDir !== void 0) {
|
|
47824
|
+
const bundled = await loadAppBundledTools(appDir);
|
|
47825
|
+
const bundledTool = bundled.tools.find((t) => t.id === input.tool);
|
|
47826
|
+
if (bundledTool) {
|
|
47827
|
+
const output = await runTool({ tool: bundledTool, candidates: bundled.drivers, input: args });
|
|
47828
|
+
return textResult2(output);
|
|
47829
|
+
}
|
|
47830
|
+
}
|
|
47187
47831
|
if (!deps2.dispatchTool) return notEnabled("app_tool_call");
|
|
47188
|
-
const result = await deps2.dispatchTool(input.tool,
|
|
47832
|
+
const result = await deps2.dispatchTool(input.tool, dispatchArgs);
|
|
47189
47833
|
return textResult2(result);
|
|
47190
47834
|
} catch (err) {
|
|
47191
47835
|
return errorResult2(`app_tool_call: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -47196,7 +47840,7 @@ async function performAppToolCall(appRegistry, input, deps2) {
|
|
|
47196
47840
|
if (!installed || !installed.ui) {
|
|
47197
47841
|
return errorResult2(`app_tool_call: app "${input.appId}" is not installed or has no UI.`);
|
|
47198
47842
|
}
|
|
47199
|
-
return dispatchAllowlistedAppTool(installed.ui.tools ?? [], input, deps2);
|
|
47843
|
+
return dispatchAllowlistedAppTool(installed.ui.tools ?? [], input, deps2, installed.dir);
|
|
47200
47844
|
}
|
|
47201
47845
|
async function performBuiltinPanelToolCall(tools, input, deps2) {
|
|
47202
47846
|
if (tools === void 0) {
|
|
@@ -47323,7 +47967,7 @@ async function performAppCall(appRegistry, input, deps2) {
|
|
|
47323
47967
|
error: `app_call: workflow "${input.workflow}" on "${input.appId}" did not finish within ${timeoutMs}ms (run ${run.runId} still ${status?.status ?? "unknown"}).`
|
|
47324
47968
|
};
|
|
47325
47969
|
}
|
|
47326
|
-
await new Promise((
|
|
47970
|
+
await new Promise((resolve47) => setTimeout(resolve47, APP_CALL_POLL_INTERVAL_MS));
|
|
47327
47971
|
}
|
|
47328
47972
|
}
|
|
47329
47973
|
function refIdOf(ref) {
|
|
@@ -48709,12 +49353,12 @@ async function readBody2(req) {
|
|
|
48709
49353
|
}
|
|
48710
49354
|
return { raw: Buffer.concat(chunks).toString("utf8") };
|
|
48711
49355
|
}
|
|
48712
|
-
var
|
|
49356
|
+
var isRecord11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
48713
49357
|
function parseParts(raw) {
|
|
48714
49358
|
if (!Array.isArray(raw)) throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "message.parts must be an array");
|
|
48715
49359
|
const parts = [];
|
|
48716
49360
|
for (const p of raw) {
|
|
48717
|
-
if (!
|
|
49361
|
+
if (!isRecord11(p)) throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "each message part must be an object");
|
|
48718
49362
|
if ("text" in p) {
|
|
48719
49363
|
if (typeof p.text !== "string") throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "part.text must be a string");
|
|
48720
49364
|
parts.push({ text: p.text });
|
|
@@ -48747,13 +49391,13 @@ async function handleA2aTaskRequest(req, res, path, deps2) {
|
|
|
48747
49391
|
send(res, 200, { jsonrpc: "2.0", id: null, error: { code: JSON_RPC_ERROR.parse, message: "parse error: body is not valid JSON" } });
|
|
48748
49392
|
return true;
|
|
48749
49393
|
}
|
|
48750
|
-
if (!
|
|
49394
|
+
if (!isRecord11(rpc) || rpc.jsonrpc !== "2.0" || typeof rpc.method !== "string") {
|
|
48751
49395
|
send(res, 200, { jsonrpc: "2.0", id: null, error: { code: JSON_RPC_ERROR.invalidRequest, message: 'invalid request: expected a JSON-RPC 2.0 object with a string "method" (batches are not supported)' } });
|
|
48752
49396
|
return true;
|
|
48753
49397
|
}
|
|
48754
49398
|
const id = typeof rpc.id === "string" || typeof rpc.id === "number" ? rpc.id : null;
|
|
48755
49399
|
const method = rpc.method;
|
|
48756
|
-
const params =
|
|
49400
|
+
const params = isRecord11(rpc.params) ? rpc.params : {};
|
|
48757
49401
|
const requested = negotiateVersion(
|
|
48758
49402
|
typeof req.headers["a2a-version"] === "string" ? req.headers["a2a-version"] : void 0,
|
|
48759
49403
|
new URL(req.url ?? "/", "http://localhost").searchParams.get("version")
|
|
@@ -48811,14 +49455,14 @@ async function handleA2aTaskRequest(req, res, path, deps2) {
|
|
|
48811
49455
|
throw new RpcFailure(JSON_RPC_ERROR.unsupportedOperation, `method "SendMessage" is not allowed for app "${appId}": its manifest does not declare accepts.tasks: true`);
|
|
48812
49456
|
}
|
|
48813
49457
|
const rawMessage = params.message;
|
|
48814
|
-
if (!
|
|
49458
|
+
if (!isRecord11(rawMessage) || rawMessage.role !== "ROLE_USER") {
|
|
48815
49459
|
throw new RpcFailure(JSON_RPC_ERROR.invalidParams, 'params.message must be an object with role "ROLE_USER"');
|
|
48816
49460
|
}
|
|
48817
49461
|
const parts = parseParts(rawMessage.parts);
|
|
48818
49462
|
const { skill, prompt } = extractSkillRequest(
|
|
48819
|
-
{ parts, ...
|
|
49463
|
+
{ parts, ...isRecord11(rawMessage.metadata) ? { metadata: rawMessage.metadata } : {} },
|
|
48820
49464
|
appId,
|
|
48821
|
-
|
|
49465
|
+
isRecord11(params.metadata) ? params.metadata : void 0
|
|
48822
49466
|
);
|
|
48823
49467
|
if (!skill) {
|
|
48824
49468
|
throw new RpcFailure(JSON_RPC_ERROR.invalidParams, 'no skill requested: set message.metadata.skill or start the first text part with "skill:<id>"');
|
|
@@ -49828,6 +50472,7 @@ async function startHttpServer(opts) {
|
|
|
49828
50472
|
const auth = readAuth();
|
|
49829
50473
|
if (auth.mode !== "bearer") return true;
|
|
49830
50474
|
if (path === "/health") return true;
|
|
50475
|
+
if (opts.eventsMcp && path.startsWith("/mcp/events/")) return true;
|
|
49831
50476
|
if (/^\/inbound\/[^/]+$/.test(path)) return true;
|
|
49832
50477
|
if (isAppUiShellRequest(method, path)) return true;
|
|
49833
50478
|
const header = req.headers.authorization;
|
|
@@ -50094,6 +50739,47 @@ async function startHttpServer(opts) {
|
|
|
50094
50739
|
const server2 = await opts.orchestratorMcpServerFactory(scope);
|
|
50095
50740
|
await serveMcp(req, res, server2);
|
|
50096
50741
|
}
|
|
50742
|
+
const EVENTS_BODY_CAP = 1024 * 1024;
|
|
50743
|
+
async function handleEventsMcp(req, res, presented) {
|
|
50744
|
+
const cfg = opts.eventsMcp;
|
|
50745
|
+
const send2 = (status, headers, body) => {
|
|
50746
|
+
res.writeHead(status, { "cache-control": "no-store", ...headers });
|
|
50747
|
+
res.end(body);
|
|
50748
|
+
};
|
|
50749
|
+
if (!cfg) return send2(404, { "content-type": "application/json" }, JSON.stringify({ error: "not_found" }));
|
|
50750
|
+
const want = Buffer.from(cfg.secret);
|
|
50751
|
+
const got = Buffer.from(presented);
|
|
50752
|
+
if (got.length !== want.length || !timingSafeEqual(got, want)) {
|
|
50753
|
+
return send2(404, { "content-type": "application/json" }, JSON.stringify({ error: "not_found" }));
|
|
50754
|
+
}
|
|
50755
|
+
const origin = req.headers.origin;
|
|
50756
|
+
if (typeof origin === "string" && !(cfg.allowedOrigins ?? []).includes(origin)) {
|
|
50757
|
+
return send2(403, { "content-type": "application/json" }, JSON.stringify({ error: "origin_not_allowed" }));
|
|
50758
|
+
}
|
|
50759
|
+
const chunks = [];
|
|
50760
|
+
let size = 0;
|
|
50761
|
+
for await (const chunk of req) {
|
|
50762
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
50763
|
+
size += buf.length;
|
|
50764
|
+
if (size > EVENTS_BODY_CAP) {
|
|
50765
|
+
return send2(413, { "content-type": "application/json" }, JSON.stringify({ error: "body_too_large" }));
|
|
50766
|
+
}
|
|
50767
|
+
chunks.push(buf);
|
|
50768
|
+
}
|
|
50769
|
+
const controller = new AbortController();
|
|
50770
|
+
res.on("close", () => {
|
|
50771
|
+
if (!res.writableEnded) controller.abort();
|
|
50772
|
+
});
|
|
50773
|
+
const out = await handleModernRequest(
|
|
50774
|
+
{
|
|
50775
|
+
method: req.method ?? "GET",
|
|
50776
|
+
headers: req.headers,
|
|
50777
|
+
body: Buffer.concat(chunks).toString("utf8")
|
|
50778
|
+
},
|
|
50779
|
+
{ createServer: cfg.createServer, signal: controller.signal }
|
|
50780
|
+
);
|
|
50781
|
+
send2(out.status, out.headers, out.body);
|
|
50782
|
+
}
|
|
50097
50783
|
async function handleImportedMcp(req, res, importId) {
|
|
50098
50784
|
if (!authorizeMcp(req, res)) return;
|
|
50099
50785
|
if (!opts.mcpProxy) {
|
|
@@ -50360,7 +51046,7 @@ async function startHttpServer(opts) {
|
|
|
50360
51046
|
});
|
|
50361
51047
|
}
|
|
50362
51048
|
applyCors(req, res);
|
|
50363
|
-
if (req.method === "OPTIONS") {
|
|
51049
|
+
if (req.method === "OPTIONS" && !(opts.eventsMcp && path.startsWith("/mcp/events/"))) {
|
|
50364
51050
|
res.writeHead(204);
|
|
50365
51051
|
res.end();
|
|
50366
51052
|
return;
|
|
@@ -50387,6 +51073,21 @@ async function startHttpServer(opts) {
|
|
|
50387
51073
|
handleEvents(req, res);
|
|
50388
51074
|
return;
|
|
50389
51075
|
}
|
|
51076
|
+
if (path.startsWith("/mcp/events/")) {
|
|
51077
|
+
let presented;
|
|
51078
|
+
try {
|
|
51079
|
+
presented = decodeURIComponent(path.slice("/mcp/events/".length));
|
|
51080
|
+
} catch (error) {
|
|
51081
|
+
if (!(error instanceof URIError)) throw error;
|
|
51082
|
+
}
|
|
51083
|
+
if (presented === void 0) {
|
|
51084
|
+
res.writeHead(404, { "content-type": "application/json", "cache-control": "no-store" });
|
|
51085
|
+
res.end(JSON.stringify({ error: "not_found" }));
|
|
51086
|
+
return;
|
|
51087
|
+
}
|
|
51088
|
+
await handleEventsMcp(req, res, presented);
|
|
51089
|
+
return;
|
|
51090
|
+
}
|
|
50390
51091
|
if (path === "/mcp/orchestrator") {
|
|
50391
51092
|
await handleOrchestratorMcp(req, res);
|
|
50392
51093
|
return;
|
|
@@ -50994,15 +51695,17 @@ async function startHttpServer(opts) {
|
|
|
50994
51695
|
try {
|
|
50995
51696
|
const base = str3("base");
|
|
50996
51697
|
const anchor = str3("anchor");
|
|
50997
|
-
const result =
|
|
50998
|
-
|
|
50999
|
-
|
|
51000
|
-
|
|
51001
|
-
|
|
51002
|
-
|
|
51003
|
-
|
|
51004
|
-
|
|
51005
|
-
|
|
51698
|
+
const result = withBranchGcApplySummary(
|
|
51699
|
+
await opts.runBranchGc({
|
|
51700
|
+
repoRoot: resolved.repoRoot,
|
|
51701
|
+
apply,
|
|
51702
|
+
includeReviewed: bool3("includeReviewed"),
|
|
51703
|
+
...base ? { base } : {},
|
|
51704
|
+
...scopes?.length ? { scopes } : {},
|
|
51705
|
+
...minAgeDays !== void 0 && Number.isFinite(minAgeDays) ? { minAgeDays } : {},
|
|
51706
|
+
...anchor ? { anchor } : {}
|
|
51707
|
+
})
|
|
51708
|
+
);
|
|
51006
51709
|
res.writeHead(200, { "content-type": "application/json" });
|
|
51007
51710
|
res.end(JSON.stringify(result));
|
|
51008
51711
|
} catch (err) {
|
|
@@ -52074,16 +52777,16 @@ async function startHttpServer(opts) {
|
|
|
52074
52777
|
});
|
|
52075
52778
|
});
|
|
52076
52779
|
const bind = opts.bind ?? "127.0.0.1";
|
|
52077
|
-
await new Promise((
|
|
52780
|
+
await new Promise((resolve47, reject) => {
|
|
52078
52781
|
server.once("error", reject);
|
|
52079
|
-
server.listen(opts.port, bind, () =>
|
|
52782
|
+
server.listen(opts.port, bind, () => resolve47());
|
|
52080
52783
|
});
|
|
52081
52784
|
return {
|
|
52082
52785
|
url: `http://${bind}:${opts.port}`,
|
|
52083
52786
|
async stop() {
|
|
52084
52787
|
wss.close();
|
|
52085
52788
|
server.closeAllConnections();
|
|
52086
|
-
await new Promise((
|
|
52789
|
+
await new Promise((resolve47) => server.close(() => resolve47()));
|
|
52087
52790
|
}
|
|
52088
52791
|
};
|
|
52089
52792
|
}
|
|
@@ -52292,9 +52995,9 @@ async function currentTranscriptSeq(id) {
|
|
|
52292
52995
|
let stream;
|
|
52293
52996
|
try {
|
|
52294
52997
|
stream = createReadStream(filePath, { encoding: "utf8" });
|
|
52295
|
-
await new Promise((
|
|
52998
|
+
await new Promise((resolve47, reject) => {
|
|
52296
52999
|
stream.once("error", reject);
|
|
52297
|
-
stream.once("open",
|
|
53000
|
+
stream.once("open", resolve47);
|
|
52298
53001
|
});
|
|
52299
53002
|
} catch (err) {
|
|
52300
53003
|
if (err.code === "ENOENT") return 0;
|
|
@@ -52319,9 +53022,9 @@ async function* transcriptDiskRecords(id) {
|
|
|
52319
53022
|
let stream;
|
|
52320
53023
|
try {
|
|
52321
53024
|
stream = createReadStream(filePath, { encoding: "utf8" });
|
|
52322
|
-
await new Promise((
|
|
53025
|
+
await new Promise((resolve47, reject) => {
|
|
52323
53026
|
stream.once("error", reject);
|
|
52324
|
-
stream.once("open",
|
|
53027
|
+
stream.once("open", resolve47);
|
|
52325
53028
|
});
|
|
52326
53029
|
} catch (err) {
|
|
52327
53030
|
if (err.code === "ENOENT") return;
|
|
@@ -54077,9 +54780,9 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
54077
54780
|
let fileStream;
|
|
54078
54781
|
try {
|
|
54079
54782
|
fileStream = createReadStream(filePath, { encoding: "utf8" });
|
|
54080
|
-
await new Promise((
|
|
54783
|
+
await new Promise((resolve47, reject) => {
|
|
54081
54784
|
fileStream.once("error", reject);
|
|
54082
|
-
fileStream.once("open",
|
|
54785
|
+
fileStream.once("open", resolve47);
|
|
54083
54786
|
});
|
|
54084
54787
|
} catch (err) {
|
|
54085
54788
|
const code = err.code;
|
|
@@ -54135,9 +54838,9 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
54135
54838
|
let fileStream;
|
|
54136
54839
|
try {
|
|
54137
54840
|
fileStream = createReadStream(filePath, { encoding: "utf8" });
|
|
54138
|
-
await new Promise((
|
|
54841
|
+
await new Promise((resolve47, reject) => {
|
|
54139
54842
|
fileStream.once("error", reject);
|
|
54140
|
-
fileStream.once("open",
|
|
54843
|
+
fileStream.once("open", resolve47);
|
|
54141
54844
|
});
|
|
54142
54845
|
} catch (err) {
|
|
54143
54846
|
const code = err.code;
|
|
@@ -54581,7 +55284,10 @@ async function handleSentinels(req, res, path, deps2) {
|
|
|
54581
55284
|
return true;
|
|
54582
55285
|
}
|
|
54583
55286
|
if (req.method === "DELETE") {
|
|
54584
|
-
const removed = await cancelSentinelWatch(
|
|
55287
|
+
const removed = await cancelSentinelWatch(
|
|
55288
|
+
{ store: deps2.store, resolveProvider: deps2.resolveProvider, ...deps2.tombstones ? { tombstones: deps2.tombstones } : {} },
|
|
55289
|
+
id
|
|
55290
|
+
);
|
|
54585
55291
|
if (!removed) {
|
|
54586
55292
|
json3(404, { error: "sentinel_not_found", id });
|
|
54587
55293
|
return true;
|
|
@@ -56891,7 +57597,7 @@ function createTransmitterBindingStore(opts) {
|
|
|
56891
57597
|
const nowMs = Date.now;
|
|
56892
57598
|
const debounceMs = PERSIST_DEBOUNCE_MS6;
|
|
56893
57599
|
let persistTimer = null;
|
|
56894
|
-
const
|
|
57600
|
+
const load2 = () => {
|
|
56895
57601
|
const out = /* @__PURE__ */ new Map();
|
|
56896
57602
|
let raw;
|
|
56897
57603
|
try {
|
|
@@ -56916,7 +57622,7 @@ function createTransmitterBindingStore(opts) {
|
|
|
56916
57622
|
}
|
|
56917
57623
|
return out;
|
|
56918
57624
|
};
|
|
56919
|
-
const bindings =
|
|
57625
|
+
const bindings = load2();
|
|
56920
57626
|
const snapshot = () => {
|
|
56921
57627
|
const out = {};
|
|
56922
57628
|
for (const [key, binding] of bindings.entries()) out[key] = binding;
|
|
@@ -56976,7 +57682,7 @@ function createInboundEndpointStore(opts) {
|
|
|
56976
57682
|
const debounceMs = opts?.debounceMs ?? PERSIST_DEBOUNCE_MS7;
|
|
56977
57683
|
const persist = opts?.persist ?? opts?.filePath !== void 0;
|
|
56978
57684
|
let persistTimer = null;
|
|
56979
|
-
const
|
|
57685
|
+
const load2 = () => {
|
|
56980
57686
|
const out = /* @__PURE__ */ new Map();
|
|
56981
57687
|
if (!persist) return out;
|
|
56982
57688
|
let raw;
|
|
@@ -57002,7 +57708,7 @@ function createInboundEndpointStore(opts) {
|
|
|
57002
57708
|
}
|
|
57003
57709
|
return out;
|
|
57004
57710
|
};
|
|
57005
|
-
const endpoints =
|
|
57711
|
+
const endpoints = load2();
|
|
57006
57712
|
const seen = /* @__PURE__ */ new Map();
|
|
57007
57713
|
let totalSeen = 0;
|
|
57008
57714
|
const snapshot = () => {
|
|
@@ -57165,6 +57871,299 @@ init_session_message();
|
|
|
57165
57871
|
init_sessions();
|
|
57166
57872
|
init_session_end_reason();
|
|
57167
57873
|
init_session_retirement();
|
|
57874
|
+
var tmpSeq6 = 0;
|
|
57875
|
+
var tmpPathFor2 = (filePath) => `${filePath}.tmp.${process.pid}.${++tmpSeq6}`;
|
|
57876
|
+
function isDirSyncUnsupported(err) {
|
|
57877
|
+
const code = err.code;
|
|
57878
|
+
return code === "EINVAL" || code === "EPERM" || code === "EISDIR" || code === "ENOTSUP";
|
|
57879
|
+
}
|
|
57880
|
+
async function writeFileDurable(filePath, data, opts = {}) {
|
|
57881
|
+
const mode = opts.mode ?? 384;
|
|
57882
|
+
const dir = dirname(filePath);
|
|
57883
|
+
await promises.mkdir(dir, { recursive: true });
|
|
57884
|
+
const tmp = tmpPathFor2(filePath);
|
|
57885
|
+
try {
|
|
57886
|
+
const fh = await promises.open(tmp, "w", mode);
|
|
57887
|
+
try {
|
|
57888
|
+
await fh.writeFile(data);
|
|
57889
|
+
await fh.chmod(mode);
|
|
57890
|
+
await fh.sync();
|
|
57891
|
+
} finally {
|
|
57892
|
+
await fh.close();
|
|
57893
|
+
}
|
|
57894
|
+
if (opts.commitIf && !opts.commitIf()) {
|
|
57895
|
+
await promises.unlink(tmp).catch(() => void 0);
|
|
57896
|
+
return;
|
|
57897
|
+
}
|
|
57898
|
+
await promises.rename(tmp, filePath);
|
|
57899
|
+
} catch (err) {
|
|
57900
|
+
await promises.unlink(tmp).catch(() => void 0);
|
|
57901
|
+
throw err;
|
|
57902
|
+
}
|
|
57903
|
+
try {
|
|
57904
|
+
const dh = await promises.open(dir, "r");
|
|
57905
|
+
try {
|
|
57906
|
+
await dh.sync();
|
|
57907
|
+
} finally {
|
|
57908
|
+
await dh.close();
|
|
57909
|
+
}
|
|
57910
|
+
} catch (err) {
|
|
57911
|
+
if (!isDirSyncUnsupported(err)) throw err;
|
|
57912
|
+
}
|
|
57913
|
+
}
|
|
57914
|
+
function writeFileDurableSync(filePath, data, mode = 384) {
|
|
57915
|
+
const dir = dirname(filePath);
|
|
57916
|
+
mkdirSync(dir, { recursive: true });
|
|
57917
|
+
const tmp = tmpPathFor2(filePath);
|
|
57918
|
+
try {
|
|
57919
|
+
const fd = openSync(tmp, "w", mode);
|
|
57920
|
+
try {
|
|
57921
|
+
writeSync(fd, data);
|
|
57922
|
+
fsyncSync(fd);
|
|
57923
|
+
} finally {
|
|
57924
|
+
closeSync(fd);
|
|
57925
|
+
}
|
|
57926
|
+
renameSync(tmp, filePath);
|
|
57927
|
+
} catch (err) {
|
|
57928
|
+
try {
|
|
57929
|
+
unlinkSync(tmp);
|
|
57930
|
+
} catch {
|
|
57931
|
+
}
|
|
57932
|
+
throw err;
|
|
57933
|
+
}
|
|
57934
|
+
try {
|
|
57935
|
+
const dfd = openSync(dir, "r");
|
|
57936
|
+
try {
|
|
57937
|
+
fsyncSync(dfd);
|
|
57938
|
+
} finally {
|
|
57939
|
+
closeSync(dfd);
|
|
57940
|
+
}
|
|
57941
|
+
} catch (err) {
|
|
57942
|
+
if (!isDirSyncUnsupported(err)) throw err;
|
|
57943
|
+
}
|
|
57944
|
+
}
|
|
57945
|
+
function appendLineDurableSync(filePath, line, mode = 384) {
|
|
57946
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
57947
|
+
const existed = (() => {
|
|
57948
|
+
try {
|
|
57949
|
+
closeSync(openSync(filePath, "r"));
|
|
57950
|
+
return true;
|
|
57951
|
+
} catch {
|
|
57952
|
+
return false;
|
|
57953
|
+
}
|
|
57954
|
+
})();
|
|
57955
|
+
const fd = openSync(filePath, "a", mode);
|
|
57956
|
+
try {
|
|
57957
|
+
appendFileSync(fd, line.endsWith("\n") ? line : `${line}
|
|
57958
|
+
`);
|
|
57959
|
+
fsyncSync(fd);
|
|
57960
|
+
} finally {
|
|
57961
|
+
closeSync(fd);
|
|
57962
|
+
}
|
|
57963
|
+
if (!existed) {
|
|
57964
|
+
try {
|
|
57965
|
+
const dfd = openSync(dirname(filePath), "r");
|
|
57966
|
+
try {
|
|
57967
|
+
fsyncSync(dfd);
|
|
57968
|
+
} finally {
|
|
57969
|
+
closeSync(dfd);
|
|
57970
|
+
}
|
|
57971
|
+
} catch (err) {
|
|
57972
|
+
if (!isDirSyncUnsupported(err)) throw err;
|
|
57973
|
+
}
|
|
57974
|
+
}
|
|
57975
|
+
}
|
|
57976
|
+
|
|
57977
|
+
// src/sentinel-cancel-tombstones.ts
|
|
57978
|
+
function defaultCancelTombstonePath() {
|
|
57979
|
+
return resolve(process.env.AGENTPROTO_HOME ?? join(homedir(), ".agentproto"), "sentinel-cancel-tombstones.json");
|
|
57980
|
+
}
|
|
57981
|
+
var SECRETISH = /secret|token|key|password|credential|authorization/i;
|
|
57982
|
+
function stripSecrets(handle) {
|
|
57983
|
+
const state = {};
|
|
57984
|
+
for (const [k, v] of Object.entries(handle.state ?? {})) if (!SECRETISH.test(k)) state[k] = v;
|
|
57985
|
+
return {
|
|
57986
|
+
provider: handle.provider,
|
|
57987
|
+
...handle.remoteId !== void 0 ? { remoteId: handle.remoteId } : {},
|
|
57988
|
+
...handle.cursor !== void 0 ? { cursor: handle.cursor } : {},
|
|
57989
|
+
...Object.keys(state).length > 0 ? { state } : {}
|
|
57990
|
+
};
|
|
57991
|
+
}
|
|
57992
|
+
var keyOf2 = (provider, remoteId) => `${provider}|${remoteId}`;
|
|
57993
|
+
function load(filePath) {
|
|
57994
|
+
try {
|
|
57995
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf8"));
|
|
57996
|
+
if (!Array.isArray(parsed.tombstones)) return [];
|
|
57997
|
+
return parsed.tombstones.filter(
|
|
57998
|
+
(t) => typeof t === "object" && t !== null && typeof t.key === "string"
|
|
57999
|
+
);
|
|
58000
|
+
} catch {
|
|
58001
|
+
return [];
|
|
58002
|
+
}
|
|
58003
|
+
}
|
|
58004
|
+
function createCancelTombstoneStore(opts) {
|
|
58005
|
+
const nowMs = opts.nowMs ?? Date.now;
|
|
58006
|
+
const log = opts.log ?? ((line) => console.warn(line));
|
|
58007
|
+
const base = opts.baseBackoffMs ?? 3e4;
|
|
58008
|
+
const max = opts.maxBackoffMs ?? 60 * 60 * 1e3;
|
|
58009
|
+
const rows = /* @__PURE__ */ new Map();
|
|
58010
|
+
if (opts.filePath) for (const t of load(opts.filePath)) rows.set(t.key, t);
|
|
58011
|
+
let writeTail = Promise.resolve();
|
|
58012
|
+
function persist() {
|
|
58013
|
+
if (!opts.filePath) return Promise.resolve();
|
|
58014
|
+
const filePath = opts.filePath;
|
|
58015
|
+
const run = () => writeFileDurable(filePath, JSON.stringify({ version: 1, tombstones: [...rows.values()] }, null, 2));
|
|
58016
|
+
const next = writeTail.then(run, run);
|
|
58017
|
+
writeTail = next.catch(() => void 0);
|
|
58018
|
+
return next;
|
|
58019
|
+
}
|
|
58020
|
+
const inFlight2 = /* @__PURE__ */ new Map();
|
|
58021
|
+
async function attempt(t, explicit = false) {
|
|
58022
|
+
const running = inFlight2.get(t.key);
|
|
58023
|
+
if (running) return running;
|
|
58024
|
+
const p = (async () => {
|
|
58025
|
+
if (!explicit && opts.isRemoteInUse?.(t.provider, t.remoteId)) {
|
|
58026
|
+
rows.delete(t.key);
|
|
58027
|
+
await persist().catch((err) => log(`[sentinel-tombstones] persist failed: ${String(err)}`));
|
|
58028
|
+
return true;
|
|
58029
|
+
}
|
|
58030
|
+
const provider = await opts.resolveProvider(t.provider);
|
|
58031
|
+
let error;
|
|
58032
|
+
if (!provider) error = `unknown sentinel provider "${t.provider}"`;
|
|
58033
|
+
else {
|
|
58034
|
+
try {
|
|
58035
|
+
await provider.cancel(t.handle);
|
|
58036
|
+
} catch (err) {
|
|
58037
|
+
error = err instanceof Error ? err.message : String(err);
|
|
58038
|
+
}
|
|
58039
|
+
}
|
|
58040
|
+
const live = rows.get(t.key);
|
|
58041
|
+
if (error === void 0) {
|
|
58042
|
+
if (live) rows.delete(t.key);
|
|
58043
|
+
await persist().catch((err) => log(`[sentinel-tombstones] persist failed: ${String(err)}`));
|
|
58044
|
+
return true;
|
|
58045
|
+
}
|
|
58046
|
+
if (live) {
|
|
58047
|
+
live.attempts += 1;
|
|
58048
|
+
live.lastAttemptAt = nowMs();
|
|
58049
|
+
live.lastError = error.slice(0, 300);
|
|
58050
|
+
live.nextAttemptAt = nowMs() + Math.min(max, base * 2 ** Math.min(live.attempts, 20));
|
|
58051
|
+
await persist().catch((err) => log(`[sentinel-tombstones] persist failed: ${String(err)}`));
|
|
58052
|
+
}
|
|
58053
|
+
return false;
|
|
58054
|
+
})().finally(() => inFlight2.delete(t.key));
|
|
58055
|
+
inFlight2.set(t.key, p);
|
|
58056
|
+
return p;
|
|
58057
|
+
}
|
|
58058
|
+
return {
|
|
58059
|
+
async cancel(handle, afterRecorded) {
|
|
58060
|
+
const provider = await opts.resolveProvider(handle.provider);
|
|
58061
|
+
if (!handle.remoteId || !provider?.exclusiveRemote) {
|
|
58062
|
+
afterRecorded?.();
|
|
58063
|
+
let converged2 = true;
|
|
58064
|
+
try {
|
|
58065
|
+
await provider?.cancel(handle);
|
|
58066
|
+
} catch {
|
|
58067
|
+
converged2 = false;
|
|
58068
|
+
}
|
|
58069
|
+
return { converged: converged2 };
|
|
58070
|
+
}
|
|
58071
|
+
const key = keyOf2(handle.provider, handle.remoteId);
|
|
58072
|
+
let t = rows.get(key);
|
|
58073
|
+
if (!t) {
|
|
58074
|
+
const now = nowMs();
|
|
58075
|
+
t = {
|
|
58076
|
+
key,
|
|
58077
|
+
provider: handle.provider,
|
|
58078
|
+
remoteId: handle.remoteId,
|
|
58079
|
+
handle: stripSecrets(handle),
|
|
58080
|
+
createdAt: now,
|
|
58081
|
+
attempts: 0,
|
|
58082
|
+
nextAttemptAt: now
|
|
58083
|
+
};
|
|
58084
|
+
rows.set(key, t);
|
|
58085
|
+
try {
|
|
58086
|
+
await persist();
|
|
58087
|
+
} catch (err) {
|
|
58088
|
+
rows.delete(key);
|
|
58089
|
+
throw err;
|
|
58090
|
+
}
|
|
58091
|
+
}
|
|
58092
|
+
afterRecorded?.();
|
|
58093
|
+
const converged = await attempt(t, true);
|
|
58094
|
+
const remaining = rows.get(key);
|
|
58095
|
+
return { converged, ...remaining ? { tombstone: remaining } : {} };
|
|
58096
|
+
},
|
|
58097
|
+
async sweep() {
|
|
58098
|
+
const now = nowMs();
|
|
58099
|
+
const due = [...rows.values()].filter((t) => t.nextAttemptAt <= now);
|
|
58100
|
+
let converged = 0;
|
|
58101
|
+
for (const t of due) if (await attempt(t)) converged++;
|
|
58102
|
+
return { attempted: due.length, converged, remaining: rows.size };
|
|
58103
|
+
},
|
|
58104
|
+
list: () => [...rows.values()],
|
|
58105
|
+
has: (provider, remoteId) => rows.has(keyOf2(provider, remoteId))
|
|
58106
|
+
};
|
|
58107
|
+
}
|
|
58108
|
+
function defaultSentinelQuarantinePath() {
|
|
58109
|
+
return resolve(process.env.AGENTPROTO_HOME ?? join(homedir(), ".agentproto"), "sentinel-quarantine.jsonl");
|
|
58110
|
+
}
|
|
58111
|
+
function keyFor(sentinelId, provider, item) {
|
|
58112
|
+
const identity = item.remoteDeliveryId ?? (item.seq !== void 0 ? `seq:${item.seq}` : "");
|
|
58113
|
+
return [sentinelId, provider, identity, item.digest ?? ""].join("|");
|
|
58114
|
+
}
|
|
58115
|
+
function loadFile(filePath) {
|
|
58116
|
+
if (!existsSync(filePath)) return [];
|
|
58117
|
+
const out = [];
|
|
58118
|
+
for (const line of readFileSync(filePath, "utf8").split("\n")) {
|
|
58119
|
+
if (line.trim() === "") continue;
|
|
58120
|
+
try {
|
|
58121
|
+
const rec = JSON.parse(line);
|
|
58122
|
+
if (rec && typeof rec.key === "string") out.push(rec);
|
|
58123
|
+
} catch {
|
|
58124
|
+
}
|
|
58125
|
+
}
|
|
58126
|
+
return out;
|
|
58127
|
+
}
|
|
58128
|
+
function createSentinelQuarantine(opts = {}) {
|
|
58129
|
+
const nowMs = opts.nowMs ?? Date.now;
|
|
58130
|
+
const records = /* @__PURE__ */ new Map();
|
|
58131
|
+
let loaded = false;
|
|
58132
|
+
function ensureLoaded() {
|
|
58133
|
+
if (loaded) return;
|
|
58134
|
+
if (opts.filePath) for (const rec of loadFile(opts.filePath)) records.set(rec.key, rec);
|
|
58135
|
+
loaded = true;
|
|
58136
|
+
}
|
|
58137
|
+
return {
|
|
58138
|
+
record({ sentinelId, provider, remoteId, item }) {
|
|
58139
|
+
ensureLoaded();
|
|
58140
|
+
const key = keyFor(sentinelId, provider, item);
|
|
58141
|
+
const existing = records.get(key);
|
|
58142
|
+
if (existing) return existing;
|
|
58143
|
+
const rec = {
|
|
58144
|
+
key,
|
|
58145
|
+
quarantinedAt: new Date(nowMs()).toISOString(),
|
|
58146
|
+
sentinelId,
|
|
58147
|
+
provider,
|
|
58148
|
+
...remoteId !== void 0 ? { remoteId } : {},
|
|
58149
|
+
...item.seq !== void 0 ? { seq: item.seq } : {},
|
|
58150
|
+
...item.remoteDeliveryId !== void 0 ? { remoteDeliveryId: item.remoteDeliveryId } : {},
|
|
58151
|
+
error: item.error,
|
|
58152
|
+
...item.excerpt ? { excerpt: item.excerpt } : {},
|
|
58153
|
+
...item.digest !== void 0 ? { digest: item.digest } : {},
|
|
58154
|
+
...item.bytes !== void 0 ? { bytes: item.bytes } : {}
|
|
58155
|
+
};
|
|
58156
|
+
if (opts.filePath) appendLineDurableSync(opts.filePath, JSON.stringify(rec));
|
|
58157
|
+
records.set(key, rec);
|
|
58158
|
+
return rec;
|
|
58159
|
+
},
|
|
58160
|
+
list(filter) {
|
|
58161
|
+
ensureLoaded();
|
|
58162
|
+
const all = [...records.values()];
|
|
58163
|
+
return filter?.sentinelId ? all.filter((r) => r.sentinelId === filter.sentinelId) : all;
|
|
58164
|
+
}
|
|
58165
|
+
};
|
|
58166
|
+
}
|
|
57168
58167
|
|
|
57169
58168
|
// src/webhook-egress/delivery.ts
|
|
57170
58169
|
init_signing();
|
|
@@ -57352,7 +58351,7 @@ function finalHeaders(headers, hostname6, port) {
|
|
|
57352
58351
|
return { ...headers, Host: port === 443 ? hostname6 : `${hostname6}:${port}` };
|
|
57353
58352
|
}
|
|
57354
58353
|
function rawPost(args) {
|
|
57355
|
-
return new Promise((
|
|
58354
|
+
return new Promise((resolve47, reject) => {
|
|
57356
58355
|
const req = request({
|
|
57357
58356
|
// Connect to the PRE-VALIDATED address; keep the original hostname in
|
|
57358
58357
|
// `servername` so SNI and the certificate check never loosen.
|
|
@@ -57376,7 +58375,7 @@ function rawPost(args) {
|
|
|
57376
58375
|
const ok4 = (status, body) => {
|
|
57377
58376
|
if (settled) return;
|
|
57378
58377
|
settled = true;
|
|
57379
|
-
|
|
58378
|
+
resolve47({ status, body });
|
|
57380
58379
|
};
|
|
57381
58380
|
req.setTimeout(args.timeoutMs, () => fail4("timeout", `no response within ${args.timeoutMs}ms`));
|
|
57382
58381
|
req.on("error", (err) => {
|
|
@@ -57459,7 +58458,7 @@ async function deliverEventEnvelope(replay, event, deps2 = {}) {
|
|
|
57459
58458
|
try {
|
|
57460
58459
|
response = await fetcher(replay.callbackUrl, {
|
|
57461
58460
|
method: "POST",
|
|
57462
|
-
headers: { ...signed, "content-type": "application/json" },
|
|
58461
|
+
headers: { ...signed, "content-type": "application/json", "X-MCP-Subscription-Id": replay.subId },
|
|
57463
58462
|
body: payloadBytes,
|
|
57464
58463
|
timeoutMs: 15e3
|
|
57465
58464
|
// delivery default (challenge uses 10_000)
|
|
@@ -57891,13 +58890,16 @@ function invalidParams(reason, detail) {
|
|
|
57891
58890
|
function callbackEndpointError(reason, detail) {
|
|
57892
58891
|
return new McpEventsError(-32015, `CallbackEndpointError: ${detail}`, { reason });
|
|
57893
58892
|
}
|
|
58893
|
+
function backingSubscriptionError(reason, detail, subscriptionId2) {
|
|
58894
|
+
return new McpEventsError(-32016, `BackingSubscriptionError: ${detail}`, { reason, subscriptionId: subscriptionId2 });
|
|
58895
|
+
}
|
|
57894
58896
|
var mutationChain = Promise.resolve();
|
|
57895
58897
|
function withSubscribeMutex(fn) {
|
|
57896
58898
|
const run = mutationChain.then(fn, fn);
|
|
57897
58899
|
mutationChain = run.catch(() => void 0);
|
|
57898
58900
|
return run;
|
|
57899
58901
|
}
|
|
57900
|
-
function
|
|
58902
|
+
function isRecord12(value) {
|
|
57901
58903
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
57902
58904
|
}
|
|
57903
58905
|
var LIST_PAGE_DEFAULT = 50;
|
|
@@ -57918,7 +58920,7 @@ function decodeListCursor(cursor) {
|
|
|
57918
58920
|
}
|
|
57919
58921
|
}
|
|
57920
58922
|
function requireWebhookDelivery(delivery) {
|
|
57921
|
-
if (!
|
|
58923
|
+
if (!isRecord12(delivery) || delivery.mode !== "webhook") {
|
|
57922
58924
|
throw invalidParams("unsupported_delivery_mode", 'delivery.mode must be "webhook"');
|
|
57923
58925
|
}
|
|
57924
58926
|
if (typeof delivery.url !== "string" || delivery.url.length === 0) {
|
|
@@ -57927,7 +58929,7 @@ function requireWebhookDelivery(delivery) {
|
|
|
57927
58929
|
return { mode: "webhook", url: delivery.url, ...typeof delivery.secret === "string" ? { secret: delivery.secret } : {} };
|
|
57928
58930
|
}
|
|
57929
58931
|
function validateArgsOrThrow(name, registration, args) {
|
|
57930
|
-
if (!
|
|
58932
|
+
if (!isRecord12(args)) throw invalidParams("invalid_arguments", "`arguments` must be an object");
|
|
57931
58933
|
const schemaCheck = validateAgainstInputSchema(registration.definition.inputSchema, args);
|
|
57932
58934
|
if (!schemaCheck.ok) {
|
|
57933
58935
|
throw invalidParams("invalid_arguments", `arguments for "${name}": ${schemaCheck.reason}`);
|
|
@@ -57983,10 +58985,30 @@ async function eventsSubscribe(input, ctx) {
|
|
|
57983
58985
|
if (target.kind !== "webhook") {
|
|
57984
58986
|
throw invalidParams("identity_conflict", `subscription ${id} exists with a non-webhook target`);
|
|
57985
58987
|
}
|
|
58988
|
+
let handle2 = existing.handle;
|
|
58989
|
+
const provider2 = await ctx.resolveProvider(existing.provider);
|
|
58990
|
+
if (provider2?.renew) {
|
|
58991
|
+
try {
|
|
58992
|
+
handle2 = await provider2.renew(existing.handle, until);
|
|
58993
|
+
} catch (err) {
|
|
58994
|
+
if (err instanceof SentinelBackingExpiredError) {
|
|
58995
|
+
throw backingSubscriptionError(
|
|
58996
|
+
"backing_subscription_expired",
|
|
58997
|
+
`${err.message}; unsubscribe and subscribe again`,
|
|
58998
|
+
id
|
|
58999
|
+
);
|
|
59000
|
+
}
|
|
59001
|
+
throw backingSubscriptionError(
|
|
59002
|
+
"backing_renew_failed",
|
|
59003
|
+
err instanceof Error ? err.message : String(err),
|
|
59004
|
+
id
|
|
59005
|
+
);
|
|
59006
|
+
}
|
|
59007
|
+
}
|
|
57986
59008
|
const ref = ctx.store.materializeWebhookTargetRef(target);
|
|
57987
59009
|
if (ref !== void 0) ctx.store.putSentinelSecret(ref, { secret });
|
|
57988
|
-
ctx.store.update(id, { spec: { ...existing.spec, until }, status: "active" });
|
|
57989
|
-
return { id, refreshBefore: computeRefreshBefore(until), cursor: null };
|
|
59010
|
+
ctx.store.update(id, { spec: { ...existing.spec, until }, handle: handle2, status: "active" });
|
|
59011
|
+
return { id, refreshBefore: computeRefreshBefore(until), cursor: null, truncated: false };
|
|
57990
59012
|
}
|
|
57991
59013
|
const provider = await ctx.resolveProvider(mapped.providerSlug);
|
|
57992
59014
|
if (!provider) {
|
|
@@ -58002,7 +59024,7 @@ async function eventsSubscribe(input, ctx) {
|
|
|
58002
59024
|
sentinelId: id
|
|
58003
59025
|
});
|
|
58004
59026
|
ctx.store.create({ id, spec, provider: mapped.providerSlug, handle });
|
|
58005
|
-
return { id, refreshBefore: computeRefreshBefore(until), cursor: null };
|
|
59027
|
+
return { id, refreshBefore: computeRefreshBefore(until), cursor: null, truncated: false };
|
|
58006
59028
|
});
|
|
58007
59029
|
}
|
|
58008
59030
|
async function eventsUnsubscribe(input, ctx) {
|
|
@@ -58022,6 +59044,13 @@ async function eventsUnsubscribe(input, ctx) {
|
|
|
58022
59044
|
await withSubscribeMutex(async () => {
|
|
58023
59045
|
const existing = ctx.store.get(id);
|
|
58024
59046
|
if (!existing) return;
|
|
59047
|
+
if (ctx.tombstones) {
|
|
59048
|
+
try {
|
|
59049
|
+
await ctx.tombstones.cancel(existing.handle, () => ctx.store.remove(id));
|
|
59050
|
+
return;
|
|
59051
|
+
} catch {
|
|
59052
|
+
}
|
|
59053
|
+
}
|
|
58025
59054
|
const provider = await ctx.resolveProvider(existing.provider);
|
|
58026
59055
|
if (provider) {
|
|
58027
59056
|
try {
|
|
@@ -58051,7 +59080,6 @@ var PERSIST_DEBOUNCE_MS8 = 1500;
|
|
|
58051
59080
|
var DELIVERED_REAP_MS = 24 * 60 * 60 * 1e3;
|
|
58052
59081
|
var PENDING_AGE_OUT_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
58053
59082
|
var ROW_CAP = 2e3;
|
|
58054
|
-
var tmpSeq6 = 0;
|
|
58055
59083
|
function webhookRequestId(sentinelId, eventId) {
|
|
58056
59084
|
const digest = createHash("sha256").update(`${sentinelId}:${eventId}`).digest("hex");
|
|
58057
59085
|
return `sub_${digest.slice(0, 32)}`;
|
|
@@ -58067,7 +59095,7 @@ function createSentinelWebhookOutbox(opts) {
|
|
|
58067
59095
|
const persist = opts.persist ?? opts.filePath !== void 0;
|
|
58068
59096
|
const deliverEvent = opts.deliverEvent ?? (async (input) => deliverEventEnvelope(input.replay, input.row.envelope));
|
|
58069
59097
|
const rowKey = (sentinelId, eventId) => `${sentinelId}::${eventId}`;
|
|
58070
|
-
const
|
|
59098
|
+
const load2 = () => {
|
|
58071
59099
|
const out = /* @__PURE__ */ new Map();
|
|
58072
59100
|
if (!persist) return out;
|
|
58073
59101
|
let raw;
|
|
@@ -58091,28 +59119,34 @@ function createSentinelWebhookOutbox(opts) {
|
|
|
58091
59119
|
}
|
|
58092
59120
|
return out;
|
|
58093
59121
|
};
|
|
58094
|
-
const rows =
|
|
59122
|
+
const rows = load2();
|
|
58095
59123
|
const snapshot = () => {
|
|
58096
59124
|
const out = {};
|
|
58097
59125
|
for (const [key, row] of rows.entries()) out[key] = row;
|
|
58098
59126
|
return out;
|
|
58099
59127
|
};
|
|
58100
59128
|
let persistTimer = null;
|
|
59129
|
+
let writeTail = Promise.resolve();
|
|
59130
|
+
let syncGeneration = 0;
|
|
59131
|
+
const persistNow = () => {
|
|
59132
|
+
if (!persist) return Promise.resolve();
|
|
59133
|
+
const run = async () => {
|
|
59134
|
+
const generation = syncGeneration;
|
|
59135
|
+
const body = JSON.stringify(snapshot(), null, 2) + "\n";
|
|
59136
|
+
await writeFileDurable(filePath, body, { commitIf: () => generation === syncGeneration });
|
|
59137
|
+
};
|
|
59138
|
+
const next = writeTail.then(run, run);
|
|
59139
|
+
writeTail = next.catch(() => void 0);
|
|
59140
|
+
return next;
|
|
59141
|
+
};
|
|
58101
59142
|
const schedulePersist = () => {
|
|
58102
59143
|
if (!persist) return;
|
|
58103
59144
|
if (persistTimer) clearTimeout(persistTimer);
|
|
58104
59145
|
persistTimer = setTimeout(() => {
|
|
58105
|
-
|
|
58106
|
-
|
|
58107
|
-
|
|
58108
|
-
|
|
58109
|
-
await promises.writeFile(tmp, JSON.stringify(snapshot(), null, 2) + "\n", { mode: 384 });
|
|
58110
|
-
await promises.chmod(tmp, 384);
|
|
58111
|
-
await promises.rename(tmp, filePath);
|
|
58112
|
-
} catch (err) {
|
|
58113
|
-
log(`[sentinel-webhook-outbox] persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
58114
|
-
}
|
|
58115
|
-
})();
|
|
59146
|
+
persistTimer = null;
|
|
59147
|
+
persistNow().catch((err) => {
|
|
59148
|
+
log(`[sentinel-webhook-outbox] persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
59149
|
+
});
|
|
58116
59150
|
}, debounceMs);
|
|
58117
59151
|
};
|
|
58118
59152
|
const flushSync = () => {
|
|
@@ -58121,12 +59155,9 @@ function createSentinelWebhookOutbox(opts) {
|
|
|
58121
59155
|
clearTimeout(persistTimer);
|
|
58122
59156
|
persistTimer = null;
|
|
58123
59157
|
}
|
|
59158
|
+
syncGeneration++;
|
|
58124
59159
|
try {
|
|
58125
|
-
|
|
58126
|
-
const tmp = `${filePath}.tmp.${process.pid}.${++tmpSeq6}`;
|
|
58127
|
-
writeFileSync(tmp, JSON.stringify(snapshot(), null, 2) + "\n", { mode: 384 });
|
|
58128
|
-
chmodSync(tmp, 384);
|
|
58129
|
-
renameSync(tmp, filePath);
|
|
59160
|
+
writeFileDurableSync(filePath, JSON.stringify(snapshot(), null, 2) + "\n");
|
|
58130
59161
|
} catch {
|
|
58131
59162
|
}
|
|
58132
59163
|
};
|
|
@@ -58203,7 +59234,14 @@ function createSentinelWebhookOutbox(opts) {
|
|
|
58203
59234
|
const key = rowKey(sentinelId, event.id);
|
|
58204
59235
|
const existing = rows.get(key);
|
|
58205
59236
|
if (existing) {
|
|
58206
|
-
if (existing.status !== "pending")
|
|
59237
|
+
if (existing.status !== "pending") {
|
|
59238
|
+
opts.onTerminal(sentinelId, existing);
|
|
59239
|
+
return void 0;
|
|
59240
|
+
}
|
|
59241
|
+
await writeTail;
|
|
59242
|
+
if (rows.get(key) !== existing) {
|
|
59243
|
+
throw new Error(`webhook outbox row ${key} was not persisted`);
|
|
59244
|
+
}
|
|
58207
59245
|
return void 0;
|
|
58208
59246
|
}
|
|
58209
59247
|
const envelope = toWebhookEnvelope(event);
|
|
@@ -58219,12 +59257,23 @@ function createSentinelWebhookOutbox(opts) {
|
|
|
58219
59257
|
envelope,
|
|
58220
59258
|
event
|
|
58221
59259
|
};
|
|
59260
|
+
let evicted;
|
|
58222
59261
|
if (rows.size >= ROW_CAP) {
|
|
58223
59262
|
const oldest = oldestTerminalRowKey();
|
|
58224
|
-
|
|
59263
|
+
const evictedRow = oldest ? rows.get(oldest) : void 0;
|
|
59264
|
+
if (oldest && evictedRow) {
|
|
59265
|
+
evicted = [oldest, evictedRow];
|
|
59266
|
+
rows.delete(oldest);
|
|
59267
|
+
}
|
|
58225
59268
|
}
|
|
58226
59269
|
rows.set(key, row);
|
|
58227
|
-
|
|
59270
|
+
try {
|
|
59271
|
+
await persistNow();
|
|
59272
|
+
} catch (err) {
|
|
59273
|
+
if (rows.get(key) === row) rows.delete(key);
|
|
59274
|
+
if (evicted && !rows.has(evicted[0])) rows.set(evicted[0], evicted[1]);
|
|
59275
|
+
throw err;
|
|
59276
|
+
}
|
|
58228
59277
|
enqueueDispatch();
|
|
58229
59278
|
return row;
|
|
58230
59279
|
},
|
|
@@ -58354,14 +59403,27 @@ function createSentinelRuntime(opts) {
|
|
|
58354
59403
|
if (store.get(sentinel.id)?.status !== "expired") {
|
|
58355
59404
|
store.update(sentinel.id, { status: "expired" });
|
|
58356
59405
|
}
|
|
58357
|
-
const provider = await opts.resolveProvider(sentinel.provider);
|
|
58358
|
-
if (!provider) return;
|
|
58359
59406
|
try {
|
|
58360
|
-
await
|
|
59407
|
+
await cancelTombstones.cancel(sentinel.handle);
|
|
58361
59408
|
} catch (err) {
|
|
58362
59409
|
log(`[sentinel-runtime] expiry cancel failed for ${sentinel.id}: ${describeError(err)}`);
|
|
58363
59410
|
}
|
|
58364
59411
|
}
|
|
59412
|
+
const outboxPersistent = opts.outboxPersist ?? (opts.outboxPath !== void 0 || opts.deliverEvent === void 0);
|
|
59413
|
+
const quarantinePath = opts.quarantinePath ?? (outboxPersistent ? defaultSentinelQuarantinePath() : void 0);
|
|
59414
|
+
const quarantine = createSentinelQuarantine({
|
|
59415
|
+
...quarantinePath !== void 0 ? { filePath: quarantinePath } : {},
|
|
59416
|
+
nowMs
|
|
59417
|
+
});
|
|
59418
|
+
const cancelTombstonePath = opts.cancelTombstonePath ?? (outboxPersistent ? defaultCancelTombstonePath() : void 0);
|
|
59419
|
+
const cancelTombstones = createCancelTombstoneStore({
|
|
59420
|
+
...cancelTombstonePath !== void 0 ? { filePath: cancelTombstonePath } : {},
|
|
59421
|
+
resolveProvider: opts.resolveProvider,
|
|
59422
|
+
// A live local watch that owns the remote makes the tombstone stale.
|
|
59423
|
+
isRemoteInUse: (provider, remoteId) => store.list().some((s) => s.provider === provider && s.handle.remoteId === remoteId && s.status !== "expired"),
|
|
59424
|
+
nowMs,
|
|
59425
|
+
log
|
|
59426
|
+
});
|
|
58365
59427
|
const outbox = createSentinelWebhookOutbox({
|
|
58366
59428
|
...opts.outboxPath !== void 0 ? { filePath: opts.outboxPath } : {},
|
|
58367
59429
|
nowMs,
|
|
@@ -58383,7 +59445,7 @@ function createSentinelRuntime(opts) {
|
|
|
58383
59445
|
if (stored.prevSecret && stored.rotatedAt !== void 0 && nowMs() - stored.rotatedAt < windowMs) {
|
|
58384
59446
|
secretsOut.push(stored.prevSecret);
|
|
58385
59447
|
}
|
|
58386
|
-
const subId =
|
|
59448
|
+
const subId = sentinelId;
|
|
58387
59449
|
return { subId, callbackUrl: target.url, secrets: secretsOut };
|
|
58388
59450
|
},
|
|
58389
59451
|
/** Expiry gate consulted BEFORE every dispatch (plan §4 W-B task 2b). */
|
|
@@ -58578,13 +59640,21 @@ function createSentinelRuntime(opts) {
|
|
|
58578
59640
|
}
|
|
58579
59641
|
async function processEvents(sentinelId, provider, events) {
|
|
58580
59642
|
let haltedOnError = false;
|
|
59643
|
+
let stoppedEarly = false;
|
|
58581
59644
|
let delivered = 0;
|
|
58582
59645
|
for (const event of events) {
|
|
58583
59646
|
const current = store.get(sentinelId);
|
|
58584
|
-
if (!current)
|
|
58585
|
-
|
|
59647
|
+
if (!current) {
|
|
59648
|
+
stoppedEarly = true;
|
|
59649
|
+
break;
|
|
59650
|
+
}
|
|
59651
|
+
if (!POLLABLE_STATUSES.has(current.status)) {
|
|
59652
|
+
stoppedEarly = true;
|
|
59653
|
+
break;
|
|
59654
|
+
}
|
|
58586
59655
|
if (isExpiredSpec(current)) {
|
|
58587
59656
|
await expireSentinel(current);
|
|
59657
|
+
stoppedEarly = true;
|
|
58588
59658
|
break;
|
|
58589
59659
|
}
|
|
58590
59660
|
if (store.isSeen(current.id, event.id)) continue;
|
|
@@ -58623,7 +59693,7 @@ function createSentinelRuntime(opts) {
|
|
|
58623
59693
|
});
|
|
58624
59694
|
if (updated) await applyLifetime(updated, event, provider);
|
|
58625
59695
|
}
|
|
58626
|
-
return { haltedOnError, delivered };
|
|
59696
|
+
return { haltedOnError, delivered, stoppedEarly };
|
|
58627
59697
|
}
|
|
58628
59698
|
async function pollSentinel(sentinel) {
|
|
58629
59699
|
const provider = await opts.resolveProvider(sentinel.provider);
|
|
@@ -58635,19 +59705,35 @@ function createSentinelRuntime(opts) {
|
|
|
58635
59705
|
store.update(sentinel.id, { lastError: describeError(err) });
|
|
58636
59706
|
return;
|
|
58637
59707
|
}
|
|
58638
|
-
|
|
58639
|
-
|
|
58640
|
-
|
|
58641
|
-
|
|
58642
|
-
|
|
58643
|
-
|
|
58644
|
-
|
|
58645
|
-
|
|
58646
|
-
|
|
58647
|
-
|
|
59708
|
+
let quarantineFailed = false;
|
|
59709
|
+
for (const item of result.malformed ?? []) {
|
|
59710
|
+
try {
|
|
59711
|
+
quarantine.record({
|
|
59712
|
+
sentinelId: sentinel.id,
|
|
59713
|
+
provider: sentinel.provider,
|
|
59714
|
+
...sentinel.handle.remoteId !== void 0 ? { remoteId: sentinel.handle.remoteId } : {},
|
|
59715
|
+
item
|
|
59716
|
+
});
|
|
59717
|
+
} catch (err) {
|
|
59718
|
+
quarantineFailed = true;
|
|
59719
|
+
log(`[sentinel-runtime] quarantine write failed for ${sentinel.id}: ${describeError(err)}`);
|
|
59720
|
+
}
|
|
59721
|
+
}
|
|
59722
|
+
const { haltedOnError, stoppedEarly } = await processEvents(sentinel.id, provider, result.events);
|
|
59723
|
+
if (haltedOnError || stoppedEarly || quarantineFailed) {
|
|
59724
|
+
if (quarantineFailed) store.update(sentinel.id, { lastError: "quarantine write failed; batch not acknowledged" });
|
|
59725
|
+
return;
|
|
59726
|
+
}
|
|
59727
|
+
const latest = store.get(sentinel.id);
|
|
59728
|
+
if (latest) {
|
|
59729
|
+
if (provider.ack) {
|
|
59730
|
+
try {
|
|
59731
|
+
await provider.ack(latest.handle, result.cursor);
|
|
59732
|
+
} catch (err) {
|
|
59733
|
+
log(`[sentinel-runtime] ack failed for ${sentinel.id}: ${describeError(err)}`);
|
|
58648
59734
|
}
|
|
58649
|
-
store.update(sentinel.id, { handle: { ...latest.handle, cursor: result.cursor } });
|
|
58650
59735
|
}
|
|
59736
|
+
store.update(sentinel.id, { handle: { ...latest.handle, cursor: result.cursor } });
|
|
58651
59737
|
}
|
|
58652
59738
|
}
|
|
58653
59739
|
async function pollOnce() {
|
|
@@ -58655,6 +59741,7 @@ function createSentinelRuntime(opts) {
|
|
|
58655
59741
|
inFlight2 = true;
|
|
58656
59742
|
try {
|
|
58657
59743
|
await sweepExpiredSentinels();
|
|
59744
|
+
await cancelTombstones.sweep().catch((err) => log(`[sentinel-runtime] tombstone sweep failed: ${describeError(err)}`));
|
|
58658
59745
|
outbox.sweep();
|
|
58659
59746
|
const pollable = store.list().filter((s) => POLLABLE_STATUSES.has(s.status));
|
|
58660
59747
|
for (const sentinel of pollable) {
|
|
@@ -58724,6 +59811,7 @@ function createSentinelRuntime(opts) {
|
|
|
58724
59811
|
async start() {
|
|
58725
59812
|
await reattachAll();
|
|
58726
59813
|
await sweepExpiredSentinels();
|
|
59814
|
+
await cancelTombstones.sweep().catch((err) => log(`[sentinel-runtime] tombstone sweep failed: ${describeError(err)}`));
|
|
58727
59815
|
await outbox.dispatch();
|
|
58728
59816
|
if (!timer) scheduleNext();
|
|
58729
59817
|
},
|
|
@@ -58735,7 +59823,9 @@ function createSentinelRuntime(opts) {
|
|
|
58735
59823
|
},
|
|
58736
59824
|
pollOnce,
|
|
58737
59825
|
deliverPushed,
|
|
58738
|
-
webhookOutbox: outbox
|
|
59826
|
+
webhookOutbox: outbox,
|
|
59827
|
+
quarantine,
|
|
59828
|
+
cancelTombstones
|
|
58739
59829
|
};
|
|
58740
59830
|
}
|
|
58741
59831
|
var BUILTIN_SENTINEL_PROVIDERS = {
|
|
@@ -58812,7 +59902,7 @@ async function spawnCloudflaredUntil(argv, opts) {
|
|
|
58812
59902
|
};
|
|
58813
59903
|
let settled = false;
|
|
58814
59904
|
let forwardedLen = 0;
|
|
58815
|
-
return await new Promise((
|
|
59905
|
+
return await new Promise((resolve47, reject) => {
|
|
58816
59906
|
const poll = setInterval(() => {
|
|
58817
59907
|
const text13 = readAll();
|
|
58818
59908
|
if (opts.onLog) {
|
|
@@ -58830,7 +59920,7 @@ async function spawnCloudflaredUntil(argv, opts) {
|
|
|
58830
59920
|
if (m) {
|
|
58831
59921
|
settled = true;
|
|
58832
59922
|
clearTimeout(timer);
|
|
58833
|
-
|
|
59923
|
+
resolve47({ proc, match: m[0], stopTail: () => clearInterval(poll) });
|
|
58834
59924
|
}
|
|
58835
59925
|
}, POLL_INTERVAL_MS2);
|
|
58836
59926
|
if (poll.unref) poll.unref();
|
|
@@ -58967,15 +60057,15 @@ function quickTunnelProvider() {
|
|
|
58967
60057
|
}
|
|
58968
60058
|
}, 3e3);
|
|
58969
60059
|
timer.unref();
|
|
58970
|
-
await new Promise((
|
|
60060
|
+
await new Promise((resolve47) => {
|
|
58971
60061
|
if (proc.exitCode !== null) {
|
|
58972
60062
|
clearTimeout(timer);
|
|
58973
|
-
|
|
60063
|
+
resolve47();
|
|
58974
60064
|
return;
|
|
58975
60065
|
}
|
|
58976
60066
|
proc.once("exit", () => {
|
|
58977
60067
|
clearTimeout(timer);
|
|
58978
|
-
|
|
60068
|
+
resolve47();
|
|
58979
60069
|
});
|
|
58980
60070
|
});
|
|
58981
60071
|
}
|
|
@@ -59128,15 +60218,15 @@ function namedTunnelProvider(cfg) {
|
|
|
59128
60218
|
}
|
|
59129
60219
|
}, 3e3);
|
|
59130
60220
|
timer.unref();
|
|
59131
|
-
await new Promise((
|
|
60221
|
+
await new Promise((resolve47) => {
|
|
59132
60222
|
if (proc.exitCode !== null) {
|
|
59133
60223
|
clearTimeout(timer);
|
|
59134
|
-
|
|
60224
|
+
resolve47();
|
|
59135
60225
|
return;
|
|
59136
60226
|
}
|
|
59137
60227
|
proc.once("exit", () => {
|
|
59138
60228
|
clearTimeout(timer);
|
|
59139
|
-
|
|
60229
|
+
resolve47();
|
|
59140
60230
|
});
|
|
59141
60231
|
});
|
|
59142
60232
|
}
|
|
@@ -59260,7 +60350,7 @@ function ngrokTunnelProvider(opts) {
|
|
|
59260
60350
|
};
|
|
59261
60351
|
proc.stderr?.on("data", forwardLogs);
|
|
59262
60352
|
proc.stdout?.on("data", forwardLogs);
|
|
59263
|
-
const url = await new Promise((
|
|
60353
|
+
const url = await new Promise((resolve47, reject) => {
|
|
59264
60354
|
let settled = false;
|
|
59265
60355
|
const timer = setTimeout(() => {
|
|
59266
60356
|
if (settled) return;
|
|
@@ -59288,7 +60378,7 @@ function ngrokTunnelProvider(opts) {
|
|
|
59288
60378
|
settled = true;
|
|
59289
60379
|
clearTimeout(timer);
|
|
59290
60380
|
if (apiPollHandle) clearInterval(apiPollHandle);
|
|
59291
|
-
|
|
60381
|
+
resolve47(pubUrl);
|
|
59292
60382
|
}
|
|
59293
60383
|
} catch {
|
|
59294
60384
|
}
|
|
@@ -59303,7 +60393,7 @@ function ngrokTunnelProvider(opts) {
|
|
|
59303
60393
|
settled = true;
|
|
59304
60394
|
clearTimeout(timer);
|
|
59305
60395
|
if (apiPollHandle) clearInterval(apiPollHandle);
|
|
59306
|
-
|
|
60396
|
+
resolve47(reMatch[1]);
|
|
59307
60397
|
return;
|
|
59308
60398
|
}
|
|
59309
60399
|
for (const line of text13.split(/\r?\n/)) {
|
|
@@ -59314,7 +60404,7 @@ function ngrokTunnelProvider(opts) {
|
|
|
59314
60404
|
settled = true;
|
|
59315
60405
|
clearTimeout(timer);
|
|
59316
60406
|
if (apiPollHandle) clearInterval(apiPollHandle);
|
|
59317
|
-
|
|
60407
|
+
resolve47(parsed.url);
|
|
59318
60408
|
return;
|
|
59319
60409
|
}
|
|
59320
60410
|
} catch {
|
|
@@ -59361,15 +60451,15 @@ function ngrokTunnelProvider(opts) {
|
|
|
59361
60451
|
}
|
|
59362
60452
|
}, 3e3);
|
|
59363
60453
|
timer.unref();
|
|
59364
|
-
await new Promise((
|
|
60454
|
+
await new Promise((resolve47) => {
|
|
59365
60455
|
if (proc.exitCode !== null) {
|
|
59366
60456
|
clearTimeout(timer);
|
|
59367
|
-
|
|
60457
|
+
resolve47();
|
|
59368
60458
|
return;
|
|
59369
60459
|
}
|
|
59370
60460
|
proc.once("exit", () => {
|
|
59371
60461
|
clearTimeout(timer);
|
|
59372
|
-
|
|
60462
|
+
resolve47();
|
|
59373
60463
|
});
|
|
59374
60464
|
});
|
|
59375
60465
|
}
|
|
@@ -59581,7 +60671,7 @@ function sameCollapseGroup(a, b) {
|
|
|
59581
60671
|
if ((a.key ?? "") !== (b.key ?? "")) return false;
|
|
59582
60672
|
return a.event === b.event || TURN_FAMILY.has(a.event) && TURN_FAMILY.has(b.event);
|
|
59583
60673
|
}
|
|
59584
|
-
function
|
|
60674
|
+
function excerptOf2(text13) {
|
|
59585
60675
|
if (!text13) return void 0;
|
|
59586
60676
|
const flat = text13.replace(/\s+/g, " ").trim();
|
|
59587
60677
|
if (!flat) return void 0;
|
|
@@ -59596,7 +60686,7 @@ function formatFollowDigest(entries, resolveText, desc) {
|
|
|
59596
60686
|
const cwd = d?.cwd ?? entry.cwd;
|
|
59597
60687
|
const parts = [`[session-follow] ${who} ${entry.event}`];
|
|
59598
60688
|
if (cwd) parts.push(basename(cwd) || cwd);
|
|
59599
|
-
const text13 =
|
|
60689
|
+
const text13 = excerptOf2(resolveText(entry));
|
|
59600
60690
|
if (text13) parts.push(text13);
|
|
59601
60691
|
return parts.join(" \u2014 ");
|
|
59602
60692
|
});
|
|
@@ -59872,6 +60962,31 @@ function createSentinelAutoLinker(opts) {
|
|
|
59872
60962
|
linkNow: link
|
|
59873
60963
|
};
|
|
59874
60964
|
}
|
|
60965
|
+
function isSubscriptionPermitted(params, repoAllowlist) {
|
|
60966
|
+
const args = params.arguments;
|
|
60967
|
+
if (typeof args !== "object" || args === null || Array.isArray(args)) return false;
|
|
60968
|
+
const repo = args.repo;
|
|
60969
|
+
return typeof repo === "string" && repoAllowlist.includes(repo);
|
|
60970
|
+
}
|
|
60971
|
+
function createEventsSurfaceServer(opts) {
|
|
60972
|
+
const server = new McpServer({ name: "agentproto-events", version: opts.version }, { capabilities: { tools: {} } });
|
|
60973
|
+
server.registerTool(
|
|
60974
|
+
"events_ping",
|
|
60975
|
+
{ description: "Liveness probe for the events surface. Returns ok.", inputSchema: {} },
|
|
60976
|
+
async () => ({ content: [{ type: "text", text: "ok" }] })
|
|
60977
|
+
);
|
|
60978
|
+
registerEventsMethods(server, {
|
|
60979
|
+
list: (params) => opts.handlers.list(params),
|
|
60980
|
+
subscribe: async (params) => {
|
|
60981
|
+
if (!isSubscriptionPermitted(params, opts.repoAllowlist)) {
|
|
60982
|
+
throw new McpError(ErrorCode.InvalidParams, "subscription not permitted");
|
|
60983
|
+
}
|
|
60984
|
+
return opts.handlers.subscribe(params);
|
|
60985
|
+
},
|
|
60986
|
+
unsubscribe: (params) => opts.handlers.unsubscribe(params)
|
|
60987
|
+
});
|
|
60988
|
+
return server;
|
|
60989
|
+
}
|
|
59875
60990
|
var TELEGRAM_BOT_CREDS_FAMILY = "telegram-bot";
|
|
59876
60991
|
function makeTelegramBotCredsStore(home) {
|
|
59877
60992
|
const store = makeCredsStore({
|
|
@@ -60350,12 +61465,12 @@ function canonicalJson(value) {
|
|
|
60350
61465
|
}
|
|
60351
61466
|
function isToolAppVisible(tool) {
|
|
60352
61467
|
const meta = tool._meta;
|
|
60353
|
-
const ui =
|
|
61468
|
+
const ui = isRecord13(meta?.ui) ? meta.ui : void 0;
|
|
60354
61469
|
const visibility = ui?.visibility;
|
|
60355
61470
|
if (!Array.isArray(visibility)) return true;
|
|
60356
61471
|
return visibility.includes("app");
|
|
60357
61472
|
}
|
|
60358
|
-
function
|
|
61473
|
+
function isRecord13(v) {
|
|
60359
61474
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
60360
61475
|
}
|
|
60361
61476
|
function buildUiToolIndex(tools) {
|
|
@@ -60880,19 +61995,19 @@ function classifyMcpError(err) {
|
|
|
60880
61995
|
return { status: "unreachable", error };
|
|
60881
61996
|
}
|
|
60882
61997
|
function uiMetaOf(meta) {
|
|
60883
|
-
if (!
|
|
61998
|
+
if (!isRecord14(meta) || !isRecord14(meta.ui)) return {};
|
|
60884
61999
|
const ui = meta.ui;
|
|
60885
62000
|
const csp = cspOf(ui.csp);
|
|
60886
62001
|
return {
|
|
60887
62002
|
...csp ? { csp } : {},
|
|
60888
|
-
...
|
|
62003
|
+
...isRecord14(ui.permissions) ? { permissions: ui.permissions } : {},
|
|
60889
62004
|
...typeof ui.prefersBorder === "boolean" ? { prefersBorder: ui.prefersBorder } : {},
|
|
60890
62005
|
...typeof ui.domain === "string" ? { domain: ui.domain } : {}
|
|
60891
62006
|
};
|
|
60892
62007
|
}
|
|
60893
62008
|
var CSP_DOMAIN_KEYS = ["connectDomains", "resourceDomains", "frameDomains", "baseUriDomains"];
|
|
60894
62009
|
function cspOf(raw) {
|
|
60895
|
-
if (!
|
|
62010
|
+
if (!isRecord14(raw)) return void 0;
|
|
60896
62011
|
const csp = {};
|
|
60897
62012
|
for (const key of CSP_DOMAIN_KEYS) {
|
|
60898
62013
|
const value = raw[key];
|
|
@@ -60902,7 +62017,7 @@ function cspOf(raw) {
|
|
|
60902
62017
|
}
|
|
60903
62018
|
return Object.keys(csp).length > 0 ? csp : void 0;
|
|
60904
62019
|
}
|
|
60905
|
-
function
|
|
62020
|
+
function isRecord14(v) {
|
|
60906
62021
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
60907
62022
|
}
|
|
60908
62023
|
function errorMessage(err) {
|
|
@@ -63139,14 +64254,14 @@ function createActivityProjector(opts) {
|
|
|
63139
64254
|
if (current && isTerminalActivityState(current.state)) {
|
|
63140
64255
|
return Promise.resolve(current);
|
|
63141
64256
|
}
|
|
63142
|
-
return new Promise((
|
|
64257
|
+
return new Promise((resolve47) => {
|
|
63143
64258
|
let settled = false;
|
|
63144
64259
|
const finish = (value) => {
|
|
63145
64260
|
if (settled) return;
|
|
63146
64261
|
settled = true;
|
|
63147
64262
|
clearTimeout(timer);
|
|
63148
64263
|
unsubscribeWait();
|
|
63149
|
-
|
|
64264
|
+
resolve47(value);
|
|
63150
64265
|
};
|
|
63151
64266
|
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
63152
64267
|
const unsubscribeWait = opts.sessionEvents.on("activity:changed", (ev) => {
|
|
@@ -63308,7 +64423,7 @@ function createApprovalsEngine(opts) {
|
|
|
63308
64423
|
const list2 = waiters.get(record2.id);
|
|
63309
64424
|
if (!list2) return;
|
|
63310
64425
|
waiters.delete(record2.id);
|
|
63311
|
-
for (const
|
|
64426
|
+
for (const resolve47 of list2) resolve47(record2);
|
|
63312
64427
|
};
|
|
63313
64428
|
const emit = (type, record2) => {
|
|
63314
64429
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -63378,17 +64493,17 @@ function createApprovalsEngine(opts) {
|
|
|
63378
64493
|
const current = liveGet(id);
|
|
63379
64494
|
if (!current) return Promise.resolve(void 0);
|
|
63380
64495
|
if (current.status !== "pending") return Promise.resolve(current);
|
|
63381
|
-
return new Promise((
|
|
64496
|
+
return new Promise((resolve47) => {
|
|
63382
64497
|
const list2 = waiters.get(id) ?? [];
|
|
63383
|
-
list2.push(
|
|
64498
|
+
list2.push(resolve47);
|
|
63384
64499
|
waiters.set(id, list2);
|
|
63385
64500
|
const timer = setTimeout(() => {
|
|
63386
64501
|
const list22 = waiters.get(id);
|
|
63387
64502
|
if (!list22) return;
|
|
63388
|
-
const idx = list22.indexOf(
|
|
64503
|
+
const idx = list22.indexOf(resolve47);
|
|
63389
64504
|
if (idx >= 0) list22.splice(idx, 1);
|
|
63390
64505
|
if (list22.length === 0) waiters.delete(id);
|
|
63391
|
-
|
|
64506
|
+
resolve47(liveGet(id));
|
|
63392
64507
|
}, timeoutMs);
|
|
63393
64508
|
timer.unref?.();
|
|
63394
64509
|
});
|
|
@@ -63551,7 +64666,7 @@ function humanizeKey(key) {
|
|
|
63551
64666
|
const words = key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_\-.]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase();
|
|
63552
64667
|
return words.length === 0 ? "Value" : words.charAt(0).toUpperCase() + words.slice(1);
|
|
63553
64668
|
}
|
|
63554
|
-
function
|
|
64669
|
+
function isRecord15(value) {
|
|
63555
64670
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
63556
64671
|
}
|
|
63557
64672
|
function scalarText(value) {
|
|
@@ -63581,7 +64696,7 @@ function flattenRows(value, label, depth, out) {
|
|
|
63581
64696
|
});
|
|
63582
64697
|
return;
|
|
63583
64698
|
}
|
|
63584
|
-
if (
|
|
64699
|
+
if (isRecord15(value)) {
|
|
63585
64700
|
if (depth >= MAX_DEPTH) return;
|
|
63586
64701
|
for (const [key, child] of Object.entries(value)) {
|
|
63587
64702
|
flattenRows(child, label ? `${label} / ${humanizeKey(key)}` : humanizeKey(key), depth + 1, out);
|
|
@@ -63603,7 +64718,7 @@ function renderMail(preview2) {
|
|
|
63603
64718
|
const cc = addressList(preview2.cc);
|
|
63604
64719
|
const subject = scalarText(preview2.subject) ?? "";
|
|
63605
64720
|
const body = scalarText(preview2.body) ?? "";
|
|
63606
|
-
const attachments = Array.isArray(preview2.attachments) ? preview2.attachments.filter(
|
|
64721
|
+
const attachments = Array.isArray(preview2.attachments) ? preview2.attachments.filter(isRecord15).map((a) => {
|
|
63607
64722
|
const name = scalarText(a.fileName) ?? "";
|
|
63608
64723
|
const size = typeof a.sizeBytes === "number" ? humanSize(a.sizeBytes) : "";
|
|
63609
64724
|
return size ? `${name} (${size})` : name;
|
|
@@ -63618,9 +64733,9 @@ function renderMail(preview2) {
|
|
|
63618
64733
|
}
|
|
63619
64734
|
function renderPreview(record2) {
|
|
63620
64735
|
const preview2 = record2.preview;
|
|
63621
|
-
if (
|
|
64736
|
+
if (isRecord15(preview2) && preview2.kind === "mail") return renderMail(preview2);
|
|
63622
64737
|
const rows = [];
|
|
63623
|
-
if (
|
|
64738
|
+
if (isRecord15(preview2)) {
|
|
63624
64739
|
for (const [key, value] of Object.entries(preview2)) flattenRows(value, humanizeKey(key), 1, rows);
|
|
63625
64740
|
} else {
|
|
63626
64741
|
flattenRows(preview2, "Details", 1, rows);
|
|
@@ -65717,9 +66832,9 @@ async function* readEventRecords(path) {
|
|
|
65717
66832
|
let stream;
|
|
65718
66833
|
try {
|
|
65719
66834
|
stream = createReadStream(path, { encoding: "utf8" });
|
|
65720
|
-
await new Promise((
|
|
66835
|
+
await new Promise((resolve47, reject) => {
|
|
65721
66836
|
stream.once("error", reject);
|
|
65722
|
-
stream.once("open",
|
|
66837
|
+
stream.once("open", resolve47);
|
|
65723
66838
|
});
|
|
65724
66839
|
} catch (err) {
|
|
65725
66840
|
if (err.code === "ENOENT") return;
|
|
@@ -66177,13 +67292,13 @@ function createLinkGuard(opts) {
|
|
|
66177
67292
|
return {
|
|
66178
67293
|
async start() {
|
|
66179
67294
|
server = createServer(onRequest);
|
|
66180
|
-
return new Promise((
|
|
67295
|
+
return new Promise((resolve47, reject) => {
|
|
66181
67296
|
server.once("error", reject);
|
|
66182
67297
|
server.listen(0, "127.0.0.1", () => {
|
|
66183
67298
|
log(
|
|
66184
67299
|
`[link-guard] listening on 127.0.0.1:${currentPort()} -> ${opts.target.host}:${opts.target.port}`
|
|
66185
67300
|
);
|
|
66186
|
-
|
|
67301
|
+
resolve47(handle());
|
|
66187
67302
|
});
|
|
66188
67303
|
});
|
|
66189
67304
|
},
|
|
@@ -66191,8 +67306,8 @@ function createLinkGuard(opts) {
|
|
|
66191
67306
|
if (!server) return;
|
|
66192
67307
|
const toClose = server;
|
|
66193
67308
|
server = null;
|
|
66194
|
-
await new Promise((
|
|
66195
|
-
toClose.close((err) => err ? reject(err) :
|
|
67309
|
+
await new Promise((resolve47, reject) => {
|
|
67310
|
+
toClose.close((err) => err ? reject(err) : resolve47());
|
|
66196
67311
|
});
|
|
66197
67312
|
},
|
|
66198
67313
|
revoke() {
|
|
@@ -68203,13 +69318,13 @@ function createJoinTokenRegistry(deps2) {
|
|
|
68203
69318
|
return { create, list, revoke, startAutoconnect, shutdown };
|
|
68204
69319
|
}
|
|
68205
69320
|
function sleep2(ms, signal) {
|
|
68206
|
-
return new Promise((
|
|
68207
|
-
if (signal.aborted) return
|
|
68208
|
-
const timer = setTimeout(
|
|
69321
|
+
return new Promise((resolve47) => {
|
|
69322
|
+
if (signal.aborted) return resolve47();
|
|
69323
|
+
const timer = setTimeout(resolve47, ms);
|
|
68209
69324
|
if (typeof timer.unref === "function") timer.unref();
|
|
68210
69325
|
signal.addEventListener("abort", () => {
|
|
68211
69326
|
clearTimeout(timer);
|
|
68212
|
-
|
|
69327
|
+
resolve47();
|
|
68213
69328
|
});
|
|
68214
69329
|
});
|
|
68215
69330
|
}
|
|
@@ -68899,7 +70014,14 @@ async function createGateway(opts) {
|
|
|
68899
70014
|
registry: sessions,
|
|
68900
70015
|
followStore: sessionFollowStore,
|
|
68901
70016
|
sentinelStore,
|
|
68902
|
-
cancelSentinel: (id) => cancelSentinelWatch(
|
|
70017
|
+
cancelSentinel: (id) => cancelSentinelWatch(
|
|
70018
|
+
{
|
|
70019
|
+
store: sentinelStore,
|
|
70020
|
+
resolveProvider: resolveSentinelProviderResolved,
|
|
70021
|
+
tombstones: sentinelRuntime.cancelTombstones
|
|
70022
|
+
},
|
|
70023
|
+
id
|
|
70024
|
+
)
|
|
68903
70025
|
});
|
|
68904
70026
|
const inboundWatcher = opts.resolveAgentAdapter ? createInboundWatcher({
|
|
68905
70027
|
mcpProxy,
|
|
@@ -69281,6 +70403,7 @@ async function createGateway(opts) {
|
|
|
69281
70403
|
registerSentinelTools(server, {
|
|
69282
70404
|
store: sentinelStore,
|
|
69283
70405
|
runtime: sentinelRuntime,
|
|
70406
|
+
tombstones: sentinelRuntime.cancelTombstones,
|
|
69284
70407
|
resolveProvider: resolveSentinelProviderResolved,
|
|
69285
70408
|
isSessionAlive,
|
|
69286
70409
|
...callerSessionId ? { callerSessionId } : {}
|
|
@@ -69310,11 +70433,39 @@ async function createGateway(opts) {
|
|
|
69310
70433
|
unsubscribe: (params) => eventsUnsubscribe(params, {
|
|
69311
70434
|
principal: eventsPrincipal,
|
|
69312
70435
|
store: sentinelStore,
|
|
69313
|
-
resolveProvider: resolveSentinelProviderResolved
|
|
70436
|
+
resolveProvider: resolveSentinelProviderResolved,
|
|
70437
|
+
tombstones: sentinelRuntime.cancelTombstones
|
|
69314
70438
|
})
|
|
69315
70439
|
});
|
|
69316
70440
|
return server;
|
|
69317
70441
|
};
|
|
70442
|
+
const eventsSecret = process.env.AGENTPROTO_MCP_EVENTS_SECRET ?? "";
|
|
70443
|
+
const eventsRepos = (process.env.AGENTPROTO_MCP_EVENTS_REPOS ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
70444
|
+
const eventsMcp = eventsSecret.length >= 32 ? {
|
|
70445
|
+
secret: eventsSecret,
|
|
70446
|
+
allowedOrigins: (process.env.AGENTPROTO_MCP_EVENTS_ORIGINS ?? "").split(",").map((s) => s.trim()).filter(Boolean),
|
|
70447
|
+
createServer: async () => {
|
|
70448
|
+
const principal = sessionPrincipal("mcp-events-origin");
|
|
70449
|
+
return createEventsSurfaceServer({
|
|
70450
|
+
version: opts.version ?? "0.1.0-alpha",
|
|
70451
|
+
repoAllowlist: eventsRepos,
|
|
70452
|
+
handlers: {
|
|
70453
|
+
list: (params) => eventsList(params, { principal }),
|
|
70454
|
+
subscribe: (params) => eventsSubscribe(params, {
|
|
70455
|
+
principal,
|
|
70456
|
+
store: sentinelStore,
|
|
70457
|
+
resolveProvider: resolveSentinelProviderResolved
|
|
70458
|
+
}),
|
|
70459
|
+
unsubscribe: (params) => eventsUnsubscribe(params, {
|
|
70460
|
+
principal,
|
|
70461
|
+
store: sentinelStore,
|
|
70462
|
+
resolveProvider: resolveSentinelProviderResolved,
|
|
70463
|
+
tombstones: sentinelRuntime.cancelTombstones
|
|
70464
|
+
})
|
|
70465
|
+
}
|
|
70466
|
+
});
|
|
70467
|
+
}
|
|
70468
|
+
} : void 0;
|
|
69318
70469
|
let internalToolServerPromise;
|
|
69319
70470
|
dispatchToolBox.fn = async (name, inputs) => {
|
|
69320
70471
|
if (!internalToolServerPromise) internalToolServerPromise = mcpServerFactory();
|
|
@@ -69385,6 +70536,7 @@ async function createGateway(opts) {
|
|
|
69385
70536
|
},
|
|
69386
70537
|
mcpServerFactory,
|
|
69387
70538
|
orchestratorMcpServerFactory,
|
|
70539
|
+
...eventsMcp ? { eventsMcp } : {},
|
|
69388
70540
|
verifyOrchestratorScope: scopeTokens.verify,
|
|
69389
70541
|
conversations,
|
|
69390
70542
|
events,
|
|
@@ -69402,7 +70554,8 @@ async function createGateway(opts) {
|
|
|
69402
70554
|
store: sentinelStore,
|
|
69403
70555
|
resolveProvider: resolveSentinelProviderResolved,
|
|
69404
70556
|
isSessionAlive,
|
|
69405
|
-
runtime: sentinelRuntime
|
|
70557
|
+
runtime: sentinelRuntime,
|
|
70558
|
+
tombstones: sentinelRuntime.cancelTombstones
|
|
69406
70559
|
},
|
|
69407
70560
|
follows: {
|
|
69408
70561
|
store: sessionFollowStore,
|
|
@@ -69595,7 +70748,12 @@ async function createGateway(opts) {
|
|
|
69595
70748
|
}, pendingPromptSweepMs);
|
|
69596
70749
|
pendingPromptTimer.unref?.();
|
|
69597
70750
|
const livenessSweepIntervalMs = 3e4;
|
|
70751
|
+
const livenessTickGuard = createLivenessTickGuard(livenessSweepIntervalMs, 5e3);
|
|
69598
70752
|
const livenessSweepTimer = setInterval(() => {
|
|
70753
|
+
if (livenessTickGuard.shouldSkip()) {
|
|
70754
|
+
console.warn("[liveness-sweep] tick fired late (event loop starved) \u2014 skipping this sweep");
|
|
70755
|
+
return;
|
|
70756
|
+
}
|
|
69599
70757
|
try {
|
|
69600
70758
|
const orphanedRuns = workflowRunner?.sweep().orphaned ?? [];
|
|
69601
70759
|
if (orphanedRuns.length > 0) {
|
|
@@ -69746,6 +70904,6 @@ var export_readPairingsSnapshot = pairing_registry_exports.readPairingsSnapshot;
|
|
|
69746
70904
|
var export_removeProviderKey = providers_store_exports.removeProviderKey;
|
|
69747
70905
|
var export_setProviderKey = providers_store_exports.setProviderKey;
|
|
69748
70906
|
|
|
69749
|
-
export { AnthropicRemainingQuotaReader, AuthResolutionError, BUCKETS_ROOT, CLAMP_LIMIT_BYTES, CLAUDE_CODE_OAUTH_SOURCE, CONTINUE_PROMPT_SOURCE, DEAD_SESSION_STATUSES, DEFAULT_ALWAYS_ON_TOOLS, DEFAULT_BUCKET, DEFAULT_CONTINUE_PROMPT, DEFAULT_HOST_LOAD_BUDGET_MS, DEFAULT_HOST_LOAD_THRESHOLDS, DEFAULT_MODEL_ROLES, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_TTL_MS, DEFAULT_WORKTREE_ISOLATION, DEFAULT_WORKTREE_PROVISION_CONCURRENCY, DEVICE_PROMPT_PATH_PREFIX, EVENT_REGISTRY, FOLLOW_EVENTS, GC_REAPABLE_STATES, GITHUB_SCHEME, HOSTS_VERSION, HOST_HANDSHAKE_REMEDIATION_HINT, HOST_SCOPE_HEADER, HarnessPresetValidationError, INBOUND_PROVIDERS, INDEX_DEFAULT_LIMIT, INDEX_MAX_OUTPUT, INDEX_MAX_PROMPT, INDEX_TAIL_BYTES, JOIN_TOKENS_VERSION, LEGACY_SESSIONS_FILE, MAX_ATTEMPTS, MAX_AUTO_CONTINUE_ATTEMPTS, MAX_MESSAGE_DATA_BYTES, MAX_TTL_MS, MCP_APP_BRIDGE_SCRIPT, MESSAGE_KINDS, MESSAGE_PREAMBLE, MESSAGE_TAG, MESSAGE_URGENCIES, MIN_TTL_MS, MODEL_ROLE_REF_PREFIX, McpEventsError, NO_OUTPUT_STALL_TURN_ERROR, export_PAIRINGS_VERSION as PAIRINGS_VERSION, POSTURE_NATIVE_ALIASES, POSTURE_PREAMBLES, export_PROVIDER_ENV_VARS as PROVIDER_ENV_VARS, PrLookupError, ResumeDisabledError, SESSION_END_REASONS, SESSION_ID_ENV, SIGN_NAMESPACE, SessionRetiredError, SsrfFetchError, SubscriptionSourceError, TASK_STATUSES, WORKSPACE_SLUG_ENV, WORKTREE_ISOLATION_ENV, WORKTREE_PROVISION_CONCURRENCY_ENV, activityCounts, addHarnessPreset, allowedSignersLine, appendConversationRecord, attachSandbox, backfillSessionIndexes, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogModels, buildCatalogProviderModels, buildHostLoadReport, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, buildSessionRecap, canonicalForModeId, canonicalizeJcs, challengeCacheSize, challengeReasonForSsrf, claudeProjectSlug, collectGcCandidates, collectHostSample, compactOutcome, composeMode, composeSessionObservers, composedFromRangeSha, computeHostWarnings, computeRefreshBefore, continueInterruptedSessions, continueSkipReason, conversationIndexPath, createActivityProjector, createDaemonReviewerHost, createDefaultHostProbes, createDeviceRegistry, createFileStepCache, createGateway, createHostLoadService, createHostRegistry, createInboundEndpointStore, createJoinTokenRegistry, createOrchestratorInjector, createOrchestratorMcpServerFactory, export_createPairingRegistry as createPairingRegistry, createPrProvenanceReconciler, createProcessStatsService, createReviewLaneExecutor, createReviewLedger, createReviewPackLoader, createReviewRunner, createScopeTokenRegistry, createSentinelWebhookOutbox, createSessionFollowStore, createSessionMessage, createSupervisorTaskGateRunner, createTaskLedger, createWorkspaceBrainSubscriber, createWorkspaceBrains, createWorkspaceFs, credentialFingerprint, daemonBearerPrincipal, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, decodeWhsecSecret, decomposeMode, defaultBrowserAdapterIds, defaultBrowserAdapterResolution, defaultReviewKeysDir, defaultReviewLedgerRoot, defaultReviewPackCacheDir, defaultTranscriptBaseDir, defineBraveSearchHttpDriver, defineSerperHttpDriver, deleteUserPreset, deliverEventEnvelope, deliveryBackoffDelay, deriveIndexFromTranscript, deriveSessionOutcome, deriveSessionUsage, describeOwner, encodeWhsecSecret, enrichRollupWithProviderQuota, enrichWithRemainingQuota, ensureReviewSigningKey, envelopeClampedBytes, escapeHumanPrompt, escapeMessageBody, evaluateCostBudget, eventsList, eventsSubscribe, eventsUnsubscribe, execGh, extractHelpSection, fetchHostTurns, fetchPrStatus, fileConversationStore, fileExists3 as fileExists, filterActivities, findComposeCandidate, findConversationRecord, findEventDefinition, findNativeMode, findPrForCommit, formatToolCall, formatToolResult, getDefaultHarnessPreset, getHarnessPreset, getHostLoadService, getMcpCredentialDeps, getProcessStatsService, export_getProviderKey as getProviderKey, getToolHelp, getUserPreset, githubRepoOf, harnessPresetsPath, hostPlaceholders, hostRecordToMirrorRecord, indexEntryFromDescriptor, injectMcpAppBridge, export_injectProviderKeysIntoEnv as injectProviderKeysIntoEnv, isAgentCliAuthConfigured, isAutomatedPromptSource, isClosedTaskStatus, isKnownSessionEndReason, isMessageAllowed, isNoSessionPromptFailure, isProviderLimitError, isPubliclyRoutable, isRetired, isSafeBucketSlug, isTerminalActivityState, listBuckets, listHarnessPresets, listModelRoles, listPresets, listToolHelpTopics, listUserPresets, loadHarnessPresets, export_loadProviders as loadProviders, loadQuotaStore, loadUserPresets, loadWorkspaceModelRoles, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, makeRestartForRouting, makeSandboxCredsStore, makeSandboxResolver, matchesMessageFilter, matchesSessionQuery, measureTool, measureToolList, messageFrom, migrateLegacySessionsFile, migrationMarkerPath, mintMessageId, mirrorCursorForSession, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeCallbackUrl, normalizeCommand, normalizeInbound, normalizeModeId, normalizeRemote, normalizeSkillsOption, normalizeWorktreeField, parseAnthropicRateLimitHeaders, parseDuration, parseModelRoleRef, parsePrUrl, parseTaskStatus, parseWindow, parseWorktreeIsolationMode, pickUsageDetail, policyToActivities, policyWatchesSession, prHeadSha, prToActivities, projectBrowserTools, projectSessionUsage, promptDeviceSession, promptHostSession, export_providerEnvVar as providerEnvVar, export_providersPath as providersPath, readAllSessionIndexes, readConversationIndex, readDaemonRegistry, readHostsSnapshot, export_readPairingsSnapshot as readPairingsSnapshot, readProfileQuota, readRegisteredSlugs, readRuntimeMeta, readSandboxLedger, readSessionForBrain, readSessionIndex, readTranscriptTail, readUsageSnapshots, reapGcEntry, reapOrphanedDescendants, reconcileSandboxLedger, recordProfileQuota, recordSandboxBoot, recordSandboxLiveness, recordSandboxOrigin, recordSandboxState, registerBrainTools, registerBuiltinRoutes, registerDeviceTools, registerPairingTools, registerReviewTools, registerSandboxAttachTool, registerWebSearchTools, removeHarnessPreset, export_removeProviderKey as removeProviderKey, removeSandboxLedgerEntry, renderInboxDigest, renderSessionMessage, renderSessionMessages, repoSlug, resetChallengeCacheForTests, resolveAuthSpec, resolveBucketSlug, resolveDeferredToolsGatewayOption, resolveDevicePromptMapping, resolveEffectiveLlmEndpointFlag, resolveModelRole, resolveNativeLink, resolvePosture, resolvePrincipal, resolveRelation, resolveReuseFromLedger, resolveReviewerPreset, resolveSpawnDefaults, resolveSubscriptionCredential, resolveSuccessor, rollupSessionSubtree, rollupUsage, runContinueOnBootPass, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runShellLane, runStallWatchdogPass, sandboxLedgerPath, sanitizeLabel, saveUserPreset, searchSessionIndexes, seedWalkForTranscript, serializeEnvelope, sessionEventsPath, sessionIndexPath, sessionPrincipal, sessionTranscriptDir, setDefaultPreset, setDefaultSessionsBaseDir, setEgressDispatcherForTests, setMcpCredentialDeps, export_setProviderKey as setProviderKey, signAttestation, signWebhook, ssrfFetch, subscriptionId, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, syncDeviceMirror, tenantScope, toMcpEvent, toWebhookEnvelope, toWorktreeStatusView, trackWorktreeProvision, turnToActivities, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, untilForTtl, updateHarnessPreset, upsertSandboxLedger, userPresetsPath, validateAgainstInputSchema, verifyCallback, verifyInboundSignature, verifySignedAttestation, webSearchTool, webhookRequestId, wireSessionFollow, withPr, withPrStatus, workflowToActivities, writeDaemonRegistryEntry, writeSessionIndex };
|
|
70907
|
+
export { AnthropicRemainingQuotaReader, AuthResolutionError, BUCKETS_ROOT, CLAMP_LIMIT_BYTES, CLAUDE_CODE_OAUTH_SOURCE, CONTINUE_PROMPT_SOURCE, DEAD_SESSION_STATUSES, DEFAULT_ALWAYS_ON_TOOLS, DEFAULT_BUCKET, DEFAULT_CONTINUE_PROMPT, DEFAULT_HOST_LOAD_BUDGET_MS, DEFAULT_HOST_LOAD_THRESHOLDS, DEFAULT_MODEL_ROLES, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_TTL_MS, DEFAULT_WORKTREE_ISOLATION, DEFAULT_WORKTREE_PROVISION_CONCURRENCY, DEVICE_PROMPT_PATH_PREFIX, EVENT_REGISTRY, FOLLOW_EVENTS, GC_REAPABLE_STATES, GITHUB_SCHEME, HOSTS_VERSION, HOST_HANDSHAKE_REMEDIATION_HINT, HOST_SCOPE_HEADER, HarnessPresetValidationError, INBOUND_PROVIDERS, INDEX_DEFAULT_LIMIT, INDEX_MAX_OUTPUT, INDEX_MAX_PROMPT, INDEX_TAIL_BYTES, JOIN_TOKENS_VERSION, LEGACY_SESSIONS_FILE, MAX_ATTEMPTS, MAX_AUTO_CONTINUE_ATTEMPTS, MAX_MESSAGE_DATA_BYTES, MAX_TTL_MS, MCP_APP_BRIDGE_SCRIPT, MESSAGE_KINDS, MESSAGE_PREAMBLE, MESSAGE_TAG, MESSAGE_URGENCIES, MIN_TTL_MS, MODEL_ROLE_REF_PREFIX, McpEventsError, NO_OUTPUT_STALL_TURN_ERROR, export_PAIRINGS_VERSION as PAIRINGS_VERSION, POSTURE_NATIVE_ALIASES, POSTURE_PREAMBLES, export_PROVIDER_ENV_VARS as PROVIDER_ENV_VARS, PrLookupError, ResumeDisabledError, SESSION_END_REASONS, SESSION_ID_ENV, SIGN_NAMESPACE, SentinelBackingExpiredError, SessionRetiredError, SsrfFetchError, SubscriptionSourceError, TASK_STATUSES, WORKSPACE_SLUG_ENV, WORKTREE_ISOLATION_ENV, WORKTREE_PROVISION_CONCURRENCY_ENV, activityCounts, addHarnessPreset, allowedSignersLine, appendConversationRecord, attachSandbox, backfillSessionIndexes, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogModels, buildCatalogProviderModels, buildHostLoadReport, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, buildSessionRecap, canonicalForModeId, canonicalizeJcs, challengeCacheSize, challengeReasonForSsrf, claudeProjectSlug, collectGcCandidates, collectHostSample, compactOutcome, composeMode, composeSessionObservers, composedFromRangeSha, computeHostWarnings, computeRefreshBefore, continueInterruptedSessions, continueSkipReason, conversationIndexPath, createActivityProjector, createDaemonReviewerHost, createDefaultHostProbes, createDeviceRegistry, createFileStepCache, createGateway, createHostLoadService, createHostRegistry, createInboundEndpointStore, createJoinTokenRegistry, createOrchestratorInjector, createOrchestratorMcpServerFactory, export_createPairingRegistry as createPairingRegistry, createPrProvenanceReconciler, createProcessStatsService, createReviewLaneExecutor, createReviewLedger, createReviewPackLoader, createReviewRunner, createScopeTokenRegistry, createSentinelWebhookOutbox, createSessionFollowStore, createSessionMessage, createSupervisorTaskGateRunner, createTaskLedger, createWorkspaceBrainSubscriber, createWorkspaceBrains, createWorkspaceFs, credentialFingerprint, daemonBearerPrincipal, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, decodeWhsecSecret, decomposeMode, defaultBrowserAdapterIds, defaultBrowserAdapterResolution, defaultReviewKeysDir, defaultReviewLedgerRoot, defaultReviewPackCacheDir, defaultTranscriptBaseDir, defineBraveSearchHttpDriver, defineSerperHttpDriver, deleteUserPreset, deliverEventEnvelope, deliveryBackoffDelay, deriveIndexFromTranscript, deriveSessionOutcome, deriveSessionUsage, describeOwner, encodeWhsecSecret, enrichRollupWithProviderQuota, enrichWithRemainingQuota, ensureReviewSigningKey, envelopeClampedBytes, escapeHumanPrompt, escapeMessageBody, evaluateCostBudget, eventsList, eventsSubscribe, eventsUnsubscribe, execGh, extractHelpSection, fetchHostTurns, fetchPrStatus, fileConversationStore, fileExists3 as fileExists, filterActivities, findComposeCandidate, findConversationRecord, findEventDefinition, findNativeMode, findPrForCommit, formatToolCall, formatToolResult, getDefaultHarnessPreset, getHarnessPreset, getHostLoadService, getMcpCredentialDeps, getProcessStatsService, export_getProviderKey as getProviderKey, getToolHelp, getUserPreset, githubRepoOf, harnessPresetsPath, hostPlaceholders, hostRecordToMirrorRecord, indexEntryFromDescriptor, injectMcpAppBridge, export_injectProviderKeysIntoEnv as injectProviderKeysIntoEnv, isAgentCliAuthConfigured, isAutomatedPromptSource, isClosedTaskStatus, isKnownSessionEndReason, isMessageAllowed, isNoSessionPromptFailure, isProviderLimitError, isPubliclyRoutable, isRetired, isSafeBucketSlug, isTerminalActivityState, listBuckets, listHarnessPresets, listModelRoles, listPresets, listToolHelpTopics, listUserPresets, loadHarnessPresets, export_loadProviders as loadProviders, loadQuotaStore, loadUserPresets, loadWorkspaceModelRoles, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, makeRestartForRouting, makeSandboxCredsStore, makeSandboxResolver, matchesMessageFilter, matchesSessionQuery, measureTool, measureToolList, messageFrom, migrateLegacySessionsFile, migrationMarkerPath, mintMessageId, mirrorCursorForSession, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeCallbackUrl, normalizeCommand, normalizeInbound, normalizeModeId, normalizeRemote, normalizeSkillsOption, normalizeWorktreeField, parseAnthropicRateLimitHeaders, parseDuration, parseModelRoleRef, parsePrUrl, parseTaskStatus, parseWindow, parseWorktreeIsolationMode, pickUsageDetail, policyToActivities, policyWatchesSession, prHeadSha, prToActivities, projectBrowserTools, projectSessionUsage, promptDeviceSession, promptHostSession, export_providerEnvVar as providerEnvVar, export_providersPath as providersPath, readAllSessionIndexes, readConversationIndex, readDaemonRegistry, readHostsSnapshot, export_readPairingsSnapshot as readPairingsSnapshot, readProfileQuota, readRegisteredSlugs, readRuntimeMeta, readSandboxLedger, readSessionForBrain, readSessionIndex, readTranscriptTail, readUsageSnapshots, reapGcEntry, reapOrphanedDescendants, reconcileSandboxLedger, recordProfileQuota, recordSandboxBoot, recordSandboxLiveness, recordSandboxOrigin, recordSandboxState, registerBrainTools, registerBuiltinRoutes, registerDeviceTools, registerPairingTools, registerReviewTools, registerSandboxAttachTool, registerWebSearchTools, removeHarnessPreset, export_removeProviderKey as removeProviderKey, removeSandboxLedgerEntry, renderInboxDigest, renderSessionMessage, renderSessionMessages, repoSlug, resetChallengeCacheForTests, resolveAuthSpec, resolveBucketSlug, resolveDeferredToolsGatewayOption, resolveDevicePromptMapping, resolveEffectiveLlmEndpointFlag, resolveModelRole, resolveNativeLink, resolvePosture, resolvePrincipal, resolveRelation, resolveReuseFromLedger, resolveReviewerPreset, resolveSpawnDefaults, resolveSubscriptionCredential, resolveSuccessor, rollupSessionSubtree, rollupUsage, runContinueOnBootPass, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runShellLane, runStallWatchdogPass, sandboxLedgerPath, sanitizeLabel, saveUserPreset, searchSessionIndexes, seedWalkForTranscript, serializeEnvelope, sessionEventsPath, sessionIndexPath, sessionPrincipal, sessionTranscriptDir, setDefaultPreset, setDefaultSessionsBaseDir, setEgressDispatcherForTests, setMcpCredentialDeps, export_setProviderKey as setProviderKey, signAttestation, signWebhook, ssrfFetch, subscriptionId, summarizeBranchGcApply, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, syncDeviceMirror, tenantScope, toMcpEvent, toWebhookEnvelope, toWorktreeStatusView, trackWorktreeProvision, turnToActivities, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, untilForTtl, updateHarnessPreset, upsertSandboxLedger, userPresetsPath, validateAgainstInputSchema, verifyCallback, verifyInboundSignature, verifySignedAttestation, webSearchTool, webhookRequestId, wireSessionFollow, withBranchGcApplySummary, withPr, withPrStatus, workflowToActivities, writeDaemonRegistryEntry, writeSessionIndex };
|
|
69750
70908
|
//# sourceMappingURL=index.mjs.map
|
|
69751
70909
|
//# sourceMappingURL=index.mjs.map
|