@agentproto/runtime 5.8.0 → 5.9.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/catalog-models.mjs +38 -2
- package/dist/catalog-models.mjs.map +1 -1
- package/dist/config-schema.mjs +13 -0
- package/dist/config-schema.mjs.map +1 -1
- package/dist/config.mjs +13 -0
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.ts +761 -60
- package/dist/index.mjs +1225 -217
- package/dist/index.mjs.map +1 -1
- package/dist/resume-strategies.d.ts +22 -1
- package/dist/resume-strategies.mjs +2 -1
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/session-presence.mjs +13 -0
- package/dist/session-presence.mjs.map +1 -1
- package/dist/{sessions-SrISpFsH.d.ts → sessions-Cse9PhLG.d.ts} +102 -6
- package/dist/user-presets.d.ts +1 -1
- package/package.json +9 -9
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { execFile, spawn, execFileSync } from 'child_process';
|
|
2
2
|
import { readFile, unlink, mkdir, writeFile, readdir, stat, readlink, chmod, mkdtemp, rm, rename, copyFile, realpath, appendFile, open, access } from 'fs/promises';
|
|
3
3
|
import { homedir, freemem, loadavg, totalmem, cpus, hostname, tmpdir } from 'os';
|
|
4
|
-
import { join, resolve, dirname,
|
|
4
|
+
import { join, resolve, dirname, isAbsolute, basename, normalize as normalize$1, relative, sep, extname, delimiter } from 'path';
|
|
5
5
|
import { canonicalizePath, resolveCommandSandbox, loadAdapterSpawnSandboxConfig, loadSandboxConfig, COMMAND_SANDBOX_MODE_ENV } from '@agentproto/command-sandbox';
|
|
6
6
|
import { ensureChromeDevtoolsMcp, resolveChrome, buildHeadlessBrowserMcpEntry, headlessBrowserReadPaths } from '@agentproto/plugin-local-browser';
|
|
7
7
|
import { resolvePricing, getModelProvider, resolveContextWindow, formatTokens, LLM_PRICING_CATALOG, resolvePricingExact, splitContextWindowHint, MODEL_ALIASES, isKnownLlmId } from '@agentproto/model-catalog/llm';
|
|
8
8
|
import { randomBytes, randomUUID, timingSafeEqual, createHmac, createHash } from 'crypto';
|
|
9
|
-
import { createReadStream, promises, readFileSync, mkdirSync, writeFileSync, renameSync, readdirSync,
|
|
9
|
+
import { createReadStream, promises, readFileSync, mkdirSync, writeFileSync, renameSync, readdirSync, openSync, fstatSync, readSync, closeSync, existsSync, statSync, mkdtempSync, chmodSync, realpathSync, cpSync, appendFileSync, createWriteStream } from 'fs';
|
|
10
10
|
import { createInterface } from 'readline';
|
|
11
11
|
import * as providers_store_star from '@agentproto/providers-store';
|
|
12
12
|
import { resolveCustomRoute, registerCustomRoute, formatModelRef, resolveLlmModelRoute, tryParseModelRef, stripRouteSuffix, stripFixedNativeVendor } from '@agentproto/model-catalog/route-identity';
|
|
@@ -29,7 +29,7 @@ import { SandboxSpecSchema, resolveLifecyclePolicy, createSandboxAgentSessionHos
|
|
|
29
29
|
import { APP_UI_DISCOVERY_TOOLS, RUNNER_SELECT_SCRIPT } from '@agentproto/app-client/runner-select';
|
|
30
30
|
import { DISPLAY_MODE_SCRIPT } from '@agentproto/app-client/display-mode';
|
|
31
31
|
import { defineTool, catchErrors, ToolError, pageParamsShape, paginated, toToolResult, paginate, toolText } from '@agentproto/tool';
|
|
32
|
-
import { toMcpTool, createMcpServer, registerBuiltinTool, registerUiResource } from '@agentproto/mcp-server';
|
|
32
|
+
import { toMcpTool, createMcpServer, registerBuiltinTool, registerUiResource, registerEventsMethods } from '@agentproto/mcp-server';
|
|
33
33
|
import { SESSION_CHAT_APP_ID, liveSessionApp, makeLiveSessionApp, sessionsPanelApp, agentsOverviewApp, bureauSessionsApp, sessionStoryApp, workBoardApp, reviewPanelApp, makeSessionsPanelApp, makeAgentsOverviewApp, makeBureauSessionsApp, makeSessionStoryPanelApp, makeSessionChatApp, makeWorkBoardApp, makeReviewPanelApp, sessionChatApp } from '@agentproto/apps';
|
|
34
34
|
import { EventEmitter } from 'events';
|
|
35
35
|
import { inferLegacyModeKind, parseModelSwitchCommand, isModelSwitchAcknowledgement } from '@agentproto/driver-agent-cli';
|
|
@@ -2827,7 +2827,7 @@ function tokenizeCommand(s) {
|
|
|
2827
2827
|
if (buf) out.push(buf);
|
|
2828
2828
|
return out;
|
|
2829
2829
|
}
|
|
2830
|
-
var RESUME_STRATEGIES, RESUME_ID_REJECTED_RE;
|
|
2830
|
+
var RESUME_STRATEGIES, RESUME_ID_REJECTED_RE, RESUME_CONNECTION_LOST_RE;
|
|
2831
2831
|
var init_resume_strategies = __esm({
|
|
2832
2832
|
"src/resume-strategies.ts"() {
|
|
2833
2833
|
init_conversation_store();
|
|
@@ -2856,6 +2856,7 @@ var init_resume_strategies = __esm({
|
|
|
2856
2856
|
})
|
|
2857
2857
|
);
|
|
2858
2858
|
RESUME_ID_REJECTED_RE = /not found|does not support|not supported|unsupported/i;
|
|
2859
|
+
RESUME_CONNECTION_LOST_RE = /connection closed|connection lost|epipe/i;
|
|
2859
2860
|
}
|
|
2860
2861
|
});
|
|
2861
2862
|
function writeCommandLogEntry(sessionId, entry, baseDir) {
|
|
@@ -7284,6 +7285,36 @@ var init_bundles = __esm({
|
|
|
7284
7285
|
};
|
|
7285
7286
|
}
|
|
7286
7287
|
});
|
|
7288
|
+
function directAuthMethods(descriptor, endpoint) {
|
|
7289
|
+
const methods = [];
|
|
7290
|
+
if (subscriptionSurfaceFor(descriptor?.authSubscription, endpoint) !== void 0) {
|
|
7291
|
+
methods.push("oauth-bearer");
|
|
7292
|
+
}
|
|
7293
|
+
if (descriptor?.provider || descriptor?.modelDerivedApiKey) methods.push("api-key");
|
|
7294
|
+
return methods;
|
|
7295
|
+
}
|
|
7296
|
+
function spawnEligibilityManifest(adapter, descriptor, route, model) {
|
|
7297
|
+
const directEndpoint = descriptor?.provider ?? (model ? descriptor?.modelProviders?.[model] : void 0) ?? (model && descriptor?.modelDerivedApiKey ? modelIdPrefixProvider(model) : void 0) ?? (model ? getModelProvider(model) : void 0);
|
|
7298
|
+
const routeId = route?.gateway ?? directEndpoint;
|
|
7299
|
+
if (!routeId) return void 0;
|
|
7300
|
+
const direct = directEndpoint !== void 0 && routeId === directEndpoint;
|
|
7301
|
+
return {
|
|
7302
|
+
manifest: {
|
|
7303
|
+
id: adapter,
|
|
7304
|
+
endpointByRoute: { [routeId]: direct ? directEndpoint : routeId },
|
|
7305
|
+
methodsByRoute: {
|
|
7306
|
+
[routeId]: direct ? directAuthMethods(descriptor, directEndpoint) : ["api-key"]
|
|
7307
|
+
}
|
|
7308
|
+
},
|
|
7309
|
+
routeId,
|
|
7310
|
+
direct
|
|
7311
|
+
};
|
|
7312
|
+
}
|
|
7313
|
+
var init_eligibility_manifest = __esm({
|
|
7314
|
+
"src/eligibility-manifest.ts"() {
|
|
7315
|
+
init_spawn_defaults();
|
|
7316
|
+
}
|
|
7317
|
+
});
|
|
7287
7318
|
function normalizeRouterPrefixedId(id) {
|
|
7288
7319
|
const firstSlash = id.indexOf("/");
|
|
7289
7320
|
if (firstSlash === -1) return id;
|
|
@@ -7508,6 +7539,7 @@ function buildCatalogModels(input) {
|
|
|
7508
7539
|
];
|
|
7509
7540
|
const merged = mergeContributions(contributions);
|
|
7510
7541
|
const query = input.query ?? {};
|
|
7542
|
+
const queryAdapter = query.adapter ? input.adapters.find((a) => a.slug === query.adapter) : void 0;
|
|
7511
7543
|
const servableByRoute = /* @__PURE__ */ new Map();
|
|
7512
7544
|
for (const row of merged) {
|
|
7513
7545
|
const set = servableByRoute.get(row.route) ?? /* @__PURE__ */ new Set();
|
|
@@ -7522,12 +7554,18 @@ function buildCatalogModels(input) {
|
|
|
7522
7554
|
if (query.adapter && !row.adapters.includes(query.adapter)) continue;
|
|
7523
7555
|
const isDirectVendorRoute = row.route === row.vendor && row.adapterModes.length === 0;
|
|
7524
7556
|
const walletEligible = !isDirectVendorRoute || checkModelWalletEligibility(`${row.vendor}/${row.product}`, row.route).ok;
|
|
7525
|
-
const
|
|
7557
|
+
const projected = queryAdapter === void 0 ? void 0 : queryAdapter.authDescriptor ? spawnEligibilityManifest(
|
|
7558
|
+
queryAdapter.slug,
|
|
7559
|
+
queryAdapter.authDescriptor,
|
|
7560
|
+
{ gateway: row.route },
|
|
7561
|
+
row.ref
|
|
7562
|
+
) : null;
|
|
7563
|
+
const manifest = projected?.manifest ?? {
|
|
7526
7564
|
id: `${row.vendor}/${row.product}@${row.route}`,
|
|
7527
7565
|
endpointByRoute: { [row.route]: billedVendor(row.vendor, row.route) },
|
|
7528
7566
|
methodsByRoute: { [row.route]: row.methods }
|
|
7529
7567
|
};
|
|
7530
|
-
const eligible = walletEligible ? eligibleProfiles(input.profiles, manifest, row.route).filter(
|
|
7568
|
+
const eligible = walletEligible && projected !== null ? eligibleProfiles(input.profiles, manifest, projected?.routeId ?? row.route).filter(
|
|
7531
7569
|
(p) => profileAllowsModel(p, row.ref, `${row.vendor}/${row.product}`)
|
|
7532
7570
|
) : [];
|
|
7533
7571
|
const runnable = eligible.length > 0;
|
|
@@ -7680,6 +7718,7 @@ var WIDENING_ROUTES, VENDOR_COMPATIBILITY_ROUTES;
|
|
|
7680
7718
|
var init_catalog_models = __esm({
|
|
7681
7719
|
"src/catalog-models.ts"() {
|
|
7682
7720
|
init_spawn_defaults();
|
|
7721
|
+
init_eligibility_manifest();
|
|
7683
7722
|
WIDENING_ROUTES = [
|
|
7684
7723
|
"openrouter",
|
|
7685
7724
|
"requesty",
|
|
@@ -10105,35 +10144,10 @@ function findWorktreeLabelCwdCollision(registry, excludeId, label, cwd) {
|
|
|
10105
10144
|
function profileMethodToAuthMode(method) {
|
|
10106
10145
|
return method === "oauth-bearer" ? "subscription" : "api-key";
|
|
10107
10146
|
}
|
|
10108
|
-
function directAuthMethods(descriptor, endpoint) {
|
|
10109
|
-
const methods = [];
|
|
10110
|
-
if (subscriptionSurfaceFor(descriptor?.authSubscription, endpoint) !== void 0) {
|
|
10111
|
-
methods.push("oauth-bearer");
|
|
10112
|
-
}
|
|
10113
|
-
if (descriptor?.provider || descriptor?.modelDerivedApiKey) methods.push("api-key");
|
|
10114
|
-
return methods;
|
|
10115
|
-
}
|
|
10116
10147
|
function subscriptionOauthMethodId(descriptor, provider) {
|
|
10117
10148
|
if (!Array.isArray(descriptor?.authSubscription) || !provider) return void 0;
|
|
10118
10149
|
return `${provider}-oauth`;
|
|
10119
10150
|
}
|
|
10120
|
-
function spawnEligibilityManifest(adapter, descriptor, route, model) {
|
|
10121
|
-
const directEndpoint = descriptor?.provider ?? (model ? descriptor?.modelProviders?.[model] : void 0) ?? (model && descriptor?.modelDerivedApiKey ? modelIdPrefixProvider(model) : void 0) ?? (model ? getModelProvider(model) : void 0);
|
|
10122
|
-
const routeId = route?.gateway ?? directEndpoint;
|
|
10123
|
-
if (!routeId) return void 0;
|
|
10124
|
-
const direct = directEndpoint !== void 0 && routeId === directEndpoint;
|
|
10125
|
-
return {
|
|
10126
|
-
manifest: {
|
|
10127
|
-
id: adapter,
|
|
10128
|
-
endpointByRoute: { [routeId]: direct ? directEndpoint : routeId },
|
|
10129
|
-
methodsByRoute: {
|
|
10130
|
-
[routeId]: direct ? directAuthMethods(descriptor, directEndpoint) : ["api-key"]
|
|
10131
|
-
}
|
|
10132
|
-
},
|
|
10133
|
-
routeId,
|
|
10134
|
-
direct
|
|
10135
|
-
};
|
|
10136
|
-
}
|
|
10137
10151
|
function resolveProfileAwareRoute(adapter, authDescriptor, profile, model) {
|
|
10138
10152
|
if (!model) return void 0;
|
|
10139
10153
|
const eligibleCandidates = serviceableModelRoutes(model).map((gateway) => spawnEligibilityManifest(adapter, authDescriptor, { gateway }, model)).filter(
|
|
@@ -12246,6 +12260,7 @@ var init_session_spawn = __esm({
|
|
|
12246
12260
|
init_bundles();
|
|
12247
12261
|
init_mcp_imports();
|
|
12248
12262
|
init_launch_config();
|
|
12263
|
+
init_eligibility_manifest();
|
|
12249
12264
|
init_claude_code_oauth_source();
|
|
12250
12265
|
init_providers_store();
|
|
12251
12266
|
init_catalog_models();
|
|
@@ -16638,6 +16653,267 @@ var init_session_end_reason = __esm({
|
|
|
16638
16653
|
PROVIDER_LIMIT_ERROR_RE = /\bhit your (?:session|usage) limit\b/i;
|
|
16639
16654
|
}
|
|
16640
16655
|
});
|
|
16656
|
+
function sessionIndexPath(sessionId, baseDir) {
|
|
16657
|
+
return join(sessionTranscriptDir(sessionId, baseDir), "index.json");
|
|
16658
|
+
}
|
|
16659
|
+
function capText(text13, max) {
|
|
16660
|
+
const flat = text13.replace(/\s+/g, " ").trim();
|
|
16661
|
+
const points = Array.from(flat);
|
|
16662
|
+
if (points.length <= max) return flat;
|
|
16663
|
+
return points.slice(0, max - 1).join("") + "\u2026";
|
|
16664
|
+
}
|
|
16665
|
+
function isRecord5(value) {
|
|
16666
|
+
return typeof value === "object" && value !== null;
|
|
16667
|
+
}
|
|
16668
|
+
function indexEntryFromDescriptor(desc, extra) {
|
|
16669
|
+
const entry = {
|
|
16670
|
+
id: desc.id,
|
|
16671
|
+
kind: desc.kind,
|
|
16672
|
+
status: desc.status,
|
|
16673
|
+
alive: desc.status === "running" || desc.status === "starting",
|
|
16674
|
+
startedAt: desc.startedAt
|
|
16675
|
+
};
|
|
16676
|
+
if (desc.label !== void 0) entry.label = desc.label;
|
|
16677
|
+
if (desc.title !== void 0) entry.title = desc.title;
|
|
16678
|
+
if (desc.renamedByUser !== void 0) entry.renamedByUser = desc.renamedByUser;
|
|
16679
|
+
if (desc.adapterSlug !== void 0) entry.adapter = desc.adapterSlug;
|
|
16680
|
+
if (desc.model !== void 0) entry.model = desc.model;
|
|
16681
|
+
if (desc.cwd !== void 0) entry.cwd = desc.cwd;
|
|
16682
|
+
if (desc.workspaceSlug !== void 0) entry.workspaceSlug = desc.workspaceSlug;
|
|
16683
|
+
if (desc.origin !== void 0) entry.origin = desc.origin;
|
|
16684
|
+
if (desc.depth !== void 0) entry.depth = desc.depth;
|
|
16685
|
+
if (desc.parentSessionId !== void 0) entry.parentSessionId = desc.parentSessionId;
|
|
16686
|
+
if (desc.lastActivityAt !== void 0) entry.lastActivityAt = desc.lastActivityAt;
|
|
16687
|
+
if (desc.lastTurnReason !== void 0) entry.lastTurnReason = desc.lastTurnReason;
|
|
16688
|
+
if (desc.turnsCompleted !== void 0) entry.turnsCompleted = desc.turnsCompleted;
|
|
16689
|
+
if (desc.costUsd !== void 0) entry.costUsd = desc.costUsd;
|
|
16690
|
+
const prompt = extra?.lastUserPrompt;
|
|
16691
|
+
if (prompt && prompt.text.trim()) {
|
|
16692
|
+
entry.lastUserPrompt = { ts: prompt.ts, text: capText(prompt.text, INDEX_MAX_PROMPT) };
|
|
16693
|
+
}
|
|
16694
|
+
const output = extra?.lastOutputText;
|
|
16695
|
+
if (output && output.trim()) entry.lastOutputText = capText(output, INDEX_MAX_OUTPUT);
|
|
16696
|
+
return entry;
|
|
16697
|
+
}
|
|
16698
|
+
function readSessionIndex(sessionId, baseDir) {
|
|
16699
|
+
let raw;
|
|
16700
|
+
try {
|
|
16701
|
+
raw = readFileSync(sessionIndexPath(sessionId, baseDir), "utf8");
|
|
16702
|
+
} catch {
|
|
16703
|
+
return void 0;
|
|
16704
|
+
}
|
|
16705
|
+
let parsed;
|
|
16706
|
+
try {
|
|
16707
|
+
parsed = JSON.parse(raw);
|
|
16708
|
+
} catch {
|
|
16709
|
+
return void 0;
|
|
16710
|
+
}
|
|
16711
|
+
if (!isRecord5(parsed) || typeof parsed.id !== "string" || parsed.id.length === 0) return void 0;
|
|
16712
|
+
return parsed;
|
|
16713
|
+
}
|
|
16714
|
+
function writeSessionIndex(entry, baseDir) {
|
|
16715
|
+
try {
|
|
16716
|
+
const dir = sessionTranscriptDir(entry.id, baseDir);
|
|
16717
|
+
mkdirSync(dir, { recursive: true });
|
|
16718
|
+
const finalPath = join(dir, "index.json");
|
|
16719
|
+
const tmpPath = `${finalPath}.tmp`;
|
|
16720
|
+
writeFileSync(tmpPath, JSON.stringify(entry) + "\n");
|
|
16721
|
+
renameSync(tmpPath, finalPath);
|
|
16722
|
+
} catch {
|
|
16723
|
+
}
|
|
16724
|
+
}
|
|
16725
|
+
function readTranscriptTail(eventsPath2, maxBytes = INDEX_TAIL_BYTES) {
|
|
16726
|
+
const empty = { prompts: [], bytesRead: 0 };
|
|
16727
|
+
let fd;
|
|
16728
|
+
try {
|
|
16729
|
+
fd = openSync(eventsPath2, "r");
|
|
16730
|
+
} catch {
|
|
16731
|
+
return empty;
|
|
16732
|
+
}
|
|
16733
|
+
let tail;
|
|
16734
|
+
let bytesRead = 0;
|
|
16735
|
+
try {
|
|
16736
|
+
const size = fstatSync(fd).size;
|
|
16737
|
+
const len = Math.min(size, Math.max(0, maxBytes));
|
|
16738
|
+
if (len === 0) return empty;
|
|
16739
|
+
const buf = Buffer.alloc(len);
|
|
16740
|
+
readSync(fd, buf, 0, len, size - len);
|
|
16741
|
+
bytesRead = len;
|
|
16742
|
+
tail = buf.toString("utf8");
|
|
16743
|
+
} catch {
|
|
16744
|
+
return empty;
|
|
16745
|
+
} finally {
|
|
16746
|
+
closeSync(fd);
|
|
16747
|
+
}
|
|
16748
|
+
const prompts = [];
|
|
16749
|
+
let assistant = "";
|
|
16750
|
+
let lastOutputText;
|
|
16751
|
+
let firstTs;
|
|
16752
|
+
const sealAssistant = () => {
|
|
16753
|
+
const t = assistant.trim();
|
|
16754
|
+
if (t) lastOutputText = t;
|
|
16755
|
+
assistant = "";
|
|
16756
|
+
};
|
|
16757
|
+
for (const line of tail.split("\n")) {
|
|
16758
|
+
const trimmed = line.trim();
|
|
16759
|
+
if (!trimmed) continue;
|
|
16760
|
+
let rec;
|
|
16761
|
+
try {
|
|
16762
|
+
rec = JSON.parse(trimmed);
|
|
16763
|
+
} catch {
|
|
16764
|
+
continue;
|
|
16765
|
+
}
|
|
16766
|
+
if (firstTs === void 0 && typeof rec.ts === "string") firstTs = rec.ts;
|
|
16767
|
+
if (rec.kind === "user-prompt" && typeof rec.text === "string") {
|
|
16768
|
+
sealAssistant();
|
|
16769
|
+
if (rec.text.trim()) {
|
|
16770
|
+
prompts.push({ ts: typeof rec.ts === "string" ? rec.ts : "", text: rec.text });
|
|
16771
|
+
}
|
|
16772
|
+
} else if (rec.kind === "text-delta" && typeof rec.text === "string") {
|
|
16773
|
+
assistant += rec.text;
|
|
16774
|
+
} else if (rec.kind === "tool-call" || rec.kind === "tool-result" || rec.kind === "turn-end") {
|
|
16775
|
+
sealAssistant();
|
|
16776
|
+
}
|
|
16777
|
+
}
|
|
16778
|
+
sealAssistant();
|
|
16779
|
+
return { prompts, ...lastOutputText !== void 0 ? { lastOutputText } : {}, bytesRead, ...firstTs !== void 0 ? { firstTs } : {} };
|
|
16780
|
+
}
|
|
16781
|
+
function deriveIndexFromTranscript(sessionId, baseDir) {
|
|
16782
|
+
const eventsPath2 = sessionEventsPath(sessionId, baseDir);
|
|
16783
|
+
if (!existsSync(eventsPath2)) return void 0;
|
|
16784
|
+
const tail = readTranscriptTail(eventsPath2);
|
|
16785
|
+
let startedAt;
|
|
16786
|
+
try {
|
|
16787
|
+
const stat19 = statSync(eventsPath2);
|
|
16788
|
+
if (stat19.birthtimeMs > 0) startedAt = stat19.birthtime.toISOString();
|
|
16789
|
+
else startedAt = stat19.mtime.toISOString();
|
|
16790
|
+
} catch {
|
|
16791
|
+
}
|
|
16792
|
+
startedAt = startedAt ?? tail.firstTs ?? (/* @__PURE__ */ new Date(0)).toISOString();
|
|
16793
|
+
const lastPrompt = tail.prompts[tail.prompts.length - 1];
|
|
16794
|
+
return {
|
|
16795
|
+
id: sessionId,
|
|
16796
|
+
kind: "agent-cli",
|
|
16797
|
+
status: "unknown",
|
|
16798
|
+
alive: false,
|
|
16799
|
+
startedAt,
|
|
16800
|
+
...lastPrompt ? { lastUserPrompt: { ts: lastPrompt.ts, text: capText(lastPrompt.text, INDEX_MAX_PROMPT) } } : {},
|
|
16801
|
+
...tail.lastOutputText ? { lastOutputText: capText(tail.lastOutputText, INDEX_MAX_OUTPUT) } : {}
|
|
16802
|
+
};
|
|
16803
|
+
}
|
|
16804
|
+
function readAllSessionIndexes(baseDir) {
|
|
16805
|
+
const dir = baseDir ?? defaultTranscriptBaseDir();
|
|
16806
|
+
let entries;
|
|
16807
|
+
try {
|
|
16808
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
16809
|
+
} catch {
|
|
16810
|
+
return [];
|
|
16811
|
+
}
|
|
16812
|
+
const out = [];
|
|
16813
|
+
for (const ent of entries) {
|
|
16814
|
+
if (!ent.isDirectory()) continue;
|
|
16815
|
+
const id = ent.name;
|
|
16816
|
+
const index = readSessionIndex(id, dir);
|
|
16817
|
+
if (index) {
|
|
16818
|
+
out.push(index);
|
|
16819
|
+
continue;
|
|
16820
|
+
}
|
|
16821
|
+
const derived = deriveIndexFromTranscript(id, dir);
|
|
16822
|
+
if (derived) out.push(derived);
|
|
16823
|
+
}
|
|
16824
|
+
out.sort((a, b) => (b.lastActivityAt ?? b.startedAt).localeCompare(a.lastActivityAt ?? a.startedAt));
|
|
16825
|
+
return out;
|
|
16826
|
+
}
|
|
16827
|
+
function matchesSessionQuery(entry, query) {
|
|
16828
|
+
const q = query.trim().toLowerCase();
|
|
16829
|
+
if (!q) return true;
|
|
16830
|
+
if (entry.id.toLowerCase().startsWith(q)) return true;
|
|
16831
|
+
for (const field of [entry.label, entry.title, entry.cwd, entry.workspaceSlug]) {
|
|
16832
|
+
if (field && field.toLowerCase().includes(q)) return true;
|
|
16833
|
+
}
|
|
16834
|
+
return false;
|
|
16835
|
+
}
|
|
16836
|
+
function searchSessionIndexes(entries, query, opts = {}) {
|
|
16837
|
+
const limit = opts.limit ?? INDEX_DEFAULT_LIMIT;
|
|
16838
|
+
return entries.filter((e) => matchesSessionQuery(e, query)).filter((e) => opts.status ? e.status === opts.status : true).sort((a, b) => (b.lastActivityAt ?? b.startedAt).localeCompare(a.lastActivityAt ?? a.startedAt)).slice(0, Math.max(0, limit));
|
|
16839
|
+
}
|
|
16840
|
+
function buildSessionRecap(input) {
|
|
16841
|
+
const { entry } = input;
|
|
16842
|
+
const last = input.last ?? 8;
|
|
16843
|
+
const tail = readTranscriptTail(input.eventsPath);
|
|
16844
|
+
const source = tail.prompts.length > 0 ? tail.prompts : entry.lastUserPrompt ? [entry.lastUserPrompt] : [];
|
|
16845
|
+
const prompts = source.slice(Math.max(0, source.length - last));
|
|
16846
|
+
const lastOutputText = tail.lastOutputText ?? entry.lastOutputText;
|
|
16847
|
+
return {
|
|
16848
|
+
id: entry.id,
|
|
16849
|
+
status: entry.status,
|
|
16850
|
+
alive: entry.alive,
|
|
16851
|
+
...entry.label !== void 0 ? { label: entry.label } : {},
|
|
16852
|
+
...entry.title !== void 0 ? { title: entry.title } : {},
|
|
16853
|
+
...entry.adapter !== void 0 ? { adapter: entry.adapter } : {},
|
|
16854
|
+
...entry.model !== void 0 ? { model: entry.model } : {},
|
|
16855
|
+
...entry.cwd !== void 0 ? { cwd: entry.cwd } : {},
|
|
16856
|
+
...entry.workspaceSlug !== void 0 ? { workspaceSlug: entry.workspaceSlug } : {},
|
|
16857
|
+
...entry.parentSessionId !== void 0 ? { parentSessionId: entry.parentSessionId } : {},
|
|
16858
|
+
children: [...input.children ?? []],
|
|
16859
|
+
startedAt: entry.startedAt,
|
|
16860
|
+
...entry.lastActivityAt !== void 0 ? { lastActivityAt: entry.lastActivityAt } : {},
|
|
16861
|
+
...entry.turnsCompleted !== void 0 ? { turnsCompleted: entry.turnsCompleted } : {},
|
|
16862
|
+
...entry.costUsd !== void 0 ? { costUsd: entry.costUsd } : {},
|
|
16863
|
+
...entry.lastTurnReason !== void 0 ? { lastTurnReason: entry.lastTurnReason } : {},
|
|
16864
|
+
prompts,
|
|
16865
|
+
...lastOutputText ? { lastOutputText: capText(lastOutputText, INDEX_MAX_OUTPUT) } : {},
|
|
16866
|
+
...input.queuedPrompts !== void 0 ? { queuedPrompts: input.queuedPrompts } : {}
|
|
16867
|
+
};
|
|
16868
|
+
}
|
|
16869
|
+
function backfillSessionIndexes(baseDir, opts) {
|
|
16870
|
+
const dir = baseDir ?? defaultTranscriptBaseDir();
|
|
16871
|
+
const byId = /* @__PURE__ */ new Map();
|
|
16872
|
+
if (opts?.descriptors) {
|
|
16873
|
+
for (const desc of opts.descriptors) byId.set(desc.id, desc);
|
|
16874
|
+
}
|
|
16875
|
+
let dirents;
|
|
16876
|
+
try {
|
|
16877
|
+
dirents = readdirSync(dir, { withFileTypes: true });
|
|
16878
|
+
} catch {
|
|
16879
|
+
return { scanned: 0, created: 0, skipped: 0 };
|
|
16880
|
+
}
|
|
16881
|
+
let scanned = 0;
|
|
16882
|
+
let created = 0;
|
|
16883
|
+
let skipped = 0;
|
|
16884
|
+
for (const ent of dirents) {
|
|
16885
|
+
if (!ent.isDirectory()) continue;
|
|
16886
|
+
scanned++;
|
|
16887
|
+
const id = ent.name;
|
|
16888
|
+
if (readSessionIndex(id, dir)) {
|
|
16889
|
+
skipped++;
|
|
16890
|
+
continue;
|
|
16891
|
+
}
|
|
16892
|
+
const desc = byId.get(id);
|
|
16893
|
+
const derived = deriveIndexFromTranscript(id, dir);
|
|
16894
|
+
if (!desc && !derived) {
|
|
16895
|
+
skipped++;
|
|
16896
|
+
continue;
|
|
16897
|
+
}
|
|
16898
|
+
const entry = desc ? indexEntryFromDescriptor(desc, {
|
|
16899
|
+
...derived?.lastUserPrompt ? { lastUserPrompt: derived.lastUserPrompt } : {},
|
|
16900
|
+
...derived?.lastOutputText ? { lastOutputText: derived.lastOutputText } : {}
|
|
16901
|
+
}) : derived;
|
|
16902
|
+
writeSessionIndex(entry, dir);
|
|
16903
|
+
created++;
|
|
16904
|
+
}
|
|
16905
|
+
return { scanned, created, skipped };
|
|
16906
|
+
}
|
|
16907
|
+
var INDEX_MAX_PROMPT, INDEX_MAX_OUTPUT, INDEX_TAIL_BYTES, INDEX_DEFAULT_LIMIT;
|
|
16908
|
+
var init_session_index = __esm({
|
|
16909
|
+
"src/session-index.ts"() {
|
|
16910
|
+
init_transcript_writer();
|
|
16911
|
+
INDEX_MAX_PROMPT = 500;
|
|
16912
|
+
INDEX_MAX_OUTPUT = 300;
|
|
16913
|
+
INDEX_TAIL_BYTES = 256 * 1024;
|
|
16914
|
+
INDEX_DEFAULT_LIMIT = 20;
|
|
16915
|
+
}
|
|
16916
|
+
});
|
|
16641
16917
|
function isBackgroundToolCallArguments(args) {
|
|
16642
16918
|
return typeof args === "object" && args !== null && args.run_in_background === true;
|
|
16643
16919
|
}
|
|
@@ -16817,6 +17093,7 @@ function toSessionSummary(desc) {
|
|
|
16817
17093
|
blockedOn: desc.blockedOn,
|
|
16818
17094
|
stalledSinceMs: desc.stalledSinceMs,
|
|
16819
17095
|
pendingBgTasks: desc.pendingBgTasks,
|
|
17096
|
+
...desc.wrapupFlag ? { wrapupFlag: desc.wrapupFlag } : {},
|
|
16820
17097
|
backgroundTasks: desc.backgroundTasks,
|
|
16821
17098
|
lastTurnErroredAt: desc.lastTurnErroredAt,
|
|
16822
17099
|
...desc.lastError ? { lastError: desc.lastError.slice(0, 2e3) } : {},
|
|
@@ -16945,6 +17222,18 @@ function stampInterrupted(desc) {
|
|
|
16945
17222
|
delete desc.interrupted;
|
|
16946
17223
|
}
|
|
16947
17224
|
}
|
|
17225
|
+
function stampAdapterConnected(desc, rt) {
|
|
17226
|
+
const probe = rt.agentSession?.isConnected;
|
|
17227
|
+
if (!probe) {
|
|
17228
|
+
delete desc.adapterConnected;
|
|
17229
|
+
return;
|
|
17230
|
+
}
|
|
17231
|
+
try {
|
|
17232
|
+
desc.adapterConnected = probe.call(rt.agentSession);
|
|
17233
|
+
} catch {
|
|
17234
|
+
delete desc.adapterConnected;
|
|
17235
|
+
}
|
|
17236
|
+
}
|
|
16948
17237
|
function stampLiveModes(desc, rt) {
|
|
16949
17238
|
const modes = rt.agentSession?.availableModes;
|
|
16950
17239
|
if (modes && modes.length > 0) {
|
|
@@ -16956,6 +17245,9 @@ function stampLiveModes(desc, rt) {
|
|
|
16956
17245
|
function isResumable(desc) {
|
|
16957
17246
|
return desc.kind === "agent-cli" && !!desc.adapterSlug && !!desc.adapterSessionId && !!desc.cwd && !desc.archived;
|
|
16958
17247
|
}
|
|
17248
|
+
function crashReasonText(reason, pid) {
|
|
17249
|
+
return reason === "transport-closed" ? `adapter connection closed (pid ${pid ?? "?"} may still be running) \u2014 session crashed` : `adapter process gone (pid ${pid}) \u2014 session crashed`;
|
|
17250
|
+
}
|
|
16959
17251
|
function canResume(desc) {
|
|
16960
17252
|
return isResumable(desc) && (desc.resumeAttempts ?? 0) < MAX_RESUME_ATTEMPTS;
|
|
16961
17253
|
}
|
|
@@ -17194,6 +17486,7 @@ function createSessionsRegistry(opts) {
|
|
|
17194
17486
|
}
|
|
17195
17487
|
}
|
|
17196
17488
|
recordOutcome(rt);
|
|
17489
|
+
writeIndexNow(rt);
|
|
17197
17490
|
rt.linkProbeStop?.();
|
|
17198
17491
|
cancelPendingPermissionsForSession(rt);
|
|
17199
17492
|
if (runWorktreeAutoReclaim && rt.desc.worktreeAutoProvisioned && rt.desc.worktreePath) {
|
|
@@ -17428,6 +17721,53 @@ function createSessionsRegistry(opts) {
|
|
|
17428
17721
|
void persistSnapshot();
|
|
17429
17722
|
}, PERSIST_DEBOUNCE_MS2);
|
|
17430
17723
|
};
|
|
17724
|
+
const INDEX_WRITE_THROTTLE_MS = 400;
|
|
17725
|
+
const dirtyIndexIds = /* @__PURE__ */ new Set();
|
|
17726
|
+
let indexFlushTimer;
|
|
17727
|
+
const captureIndexTail = (rt) => {
|
|
17728
|
+
let lastUserPrompt = rt.lastUserPrompt;
|
|
17729
|
+
let lastOutputText = rt.lastAssistantText;
|
|
17730
|
+
if (lastUserPrompt === void 0 || lastOutputText === void 0) {
|
|
17731
|
+
const tail = readTranscriptTail(sessionEventsPath(rt.desc.id, transcriptBaseDir), INDEX_TAIL_BYTES);
|
|
17732
|
+
if (lastUserPrompt === void 0 && tail.prompts.length > 0) {
|
|
17733
|
+
lastUserPrompt = tail.prompts[tail.prompts.length - 1];
|
|
17734
|
+
}
|
|
17735
|
+
if (lastOutputText === void 0) lastOutputText = tail.lastOutputText;
|
|
17736
|
+
}
|
|
17737
|
+
return {
|
|
17738
|
+
...lastUserPrompt ? { lastUserPrompt } : {},
|
|
17739
|
+
...lastOutputText ? { lastOutputText } : {}
|
|
17740
|
+
};
|
|
17741
|
+
};
|
|
17742
|
+
const writeIndexNow = (rt) => {
|
|
17743
|
+
try {
|
|
17744
|
+
writeSessionIndex(indexEntryFromDescriptor(rt.desc, captureIndexTail(rt)), transcriptBaseDir);
|
|
17745
|
+
} catch {
|
|
17746
|
+
}
|
|
17747
|
+
};
|
|
17748
|
+
const flushDirtyIndexes = () => {
|
|
17749
|
+
if (indexFlushTimer) {
|
|
17750
|
+
clearTimeout(indexFlushTimer);
|
|
17751
|
+
indexFlushTimer = void 0;
|
|
17752
|
+
}
|
|
17753
|
+
if (dirtyIndexIds.size === 0) return;
|
|
17754
|
+
const ids = [...dirtyIndexIds];
|
|
17755
|
+
dirtyIndexIds.clear();
|
|
17756
|
+
for (const id of ids) {
|
|
17757
|
+
const rt = sessions.get(id);
|
|
17758
|
+
if (rt) writeIndexNow(rt);
|
|
17759
|
+
}
|
|
17760
|
+
};
|
|
17761
|
+
const scheduleIndexWrite = (rt) => {
|
|
17762
|
+
if (shutdownDone) return;
|
|
17763
|
+
dirtyIndexIds.add(rt.desc.id);
|
|
17764
|
+
if (indexFlushTimer) return;
|
|
17765
|
+
indexFlushTimer = setTimeout(() => {
|
|
17766
|
+
indexFlushTimer = void 0;
|
|
17767
|
+
flushDirtyIndexes();
|
|
17768
|
+
}, INDEX_WRITE_THROTTLE_MS);
|
|
17769
|
+
indexFlushTimer.unref?.();
|
|
17770
|
+
};
|
|
17431
17771
|
const conversationLinkProbeMs = opts?.conversationLinkProbeMs ?? {
|
|
17432
17772
|
initialMs: 3e3,
|
|
17433
17773
|
intervalMs: 15e3
|
|
@@ -18030,7 +18370,12 @@ function createSessionsRegistry(opts) {
|
|
|
18030
18370
|
schedulePersist();
|
|
18031
18371
|
};
|
|
18032
18372
|
const maybeResumeAgent = async (rt, resumedFrom = "daemon-restart") => {
|
|
18033
|
-
if (rt.agentSession)
|
|
18373
|
+
if (rt.agentSession) {
|
|
18374
|
+
if (rt.agentSession.isConnected?.() === false) {
|
|
18375
|
+
markCrashedInternal(rt.desc.id, "transport-closed");
|
|
18376
|
+
}
|
|
18377
|
+
if (rt.agentSession) return;
|
|
18378
|
+
}
|
|
18034
18379
|
if (!resumeAgent) return;
|
|
18035
18380
|
if (!isResumable(rt.desc)) return;
|
|
18036
18381
|
if (!canResume(rt.desc)) {
|
|
@@ -18076,7 +18421,7 @@ function createSessionsRegistry(opts) {
|
|
|
18076
18421
|
recordFailedResume(rt);
|
|
18077
18422
|
return;
|
|
18078
18423
|
}
|
|
18079
|
-
rt
|
|
18424
|
+
bindAgentSession(rt, fresh);
|
|
18080
18425
|
bindOutOfTurnEvents(rt);
|
|
18081
18426
|
stampCapabilities(rt);
|
|
18082
18427
|
rt.adapterSlug = adapterSlug;
|
|
@@ -18133,6 +18478,48 @@ function createSessionsRegistry(opts) {
|
|
|
18133
18478
|
rt.resumePromise = void 0;
|
|
18134
18479
|
}
|
|
18135
18480
|
};
|
|
18481
|
+
const markCrashedInternal = (id, reason = "process-gone") => {
|
|
18482
|
+
const rt = sessions.get(id);
|
|
18483
|
+
if (!rt) return false;
|
|
18484
|
+
if (rt.desc.kind !== "agent-cli" || rt.desc.status !== "running") {
|
|
18485
|
+
return false;
|
|
18486
|
+
}
|
|
18487
|
+
const pid = rt.desc.pid;
|
|
18488
|
+
const providerLimitMessage = isProviderLimitError(rt.lastErrorMessage) ? rt.lastErrorMessage : void 0;
|
|
18489
|
+
const detail = providerLimitMessage ? `provider usage limit hit: ${providerLimitMessage}` : crashReasonText(reason, pid);
|
|
18490
|
+
rt.desc.status = "error";
|
|
18491
|
+
rt.desc.endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
18492
|
+
rt.desc.endedReason = providerLimitMessage ? "provider-limit" : "crashed";
|
|
18493
|
+
rt.desc.crashedAt = rt.desc.endedAt;
|
|
18494
|
+
rt.desc.lastError = detail;
|
|
18495
|
+
if (rt.agentSession) {
|
|
18496
|
+
releaseOutOfTurnEvents(rt);
|
|
18497
|
+
delete rt.desc.backgroundTasks;
|
|
18498
|
+
recordExitUsageSnapshot(rt);
|
|
18499
|
+
void rt.agentSession.close().catch(() => void 0);
|
|
18500
|
+
void transcriptWriter.close(rt.desc.id);
|
|
18501
|
+
tracedSessions.delete(rt.desc.id);
|
|
18502
|
+
rt.agentSession = void 0;
|
|
18503
|
+
}
|
|
18504
|
+
schedulePersist();
|
|
18505
|
+
const banner = providerLimitMessage ? `[provider-limit] ${providerLimitMessage}` : `[crashed] ${detail}`;
|
|
18506
|
+
appendLine(rt, banner, "stderr");
|
|
18507
|
+
transcriptWriter.recordEvent(rt.desc.id, { kind: "notice", text: banner });
|
|
18508
|
+
emitExited(rt);
|
|
18509
|
+
return true;
|
|
18510
|
+
};
|
|
18511
|
+
const bindAgentSession = (rt, session) => {
|
|
18512
|
+
rt.agentSession = session;
|
|
18513
|
+
session.onDisconnect?.((err) => {
|
|
18514
|
+
const id = rt.desc.id;
|
|
18515
|
+
if (rt.agentSession !== session) return;
|
|
18516
|
+
if (markCrashedInternal(id, "transport-closed")) {
|
|
18517
|
+
console.warn(
|
|
18518
|
+
`[sessions] ${id}: adapter connection closed (${err.message}) \u2014 marked crashed; the row stays lazy-resumable.`
|
|
18519
|
+
);
|
|
18520
|
+
}
|
|
18521
|
+
});
|
|
18522
|
+
};
|
|
18136
18523
|
const buildUsageSnapshot = (rt) => deriveSessionUsage({
|
|
18137
18524
|
...rt.desc.model !== void 0 ? { model: rt.desc.model } : {},
|
|
18138
18525
|
...rt.adapterReportedCost && rt.desc.costUsd !== void 0 ? { adapterCostUsd: rt.desc.costUsd } : {},
|
|
@@ -18592,6 +18979,7 @@ ${message}`;
|
|
|
18592
18979
|
...messageTurn ? { messages: turnOpts.messages } : {}
|
|
18593
18980
|
} : void 0
|
|
18594
18981
|
);
|
|
18982
|
+
rt.lastUserPrompt = { ts: (/* @__PURE__ */ new Date()).toISOString(), text: promptTextForIndex(message, turnOpts?.system) };
|
|
18595
18983
|
const wrapped = typeof message === "string" ? { type: "text", text: message } : message;
|
|
18596
18984
|
const switchCandidate = typeof message === "string" ? parseModelSwitchCommand(message) : void 0;
|
|
18597
18985
|
let switchLearned = false;
|
|
@@ -18829,6 +19217,7 @@ ${message}`;
|
|
|
18829
19217
|
});
|
|
18830
19218
|
}
|
|
18831
19219
|
}
|
|
19220
|
+
scheduleIndexWrite(rt);
|
|
18832
19221
|
if (!interruptedBy) dispatchQueuedPrompt(rt);
|
|
18833
19222
|
else if (interruptedBy.deliverQueueId) {
|
|
18834
19223
|
dispatchQueuedPrompt(rt, interruptedBy.deliverQueueId);
|
|
@@ -19123,6 +19512,10 @@ ${message}`;
|
|
|
19123
19512
|
};
|
|
19124
19513
|
const registry = {
|
|
19125
19514
|
bootId,
|
|
19515
|
+
transcriptBaseDir,
|
|
19516
|
+
flushSessionIndexes() {
|
|
19517
|
+
flushDirtyIndexes();
|
|
19518
|
+
},
|
|
19126
19519
|
recordAutoContinue(id) {
|
|
19127
19520
|
const rt = sessions.get(id);
|
|
19128
19521
|
if (!rt) return;
|
|
@@ -19199,6 +19592,7 @@ ${message}`;
|
|
|
19199
19592
|
emitExited(rt);
|
|
19200
19593
|
});
|
|
19201
19594
|
schedulePersist();
|
|
19595
|
+
writeIndexNow(rt);
|
|
19202
19596
|
return desc;
|
|
19203
19597
|
},
|
|
19204
19598
|
register(input) {
|
|
@@ -19248,6 +19642,7 @@ ${message}`;
|
|
|
19248
19642
|
emitExited(rt);
|
|
19249
19643
|
});
|
|
19250
19644
|
schedulePersist();
|
|
19645
|
+
writeIndexNow(rt);
|
|
19251
19646
|
return desc;
|
|
19252
19647
|
},
|
|
19253
19648
|
spawnAgent(input) {
|
|
@@ -19349,7 +19744,6 @@ ${message}`;
|
|
|
19349
19744
|
}
|
|
19350
19745
|
const rt = {
|
|
19351
19746
|
desc,
|
|
19352
|
-
agentSession: input.agentSession,
|
|
19353
19747
|
adapterSlug: input.adapterSlug,
|
|
19354
19748
|
recentLines: [],
|
|
19355
19749
|
recentBytes: [],
|
|
@@ -19366,6 +19760,7 @@ ${message}`;
|
|
|
19366
19760
|
rt.emitter.setMaxListeners(50);
|
|
19367
19761
|
sessions.set(id, rt);
|
|
19368
19762
|
linkContinuedTo(input.resumedFrom, id);
|
|
19763
|
+
bindAgentSession(rt, input.agentSession);
|
|
19369
19764
|
bindOutOfTurnEvents(rt);
|
|
19370
19765
|
stampCapabilities(rt);
|
|
19371
19766
|
armUsageRefresh(rt);
|
|
@@ -19383,6 +19778,7 @@ ${message}`;
|
|
|
19383
19778
|
"stdout"
|
|
19384
19779
|
);
|
|
19385
19780
|
schedulePersist();
|
|
19781
|
+
writeIndexNow(rt);
|
|
19386
19782
|
recordConversationLink(rt);
|
|
19387
19783
|
desc.eventsPath = sessionEventsPath(desc.id, transcriptBaseDir);
|
|
19388
19784
|
if (input.initialPrompt) {
|
|
@@ -19501,6 +19897,7 @@ ${message}`;
|
|
|
19501
19897
|
"stdout"
|
|
19502
19898
|
);
|
|
19503
19899
|
schedulePersist();
|
|
19900
|
+
writeIndexNow(rt);
|
|
19504
19901
|
desc.eventsPath = sessionEventsPath(desc.id, transcriptBaseDir);
|
|
19505
19902
|
return desc;
|
|
19506
19903
|
},
|
|
@@ -19556,7 +19953,7 @@ ${message}`;
|
|
|
19556
19953
|
emitExited(rt);
|
|
19557
19954
|
return;
|
|
19558
19955
|
}
|
|
19559
|
-
rt
|
|
19956
|
+
bindAgentSession(rt, outcome.agentSession);
|
|
19560
19957
|
bindOutOfTurnEvents(rt);
|
|
19561
19958
|
stampCapabilities(rt);
|
|
19562
19959
|
rt.readUsage = outcome.readUsage;
|
|
@@ -19578,6 +19975,7 @@ ${message}`;
|
|
|
19578
19975
|
"stdout"
|
|
19579
19976
|
);
|
|
19580
19977
|
schedulePersist();
|
|
19978
|
+
writeIndexNow(rt);
|
|
19581
19979
|
recordConversationLink(rt);
|
|
19582
19980
|
if (outcome.initialPrompt) {
|
|
19583
19981
|
void runAgentTurn(
|
|
@@ -19747,6 +20145,7 @@ ${message}`;
|
|
|
19747
20145
|
emitExited(rt);
|
|
19748
20146
|
});
|
|
19749
20147
|
schedulePersist();
|
|
20148
|
+
writeIndexNow(rt);
|
|
19750
20149
|
return desc;
|
|
19751
20150
|
},
|
|
19752
20151
|
recordCommand(input) {
|
|
@@ -20371,6 +20770,7 @@ ${message}`;
|
|
|
20371
20770
|
stampCurrentStatus(rt);
|
|
20372
20771
|
stampWatchers(desc);
|
|
20373
20772
|
stampLiveModes(desc, rt);
|
|
20773
|
+
stampAdapterConnected(desc, rt);
|
|
20374
20774
|
desc.childrenBusy = childrenBusy.get(desc.id) ?? 0;
|
|
20375
20775
|
desc.queuedPrompts = desc.promptQueue?.length ?? 0;
|
|
20376
20776
|
return desc;
|
|
@@ -20428,6 +20828,7 @@ ${message}`;
|
|
|
20428
20828
|
stampCurrentStatus(rt);
|
|
20429
20829
|
stampWatchers(desc);
|
|
20430
20830
|
stampLiveModes(desc, rt);
|
|
20831
|
+
stampAdapterConnected(desc, rt);
|
|
20431
20832
|
desc.childrenBusy = childrenBusyCounts().get(desc.id) ?? 0;
|
|
20432
20833
|
desc.queuedPrompts = desc.promptQueue?.length ?? 0;
|
|
20433
20834
|
}
|
|
@@ -20683,34 +21084,8 @@ ${message}`;
|
|
|
20683
21084
|
emitExited(rt);
|
|
20684
21085
|
return true;
|
|
20685
21086
|
},
|
|
20686
|
-
markCrashed(id) {
|
|
20687
|
-
|
|
20688
|
-
if (!rt) return false;
|
|
20689
|
-
if (rt.desc.kind !== "agent-cli" || rt.desc.status !== "running") {
|
|
20690
|
-
return false;
|
|
20691
|
-
}
|
|
20692
|
-
const pid = rt.desc.pid;
|
|
20693
|
-
const providerLimitMessage = isProviderLimitError(rt.lastErrorMessage) ? rt.lastErrorMessage : void 0;
|
|
20694
|
-
rt.desc.status = "error";
|
|
20695
|
-
rt.desc.endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20696
|
-
rt.desc.endedReason = providerLimitMessage ? "provider-limit" : "crashed";
|
|
20697
|
-
rt.desc.crashedAt = rt.desc.endedAt;
|
|
20698
|
-
rt.desc.lastError = providerLimitMessage ? `provider usage limit hit: ${providerLimitMessage}` : `adapter process gone (pid ${pid}) \u2014 session crashed`;
|
|
20699
|
-
if (rt.agentSession) {
|
|
20700
|
-
releaseOutOfTurnEvents(rt);
|
|
20701
|
-
delete rt.desc.backgroundTasks;
|
|
20702
|
-
recordExitUsageSnapshot(rt);
|
|
20703
|
-
void rt.agentSession.close().catch(() => void 0);
|
|
20704
|
-
void transcriptWriter.close(rt.desc.id);
|
|
20705
|
-
tracedSessions.delete(rt.desc.id);
|
|
20706
|
-
rt.agentSession = void 0;
|
|
20707
|
-
}
|
|
20708
|
-
schedulePersist();
|
|
20709
|
-
const banner = providerLimitMessage ? `[provider-limit] ${providerLimitMessage}` : `[crashed] adapter process gone (pid ${pid}) \u2014 session crashed`;
|
|
20710
|
-
appendLine(rt, banner, "stderr");
|
|
20711
|
-
transcriptWriter.recordEvent(rt.desc.id, { kind: "notice", text: banner });
|
|
20712
|
-
emitExited(rt);
|
|
20713
|
-
return true;
|
|
21087
|
+
markCrashed(id, reason = "process-gone") {
|
|
21088
|
+
return markCrashedInternal(id, reason);
|
|
20714
21089
|
},
|
|
20715
21090
|
markStalled(id, stalledSinceMs) {
|
|
20716
21091
|
const rt = sessions.get(id);
|
|
@@ -20876,6 +21251,7 @@ ${message}`;
|
|
|
20876
21251
|
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
20877
21252
|
});
|
|
20878
21253
|
stampReadLiveness(rt.desc);
|
|
21254
|
+
writeIndexNow(rt);
|
|
20879
21255
|
return rt.desc;
|
|
20880
21256
|
},
|
|
20881
21257
|
setKeepAlive(id, keepAlive) {
|
|
@@ -20999,6 +21375,7 @@ ${message}`;
|
|
|
20999
21375
|
if (shutdownDone) return;
|
|
21000
21376
|
shutdownDone = true;
|
|
21001
21377
|
if (persistTimer) clearTimeout(persistTimer);
|
|
21378
|
+
flushDirtyIndexes();
|
|
21002
21379
|
if (persist) {
|
|
21003
21380
|
try {
|
|
21004
21381
|
process.off("exit", onProcessExit);
|
|
@@ -21151,6 +21528,13 @@ function loadHistorySnapshot(persistPath, sessions, sessionEvents, transcriptBas
|
|
|
21151
21528
|
}
|
|
21152
21529
|
}
|
|
21153
21530
|
}
|
|
21531
|
+
function promptTextForIndex(message, system) {
|
|
21532
|
+
const text13 = typeof message === "string" ? message : (Array.isArray(message) ? message : [message]).map(
|
|
21533
|
+
(b) => b && typeof b === "object" && typeof b.text === "string" ? b.text : ""
|
|
21534
|
+
).filter(Boolean).join("\n");
|
|
21535
|
+
if (system && text13.startsWith(system)) return text13.slice(system.length).replace(/^\n\n/, "");
|
|
21536
|
+
return text13;
|
|
21537
|
+
}
|
|
21154
21538
|
function quoteArg(arg) {
|
|
21155
21539
|
if (arg === "") return '""';
|
|
21156
21540
|
if (/^[a-zA-Z0-9._/=:@,+-]+$/.test(arg)) return arg;
|
|
@@ -21190,6 +21574,7 @@ var init_sessions = __esm({
|
|
|
21190
21574
|
init_session_continue_fresh();
|
|
21191
21575
|
init_session_outcome();
|
|
21192
21576
|
init_session_end_reason();
|
|
21577
|
+
init_session_index();
|
|
21193
21578
|
init_session_message();
|
|
21194
21579
|
SESSIONS_FILE_PATH = () => resolve(homedir(), ".agentproto", "sessions.json");
|
|
21195
21580
|
SESSION_ID_ENV = "AGENTPROTO_SESSION_ID";
|
|
@@ -22937,7 +23322,7 @@ init_resume_strategies();
|
|
|
22937
23322
|
init_spawn_defaults();
|
|
22938
23323
|
init_launch_config();
|
|
22939
23324
|
init_resume_context_digest();
|
|
22940
|
-
|
|
23325
|
+
init_eligibility_manifest();
|
|
22941
23326
|
init_providers_store();
|
|
22942
23327
|
init_catalog_models();
|
|
22943
23328
|
init_config();
|
|
@@ -23435,7 +23820,7 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
23435
23820
|
desc = await spawnWithResume(strategy.resumeSessionId);
|
|
23436
23821
|
} catch (err) {
|
|
23437
23822
|
const msg = err instanceof Error ? err.message : String(err);
|
|
23438
|
-
if (strategy.resumeSessionId && RESUME_ID_REJECTED_RE.test(msg)) {
|
|
23823
|
+
if (strategy.resumeSessionId && (RESUME_ID_REJECTED_RE.test(msg) || RESUME_CONNECTION_LOST_RE.test(msg))) {
|
|
23439
23824
|
desc = await spawnWithResume(void 0);
|
|
23440
23825
|
resumeFallback = true;
|
|
23441
23826
|
} else {
|
|
@@ -23726,7 +24111,7 @@ var EMPTY_SKILLS = {
|
|
|
23726
24111
|
byHarness: [],
|
|
23727
24112
|
defaults: { global: [], byAdapter: {} }
|
|
23728
24113
|
};
|
|
23729
|
-
function
|
|
24114
|
+
function isRecord6(value) {
|
|
23730
24115
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23731
24116
|
}
|
|
23732
24117
|
function classifyDaemonMount(adapter) {
|
|
@@ -23879,15 +24264,15 @@ var slugToCamel2 = (slug) => slug.replace(/-([a-z0-9])/g, (_m, c) => c.toUpperCa
|
|
|
23879
24264
|
async function readAdapterManifest(adapter) {
|
|
23880
24265
|
try {
|
|
23881
24266
|
const mod = await import(adapter.packageName);
|
|
23882
|
-
if (!
|
|
24267
|
+
if (!isRecord6(mod)) return void 0;
|
|
23883
24268
|
const candidate = mod[slugToCamel2(adapter.slug)] ?? mod.default ?? mod.handle;
|
|
23884
|
-
return
|
|
24269
|
+
return isRecord6(candidate) ? candidate : void 0;
|
|
23885
24270
|
} catch {
|
|
23886
24271
|
return void 0;
|
|
23887
24272
|
}
|
|
23888
24273
|
}
|
|
23889
24274
|
function asSkillsTarget(value) {
|
|
23890
|
-
if (!
|
|
24275
|
+
if (!isRecord6(value) || typeof value.format !== "string") return void 0;
|
|
23891
24276
|
const out = { format: value.format };
|
|
23892
24277
|
if (typeof value.dir === "string") out.dir = value.dir;
|
|
23893
24278
|
if (typeof value.outDir === "string") out.outDir = value.outDir;
|
|
@@ -23904,10 +24289,10 @@ async function listNativeSkills(adapter) {
|
|
|
23904
24289
|
}
|
|
23905
24290
|
async function buildHarnessEntry(adapter) {
|
|
23906
24291
|
const manifest = await readAdapterManifest(adapter);
|
|
23907
|
-
const metadata = manifest &&
|
|
24292
|
+
const metadata = manifest && isRecord6(manifest.metadata) ? manifest.metadata : void 0;
|
|
23908
24293
|
const target = asSkillsTarget(metadata?.skills);
|
|
23909
24294
|
const options = manifest && Array.isArray(manifest.options) ? manifest.options : [];
|
|
23910
|
-
const spawnOption = options.some((o) =>
|
|
24295
|
+
const spawnOption = options.some((o) => isRecord6(o) && o.id === "skills");
|
|
23911
24296
|
const [installed, native] = await Promise.all([
|
|
23912
24297
|
target ? listInstalledForTarget(target) : Promise.resolve([]),
|
|
23913
24298
|
listNativeSkills(adapter)
|
|
@@ -24293,6 +24678,8 @@ async function processTreeRss(rootPids, exec = defaultPsExecutor) {
|
|
|
24293
24678
|
}
|
|
24294
24679
|
|
|
24295
24680
|
// src/session-tools.ts
|
|
24681
|
+
init_transcript_writer();
|
|
24682
|
+
init_session_index();
|
|
24296
24683
|
init_process_stats();
|
|
24297
24684
|
|
|
24298
24685
|
// src/host-load.ts
|
|
@@ -26086,6 +26473,7 @@ var publicSessionDescriptor = (session) => {
|
|
|
26086
26473
|
var compactSessionItem = (s) => ({
|
|
26087
26474
|
id: s.id,
|
|
26088
26475
|
kind: s.kind,
|
|
26476
|
+
...s.origin ? { origin: s.origin } : {},
|
|
26089
26477
|
name: s.name,
|
|
26090
26478
|
label: s.label,
|
|
26091
26479
|
status: s.status,
|
|
@@ -26374,6 +26762,66 @@ function registerSessionTools(rawServer, opts) {
|
|
|
26374
26762
|
})
|
|
26375
26763
|
]
|
|
26376
26764
|
});
|
|
26765
|
+
const sessionSearchSchema = z.object({
|
|
26766
|
+
query: z.string().describe(
|
|
26767
|
+
"Case-insensitive substring to match: a session id PREFIX, or a substring of label, title, cwd, or workspace slug. Empty matches all."
|
|
26768
|
+
),
|
|
26769
|
+
status: z.enum(["starting", "running", "exited", "killed", "error"]).optional().describe("Filter by exact status."),
|
|
26770
|
+
...pageParamsShape
|
|
26771
|
+
});
|
|
26772
|
+
registerBuiltinTool(server, {
|
|
26773
|
+
id: "session_search",
|
|
26774
|
+
description: "Find sessions by a case-insensitive query across id prefix, label, title, cwd and workspace slug \u2014 the daemon-side twin of `agentproto sessions find <query>`. Optional `status` filters to an exact lifecycle status; `limit` (default 20) caps the result. Each hit uses the same compact shape as `session_list`. Read-only; use `session_recap` on a hit to see where that session stopped.",
|
|
26775
|
+
inputSchema: sessionSearchSchema,
|
|
26776
|
+
handler: async (input) => {
|
|
26777
|
+
let rows = registry.list({ includeArchived: true });
|
|
26778
|
+
if (callerScope) {
|
|
26779
|
+
const subtree = collectSubtree(callerScope.ownerSessionId, rows);
|
|
26780
|
+
rows = rows.filter((s) => subtree.has(s.id));
|
|
26781
|
+
}
|
|
26782
|
+
rows = rows.filter((s) => matchesSessionQuery(s, input.query));
|
|
26783
|
+
if (input.status) rows = rows.filter((s) => s.status === input.status);
|
|
26784
|
+
const limit = Math.max(1, Math.min(200, input.limit ?? INDEX_DEFAULT_LIMIT));
|
|
26785
|
+
rows = rows.sort((a, b) => (b.lastActivityAt ?? b.startedAt).localeCompare(a.lastActivityAt ?? a.startedAt)).slice(0, limit);
|
|
26786
|
+
return rows.map(publicSessionDescriptor);
|
|
26787
|
+
},
|
|
26788
|
+
transformers: [
|
|
26789
|
+
paginated({
|
|
26790
|
+
project: compactSessionItem,
|
|
26791
|
+
keyOf: (s) => s.id,
|
|
26792
|
+
maxLimit: 200,
|
|
26793
|
+
itemKey: "sessions"
|
|
26794
|
+
})
|
|
26795
|
+
]
|
|
26796
|
+
});
|
|
26797
|
+
registerBuiltinTool(server, {
|
|
26798
|
+
id: "session_recap",
|
|
26799
|
+
description: 'One-glance "where did we stop" for a session: the last K user prompts with timestamps, the final assistant text of the last turn, and meta (status/alive, model, adapter, cwd, parent, child ids, cost, queued prompts). Reads the session\'s index sidecar plus a bounded tail of its transcript \u2014 never the whole file. Use it to resume an interrupted session by id (find the id with `session_search`).',
|
|
26800
|
+
inputSchema: z.object({
|
|
26801
|
+
id: z.string().min(1).describe("Session id or name \u2014 from `session_list`/`session_search`."),
|
|
26802
|
+
last: z.number().int().min(1).max(50).optional().describe("How many recent user prompts to include (default 8).")
|
|
26803
|
+
}),
|
|
26804
|
+
handler: async (input) => {
|
|
26805
|
+
const resolved = registry.findByIdOrName(input.id);
|
|
26806
|
+
if (!resolved) throw new Error(`session_recap: no session "${input.id}"`);
|
|
26807
|
+
const desc = registry.get(resolved.id) ?? resolved;
|
|
26808
|
+
const baseDir = registry.transcriptBaseDir;
|
|
26809
|
+
const index = readSessionIndex(desc.id, baseDir);
|
|
26810
|
+
const entry = indexEntryFromDescriptor(desc, {
|
|
26811
|
+
...index?.lastUserPrompt ? { lastUserPrompt: index.lastUserPrompt } : {},
|
|
26812
|
+
...index?.lastOutputText ? { lastOutputText: index.lastOutputText } : {}
|
|
26813
|
+
});
|
|
26814
|
+
const children = registry.list({ includeArchived: true }).filter((s) => s.parentSessionId === desc.id).map((s) => s.id);
|
|
26815
|
+
return buildSessionRecap({
|
|
26816
|
+
entry,
|
|
26817
|
+
eventsPath: sessionEventsPath(desc.id, baseDir),
|
|
26818
|
+
last: input.last ?? 8,
|
|
26819
|
+
children,
|
|
26820
|
+
...desc.queuedPrompts !== void 0 ? { queuedPrompts: desc.queuedPrompts } : {}
|
|
26821
|
+
});
|
|
26822
|
+
},
|
|
26823
|
+
transformers: [catchErrors()]
|
|
26824
|
+
});
|
|
26377
26825
|
registerBuiltinTool(server, {
|
|
26378
26826
|
id: "session_stats",
|
|
26379
26827
|
description: 'Resource usage per session, sampled from the OS process table: RSS bytes, %CPU, process count and top commands by RSS for every live session, sorted by RSS (each row labelled with the session\'s `label`/`name`), plus `daemon` (the daemon process + its own children), `provisioning` (worktree setup work such as `pnpm install` not yet attached to a session, with `inFlight` provisions), `orphans` (processes that look agentproto-owned but belong to no live session - reported only, never killed), `totals`, and `host` (load average, free/total memory). `detail:"full"` adds every process (pid, command, RSS, CPU, elapsed) per row. Cached ~3s; `fresh:true` forces a new sample. A subtree-scoped caller sees only its own sessions (no daemon/provisioning/orphan buckets).',
|
|
@@ -28621,8 +29069,8 @@ function registerSessionTools(rawServer, opts) {
|
|
|
28621
29069
|
'Record a verdict on specific sessions \u2014 the mutating half of `session_wrapup_plan`. Each id is RE-CLASSIFIED from scratch immediately before acting (a plan computed moments earlier can be stale) and is only acted on if it is STILL `close` or `stuck`. Pass `judgedBy` (a judge session id) to also accept a `judge`-class id \u2014 the judge\'s verdict is what makes it safe to act on. `keep`-class ids are ALWAYS refused, no exception. `verdict: "done"` or `"abandoned"` actually CLOSES the session (tagged `endedReason:\'steward-completed\'`/`\'steward-abandoned\'`) and leaves it resumable (same as the idle reaper) \u2014 this never deletes anything. `verdict: "blocked"` or `"needs-input"` is NOT a completion: the session is left running untouched and the verdict is recorded as a flag (`SessionDescriptor.wrapupFlag`) instead \u2014 the per-id result\'s `action` says `closed` vs `flagged`. Also refused (result `ok:false`, `error:\'refused_stale_or_busy\'`) if the session is busy/awaitingInput/awaitingPermission or has a background task outstanding at the moment of the call, for either kind of action. A scoped orchestrator may only act on its own subtree. Returns a per-id result. Only the requested sessions are re-checked (never a full plan). If it outlasts 25 s (`waitMs`) it returns `{ jobId, status: "running", followUp }` \u2014 poll `session_wrapup_status`; the apply keeps running regardless.',
|
|
28622
29070
|
{
|
|
28623
29071
|
sessionIds: z.array(z.string().min(1)).min(1).describe("Session ids or names, from `session_wrapup_plan`."),
|
|
28624
|
-
verdict: z.enum(["done", "abandoned", "blocked", "needs-input"]).describe(
|
|
28625
|
-
'What the session\'s work amounted to. "done"/"abandoned" CLOSE the session (`endedReason:\'steward-completed\'`/`\'steward-abandoned\'`); "blocked"/"needs-input" only FLAG it (`SessionDescriptor.wrapupFlag`) \u2014 the session keeps running.'
|
|
29072
|
+
verdict: z.enum(["done", "abandoned", "partial", "failed", "blocked", "needs-input"]).describe(
|
|
29073
|
+
'What the session\'s work amounted to. "done"/"abandoned"/"partial"/"failed" CLOSE the session (`endedReason:\'steward-completed\'`/`\'steward-abandoned\'` \u2014 done only), the verdict nuance kept on the outcome; "blocked"/"needs-input" only FLAG it (`SessionDescriptor.wrapupFlag`) \u2014 the session keeps running.'
|
|
28626
29074
|
),
|
|
28627
29075
|
note: z.string().optional().describe("Free-text note recorded on the outcome or the flag."),
|
|
28628
29076
|
judgedBy: z.string().optional().describe(
|
|
@@ -28697,6 +29145,70 @@ function registerSessionTools(rawServer, opts) {
|
|
|
28697
29145
|
}
|
|
28698
29146
|
}
|
|
28699
29147
|
);
|
|
29148
|
+
server.tool(
|
|
29149
|
+
"session_mark_completed",
|
|
29150
|
+
"Mark a live session as completed \u2014 closes it with verdict:'done' and tags it as steward-completed. Use when a human (or an agent's judge) decides the session's work is done \u2014 the declared path: no wrapup plan, no classification. One call fuses what would otherwise be `session_wrapup_apply` without a plan: the verdict (with an optional summary + who judged it) is written onto the session's Level-2 `SessionOutcome` and the session is closed gracefully the same way wrapup-apply does, left lazy-resumable (never deleted). `verdict:'partial'`/'failed'/'abandoned' close as not-completed (`endedReason:'steward-abandoned'`); `'blocked'`/'needs-input' are NOT completions \u2014 the session stays running and the verdict is recorded as a flag instead. Refused (result ok:false) when the session is missing, not agent-cli, already terminal, mid-turn/awaiting input/permission, or has a background task in flight.",
|
|
29151
|
+
{
|
|
29152
|
+
sessionId: z.string().min(1).describe("Session id or name \u2014 from `session_list`, must be a live agent-cli session."),
|
|
29153
|
+
verdict: z.enum(["done", "abandoned", "partial", "failed", "blocked", "needs-input"]).optional().describe(
|
|
29154
|
+
"Default 'done'. 'done' closes as completed (`endedReason:'steward-completed'`); 'partial'/'failed'/'abandoned' close as not-completed (steward-abandoned) with the verdict nuance kept on the outcome; 'blocked'/'needs-input' flag instead \u2014 the session keeps running."
|
|
29155
|
+
),
|
|
29156
|
+
summary: z.string().optional().describe("Overrides the outcome's derived summary (trimmed to the same cap as the derived one)."),
|
|
29157
|
+
note: z.string().optional().describe("Free-text note explaining the verdict."),
|
|
29158
|
+
judgedBy: z.string().optional().describe(
|
|
29159
|
+
"A judge session id \u2014 sets the outcome's source to 'judged'. Omitted \u21D2 'declared', judgedBy:'steward-rules'."
|
|
29160
|
+
)
|
|
29161
|
+
},
|
|
29162
|
+
async (input) => {
|
|
29163
|
+
const desc = registry.findByIdOrName(input.sessionId);
|
|
29164
|
+
if (!desc) {
|
|
29165
|
+
return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: "not_found", sessionId: input.sessionId }) }] };
|
|
29166
|
+
}
|
|
29167
|
+
if (callerScope) {
|
|
29168
|
+
const subtree = collectSubtree(callerScope.ownerSessionId, registry.list({ includeArchived: true }));
|
|
29169
|
+
if (!subtree.has(desc.id)) {
|
|
29170
|
+
return {
|
|
29171
|
+
content: [
|
|
29172
|
+
{
|
|
29173
|
+
type: "text",
|
|
29174
|
+
text: JSON.stringify({
|
|
29175
|
+
ok: false,
|
|
29176
|
+
error: "orchestrator_session_out_of_scope",
|
|
29177
|
+
message: `session_mark_completed: session "${desc.id}" is not in your subtree \u2014 a scoped orchestrator can only mark sessions it (transitively) spawned.`,
|
|
29178
|
+
sessionId: desc.id
|
|
29179
|
+
})
|
|
29180
|
+
}
|
|
29181
|
+
],
|
|
29182
|
+
isError: true
|
|
29183
|
+
};
|
|
29184
|
+
}
|
|
29185
|
+
}
|
|
29186
|
+
const verdict = input.verdict ?? "done";
|
|
29187
|
+
const status = registry.get(desc.id)?.status ?? desc.status;
|
|
29188
|
+
if (status !== "running" && status !== "starting") {
|
|
29189
|
+
return {
|
|
29190
|
+
content: [{ type: "text", text: JSON.stringify({ ok: false, error: "not_live", status, sessionId: desc.id }) }],
|
|
29191
|
+
isError: true
|
|
29192
|
+
};
|
|
29193
|
+
}
|
|
29194
|
+
const source = input.judgedBy ? "judged" : "declared";
|
|
29195
|
+
const applied = registry.closeWithOutcome(desc.id, {
|
|
29196
|
+
verdict,
|
|
29197
|
+
...input.summary !== void 0 ? { summary: input.summary } : {},
|
|
29198
|
+
...input.note !== void 0 ? { note: input.note } : {},
|
|
29199
|
+
judgedBy: input.judgedBy ?? "steward-rules",
|
|
29200
|
+
source
|
|
29201
|
+
});
|
|
29202
|
+
const out = {
|
|
29203
|
+
ok: applied,
|
|
29204
|
+
sessionId: desc.id,
|
|
29205
|
+
verdict,
|
|
29206
|
+
action: verdict === "blocked" || verdict === "needs-input" ? "flagged" : "closed",
|
|
29207
|
+
...!applied ? { error: "refused_stale_or_busy" } : {}
|
|
29208
|
+
};
|
|
29209
|
+
return { content: [{ type: "text", text: JSON.stringify(applied ? { ...out, endedReason: registry.get(desc.id)?.endedReason } : out) }] };
|
|
29210
|
+
}
|
|
29211
|
+
);
|
|
28700
29212
|
server.tool(
|
|
28701
29213
|
"session_evidence",
|
|
28702
29214
|
"READ-ONLY \u2014 a compact evidence object for ONE session, as fed to the session-steward judge: label, cwd, adapter, status, keepAlive, awaitingInput, busy, idle minutes, the last ~10 user/assistant turns (trimmed to ~3 KB total, newest kept first), and \u2014 for a session in a linked worktree \u2014 branch, dirty counts, ahead/behind and PR state/number. Mutates nothing.",
|
|
@@ -34924,11 +35436,11 @@ function verifySignatureV2(secret, headers, body, nowMs, skewMs = SIGNATURE_V2_S
|
|
|
34924
35436
|
if (a.length !== b.length || !timingSafeEqual(a, b)) return { ok: false, reason: "signature_mismatch" };
|
|
34925
35437
|
return { ok: true, timestampSec };
|
|
34926
35438
|
}
|
|
34927
|
-
var
|
|
35439
|
+
var isRecord7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
34928
35440
|
function toSentinelEvent(raw, seq) {
|
|
34929
|
-
if (!
|
|
35441
|
+
if (!isRecord7(raw)) return null;
|
|
34930
35442
|
const { id, source, type, subject, time, data, summary, subjects, terminal, consumerref } = raw;
|
|
34931
|
-
if (raw.specversion !== "1.0" || typeof id !== "string" || id === "" || typeof source !== "string" || typeof type !== "string" || type === "" || typeof subject !== "string" || subject === "" || typeof time !== "string" || !
|
|
35443
|
+
if (raw.specversion !== "1.0" || typeof id !== "string" || id === "" || typeof source !== "string" || typeof type !== "string" || type === "" || typeof subject !== "string" || subject === "" || typeof time !== "string" || !isRecord7(data) || typeof summary !== "string" || !Array.isArray(subjects) || !subjects.every((s) => typeof s === "string") || typeof terminal !== "boolean") {
|
|
34932
35444
|
return null;
|
|
34933
35445
|
}
|
|
34934
35446
|
const envSeq = typeof raw.seq === "number" ? raw.seq : seq;
|
|
@@ -35034,7 +35546,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35034
35546
|
json3 = void 0;
|
|
35035
35547
|
}
|
|
35036
35548
|
if (!res.ok) {
|
|
35037
|
-
const detail =
|
|
35549
|
+
const detail = isRecord7(json3) && typeof json3.error === "string" ? json3.error : text13.slice(0, 200);
|
|
35038
35550
|
throw new AgentpushHttpError(res.status, `agentpush ${method} ${path} \u2192 HTTP ${res.status}${detail ? `: ${detail}` : ""}`);
|
|
35039
35551
|
}
|
|
35040
35552
|
return json3;
|
|
@@ -35120,7 +35632,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35120
35632
|
...push ? { callback_url: callbackUrl2(delivery.callbackUrl, hookKey), callback_secret: callbackSecret } : {}
|
|
35121
35633
|
}
|
|
35122
35634
|
});
|
|
35123
|
-
const id =
|
|
35635
|
+
const id = isRecord7(json3) && isRecord7(json3.subscription) ? json3.subscription.id : void 0;
|
|
35124
35636
|
if (typeof id !== "string" || id === "") throw new Error("agentpush: create returned no subscription id");
|
|
35125
35637
|
return {
|
|
35126
35638
|
provider: AGENTPUSH_SLUG,
|
|
@@ -35147,7 +35659,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35147
35659
|
let sub;
|
|
35148
35660
|
try {
|
|
35149
35661
|
const json3 = await api("GET", subPath(handle));
|
|
35150
|
-
sub =
|
|
35662
|
+
sub = isRecord7(json3) && isRecord7(json3.subscription) ? json3.subscription : void 0;
|
|
35151
35663
|
} catch (err) {
|
|
35152
35664
|
if (isHttp(err, 404)) {
|
|
35153
35665
|
throw new Error(`agentpush subscription ${handle.remoteId} no longer exists \u2014 re-create the sentinel`);
|
|
@@ -35178,7 +35690,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35178
35690
|
async status(handle) {
|
|
35179
35691
|
try {
|
|
35180
35692
|
const json3 = await api("GET", subPath(handle));
|
|
35181
|
-
const sub =
|
|
35693
|
+
const sub = isRecord7(json3) && isRecord7(json3.subscription) ? json3.subscription : void 0;
|
|
35182
35694
|
const status = sub && typeof sub.status === "string" ? sub.status : "unknown";
|
|
35183
35695
|
if (status === "active") return { ok: true };
|
|
35184
35696
|
return { ok: false, detail: `the agentpush subscription is ${status}` };
|
|
@@ -35190,12 +35702,12 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35190
35702
|
const after = handle.cursor ?? "0";
|
|
35191
35703
|
if (stateOf(handle).mode === "push") return { events: [], cursor: after };
|
|
35192
35704
|
const json3 = await api("GET", `${subPath(handle)}/events`, { query: { after, limit: Math.max(1, Math.min(limit, 1e3)) } });
|
|
35193
|
-
const items =
|
|
35705
|
+
const items = isRecord7(json3) && Array.isArray(json3.items) ? json3.items : [];
|
|
35194
35706
|
const events = [];
|
|
35195
35707
|
let cursor = Number(after);
|
|
35196
35708
|
if (!Number.isFinite(cursor)) cursor = 0;
|
|
35197
35709
|
for (const item of items) {
|
|
35198
|
-
if (!
|
|
35710
|
+
if (!isRecord7(item)) continue;
|
|
35199
35711
|
const seq = typeof item.seq === "number" ? item.seq : void 0;
|
|
35200
35712
|
if (seq !== void 0 && seq > cursor) cursor = seq;
|
|
35201
35713
|
const event = toSentinelEvent(item.envelope, seq);
|
|
@@ -37571,11 +38083,11 @@ function sanitize(cacheKey) {
|
|
|
37571
38083
|
const cleaned = cacheKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
37572
38084
|
return cleaned.length > 0 ? cleaned : "default";
|
|
37573
38085
|
}
|
|
37574
|
-
function
|
|
38086
|
+
function isRecord8(v) {
|
|
37575
38087
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
37576
38088
|
}
|
|
37577
38089
|
function isEntry2(v) {
|
|
37578
|
-
return
|
|
38090
|
+
return isRecord8(v) && typeof v.resolvedInputHash === "string" && "output" in v;
|
|
37579
38091
|
}
|
|
37580
38092
|
function createFileStepCache(cacheKey, opts) {
|
|
37581
38093
|
const dir = opts?.dir ?? DEFAULT_CACHE_DIR();
|
|
@@ -37588,7 +38100,7 @@ function createFileStepCache(cacheKey, opts) {
|
|
|
37588
38100
|
} catch {
|
|
37589
38101
|
return {};
|
|
37590
38102
|
}
|
|
37591
|
-
if (!
|
|
38103
|
+
if (!isRecord8(parsed)) return {};
|
|
37592
38104
|
const out = {};
|
|
37593
38105
|
for (const [k, v] of Object.entries(parsed)) if (isEntry2(v)) out[k] = v;
|
|
37594
38106
|
return out;
|
|
@@ -44722,12 +45234,12 @@ async function readBody2(req) {
|
|
|
44722
45234
|
}
|
|
44723
45235
|
return { raw: Buffer.concat(chunks).toString("utf8") };
|
|
44724
45236
|
}
|
|
44725
|
-
var
|
|
45237
|
+
var isRecord9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
44726
45238
|
function parseParts(raw) {
|
|
44727
45239
|
if (!Array.isArray(raw)) throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "message.parts must be an array");
|
|
44728
45240
|
const parts = [];
|
|
44729
45241
|
for (const p of raw) {
|
|
44730
|
-
if (!
|
|
45242
|
+
if (!isRecord9(p)) throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "each message part must be an object");
|
|
44731
45243
|
if ("text" in p) {
|
|
44732
45244
|
if (typeof p.text !== "string") throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "part.text must be a string");
|
|
44733
45245
|
parts.push({ text: p.text });
|
|
@@ -44760,13 +45272,13 @@ async function handleA2aTaskRequest(req, res, path, deps2) {
|
|
|
44760
45272
|
send(res, 200, { jsonrpc: "2.0", id: null, error: { code: JSON_RPC_ERROR.parse, message: "parse error: body is not valid JSON" } });
|
|
44761
45273
|
return true;
|
|
44762
45274
|
}
|
|
44763
|
-
if (!
|
|
45275
|
+
if (!isRecord9(rpc) || rpc.jsonrpc !== "2.0" || typeof rpc.method !== "string") {
|
|
44764
45276
|
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)' } });
|
|
44765
45277
|
return true;
|
|
44766
45278
|
}
|
|
44767
45279
|
const id = typeof rpc.id === "string" || typeof rpc.id === "number" ? rpc.id : null;
|
|
44768
45280
|
const method = rpc.method;
|
|
44769
|
-
const params =
|
|
45281
|
+
const params = isRecord9(rpc.params) ? rpc.params : {};
|
|
44770
45282
|
const requested = negotiateVersion(
|
|
44771
45283
|
typeof req.headers["a2a-version"] === "string" ? req.headers["a2a-version"] : void 0,
|
|
44772
45284
|
new URL(req.url ?? "/", "http://localhost").searchParams.get("version")
|
|
@@ -44824,14 +45336,14 @@ async function handleA2aTaskRequest(req, res, path, deps2) {
|
|
|
44824
45336
|
throw new RpcFailure(JSON_RPC_ERROR.unsupportedOperation, `method "SendMessage" is not allowed for app "${appId}": its manifest does not declare accepts.tasks: true`);
|
|
44825
45337
|
}
|
|
44826
45338
|
const rawMessage = params.message;
|
|
44827
|
-
if (!
|
|
45339
|
+
if (!isRecord9(rawMessage) || rawMessage.role !== "ROLE_USER") {
|
|
44828
45340
|
throw new RpcFailure(JSON_RPC_ERROR.invalidParams, 'params.message must be an object with role "ROLE_USER"');
|
|
44829
45341
|
}
|
|
44830
45342
|
const parts = parseParts(rawMessage.parts);
|
|
44831
45343
|
const { skill, prompt } = extractSkillRequest(
|
|
44832
|
-
{ parts, ...
|
|
45344
|
+
{ parts, ...isRecord9(rawMessage.metadata) ? { metadata: rawMessage.metadata } : {} },
|
|
44833
45345
|
appId,
|
|
44834
|
-
|
|
45346
|
+
isRecord9(params.metadata) ? params.metadata : void 0
|
|
44835
45347
|
);
|
|
44836
45348
|
if (!skill) {
|
|
44837
45349
|
throw new RpcFailure(JSON_RPC_ERROR.invalidParams, 'no skill requested: set message.metadata.skill or start the first text part with "skill:<id>"');
|
|
@@ -52347,9 +52859,13 @@ function isCrashed(desc) {
|
|
|
52347
52859
|
if (desc.kind !== "agent-cli") return false;
|
|
52348
52860
|
if (desc.status !== "running") return false;
|
|
52349
52861
|
if (desc.remote === true) return false;
|
|
52862
|
+
if (desc.adapterConnected === false) return true;
|
|
52350
52863
|
if (desc.pid === null || desc.pid === void 0) return false;
|
|
52351
52864
|
return desc.processAlive === false;
|
|
52352
52865
|
}
|
|
52866
|
+
function crashReasonFor(desc) {
|
|
52867
|
+
return desc.adapterConnected === false ? "transport-closed" : "process-gone";
|
|
52868
|
+
}
|
|
52353
52869
|
function runCrashDetectPass(opts) {
|
|
52354
52870
|
const { registry, isServed } = opts;
|
|
52355
52871
|
const intervalMs = opts.crashDetectIntervalMs;
|
|
@@ -52365,7 +52881,7 @@ function runCrashDetectPass(opts) {
|
|
|
52365
52881
|
ids: []
|
|
52366
52882
|
};
|
|
52367
52883
|
for (const d of candidates) {
|
|
52368
|
-
if (registry.markCrashed(d.id)) {
|
|
52884
|
+
if (registry.markCrashed(d.id, crashReasonFor(d))) {
|
|
52369
52885
|
summary.crashed++;
|
|
52370
52886
|
summary.ids.push(d.id);
|
|
52371
52887
|
}
|
|
@@ -52535,6 +53051,7 @@ async function resolveMessagingDefaults(loadCfg = loadConfig) {
|
|
|
52535
53051
|
|
|
52536
53052
|
// src/index.ts
|
|
52537
53053
|
init_transcript_writer();
|
|
53054
|
+
init_session_index();
|
|
52538
53055
|
var BINDINGS_FILE_PATH = () => resolve(homedir(), ".agentproto", "transmitter-bindings.json");
|
|
52539
53056
|
var PERSIST_DEBOUNCE_MS5 = 1500;
|
|
52540
53057
|
var keyOf = (alias, source, contactRef) => `${alias}:${source}:${contactRef}`;
|
|
@@ -52948,12 +53465,13 @@ async function ssrfFetch(url, init, io = {}) {
|
|
|
52948
53465
|
if ((init.body?.byteLength ?? 0) > MAX_REQUEST_BODY_BYTES) {
|
|
52949
53466
|
throw new SsrfFetchError("connect", `request body exceeds the ${MAX_REQUEST_BODY_BYTES}-byte clamp`);
|
|
52950
53467
|
}
|
|
53468
|
+
const port = parsed.port ? Number(parsed.port) : 443;
|
|
52951
53469
|
if (testDispatcher) {
|
|
52952
53470
|
const literal = parseIpv4(parsed.hostname);
|
|
52953
53471
|
if (literal && !ipv4Public(literal[0], literal[1], literal[2], literal[3])) {
|
|
52954
53472
|
throw new SsrfFetchError("private_target", `literal non-public address ${parsed.hostname}`);
|
|
52955
53473
|
}
|
|
52956
|
-
return await testDispatcher({ url, headers: init.headers ?? {}, body: init.body, timeoutMs: init.timeoutMs });
|
|
53474
|
+
return await testDispatcher({ url, headers: finalHeaders(init.headers ?? {}, parsed.hostname, port), body: init.body, timeoutMs: init.timeoutMs });
|
|
52957
53475
|
}
|
|
52958
53476
|
const candidates = await resolveHost(parsed.hostname, io.resolvers ?? {});
|
|
52959
53477
|
if (candidates.length === 0) {
|
|
@@ -52965,17 +53483,26 @@ async function ssrfFetch(url, init, io = {}) {
|
|
|
52965
53483
|
}
|
|
52966
53484
|
const connectIp = candidates[0] ?? candidates[candidates.length - 1];
|
|
52967
53485
|
if (connectIp === void 0) throw new SsrfFetchError("connect", "no address available for connect");
|
|
52968
|
-
const port = parsed.port ? Number(parsed.port) : 443;
|
|
52969
53486
|
return await rawPost({
|
|
52970
53487
|
connectIp,
|
|
52971
53488
|
servername: parsed.hostname,
|
|
52972
53489
|
port,
|
|
52973
53490
|
path: `${parsed.pathname}${parsed.search}`,
|
|
52974
|
-
|
|
53491
|
+
// HTTP Host header must stay the ORIGINAL hostname — `request({host})`
|
|
53492
|
+
// below only picks the TCP destination; a literal-IP Host is answered
|
|
53493
|
+
// 403/421 by name-based vhosts (tested live against cloudflared+CF edge),
|
|
53494
|
+
// which would falsely categorise every virtual-hosted subscriber as
|
|
53495
|
+
// non_2xx. An explicit caller Host header wins (finalHeaders keeps it).
|
|
53496
|
+
headers: finalHeaders(init.headers ?? {}, parsed.hostname, port),
|
|
52975
53497
|
body: init.body,
|
|
52976
53498
|
timeoutMs: init.timeoutMs
|
|
52977
53499
|
});
|
|
52978
53500
|
}
|
|
53501
|
+
function finalHeaders(headers, hostname6, port) {
|
|
53502
|
+
const hasHost = "Host" in headers || "host" in headers;
|
|
53503
|
+
if (hasHost) return headers;
|
|
53504
|
+
return { ...headers, Host: port === 443 ? hostname6 : `${hostname6}:${port}` };
|
|
53505
|
+
}
|
|
52979
53506
|
function rawPost(args) {
|
|
52980
53507
|
return new Promise((resolve42, reject) => {
|
|
52981
53508
|
const req = request({
|
|
@@ -52986,6 +53513,8 @@ function rawPost(args) {
|
|
|
52986
53513
|
path: args.path,
|
|
52987
53514
|
method: "POST",
|
|
52988
53515
|
servername: args.servername,
|
|
53516
|
+
// Host already defaulted to the ORIGINAL hostname by finalHeaders —
|
|
53517
|
+
// the socket only carries `args.connectIp` as its TCP destination.
|
|
52989
53518
|
headers: args.headers,
|
|
52990
53519
|
rejectUnauthorized: true
|
|
52991
53520
|
});
|
|
@@ -53103,6 +53632,562 @@ async function deliverEventEnvelope(replay, event, deps2 = {}) {
|
|
|
53103
53632
|
}
|
|
53104
53633
|
return { ok: false, reason: "retries_exhausted", delivery };
|
|
53105
53634
|
}
|
|
53635
|
+
function challengeReasonForSsrf(reason) {
|
|
53636
|
+
if (reason === "non_https") return "non_https";
|
|
53637
|
+
if (reason === "private_target" || reason === "redirect") return "ssrf_blocked";
|
|
53638
|
+
return "timeout";
|
|
53639
|
+
}
|
|
53640
|
+
var CHALLENGE_TTL_MS = 10 * 60 * 1e3;
|
|
53641
|
+
var encoder = new TextEncoder();
|
|
53642
|
+
var cache = /* @__PURE__ */ new Map();
|
|
53643
|
+
function challengeCacheSize() {
|
|
53644
|
+
return cache.size;
|
|
53645
|
+
}
|
|
53646
|
+
function resetChallengeCacheForTests() {
|
|
53647
|
+
cache.clear();
|
|
53648
|
+
}
|
|
53649
|
+
function normalizeCallbackUrl(url) {
|
|
53650
|
+
try {
|
|
53651
|
+
const u = new URL(url);
|
|
53652
|
+
const port = u.port === "443" ? "" : `:${u.port}`;
|
|
53653
|
+
return `${u.protocol.toLowerCase()}//${u.hostname.toLowerCase()}${port}${u.pathname}${u.search}`;
|
|
53654
|
+
} catch {
|
|
53655
|
+
return null;
|
|
53656
|
+
}
|
|
53657
|
+
}
|
|
53658
|
+
function hashSecret(secret) {
|
|
53659
|
+
return createHash("sha256").update(secret, "utf8").digest("hex");
|
|
53660
|
+
}
|
|
53661
|
+
function constantTimeEq(a, b) {
|
|
53662
|
+
const da = createHash("sha256").update(a, "utf8").digest();
|
|
53663
|
+
const db = createHash("sha256").update(b, "utf8").digest();
|
|
53664
|
+
return timingSafeEqual(da, db);
|
|
53665
|
+
}
|
|
53666
|
+
async function verifyCallback(input, deps2 = {}) {
|
|
53667
|
+
const now = deps2.now ?? (() => Date.now());
|
|
53668
|
+
const normalized = normalizeCallbackUrl(input.url);
|
|
53669
|
+
if (normalized === null || !normalized.startsWith("https://")) {
|
|
53670
|
+
return { ok: false, reason: "non_https", detail: "callback URL must be an https URL" };
|
|
53671
|
+
}
|
|
53672
|
+
if (decodeWhsecSecret(input.secret) === null) {
|
|
53673
|
+
return {
|
|
53674
|
+
ok: false,
|
|
53675
|
+
reason: "challenge_failed",
|
|
53676
|
+
detail: "invalid secret format \u2014 must be whsec_ + base64 decoding to 24..64 bytes (the caller validates before this; a bad secret is never cached)"
|
|
53677
|
+
};
|
|
53678
|
+
}
|
|
53679
|
+
const cacheKey = `${input.principal}|${normalized}|${hashSecret(input.secret)}`;
|
|
53680
|
+
const cached = cache.get(cacheKey);
|
|
53681
|
+
if (cached && cached.expiresAt > now()) {
|
|
53682
|
+
return { ok: true, verificationBytes: cached.requestBytes };
|
|
53683
|
+
}
|
|
53684
|
+
if (cached) cache.delete(cacheKey);
|
|
53685
|
+
const challenge = randomBytes(32).toString("hex");
|
|
53686
|
+
const requestBytes = encoder.encode(JSON.stringify({ type: "verification", challenge }));
|
|
53687
|
+
const msgId = `msg_verification_${randomBytes(12).toString("hex")}`;
|
|
53688
|
+
const timestamp = Math.floor(now() / 1e3);
|
|
53689
|
+
let headers;
|
|
53690
|
+
try {
|
|
53691
|
+
const signed = signWebhook({ msgId, timestamp, payload: requestBytes, secrets: [input.secret] });
|
|
53692
|
+
headers = {
|
|
53693
|
+
...signed,
|
|
53694
|
+
"content-type": "application/json",
|
|
53695
|
+
"X-MCP-Subscription-Id": input.subscriptionId
|
|
53696
|
+
};
|
|
53697
|
+
} catch (err) {
|
|
53698
|
+
return { ok: false, reason: "challenge_failed", detail: `signing failed: ${err.message}` };
|
|
53699
|
+
}
|
|
53700
|
+
let response;
|
|
53701
|
+
try {
|
|
53702
|
+
response = await (deps2.fetch ?? ssrfFetch)(input.url, {
|
|
53703
|
+
method: "POST",
|
|
53704
|
+
headers,
|
|
53705
|
+
body: requestBytes,
|
|
53706
|
+
timeoutMs: 1e4
|
|
53707
|
+
// default challenge timeout (delivery uses 15_000)
|
|
53708
|
+
});
|
|
53709
|
+
} catch (err) {
|
|
53710
|
+
if (err instanceof SsrfFetchError) {
|
|
53711
|
+
return { ok: false, reason: challengeReasonForSsrf(err.reason), detail: `${err.reason}: ${err.message}` };
|
|
53712
|
+
}
|
|
53713
|
+
return { ok: false, reason: "timeout", detail: err.message };
|
|
53714
|
+
}
|
|
53715
|
+
if (response.status < 200 || response.status > 299) {
|
|
53716
|
+
return { ok: false, reason: "non_2xx", detail: `callback responded with status ${response.status}` };
|
|
53717
|
+
}
|
|
53718
|
+
let parsedBody;
|
|
53719
|
+
try {
|
|
53720
|
+
parsedBody = JSON.parse(response.body);
|
|
53721
|
+
} catch {
|
|
53722
|
+
return { ok: false, reason: "challenge_failed", detail: "response body is not JSON" };
|
|
53723
|
+
}
|
|
53724
|
+
const echoed = parsedBody?.challenge;
|
|
53725
|
+
if (typeof echoed !== "string" || !constantTimeEq(echoed, challenge)) {
|
|
53726
|
+
return { ok: false, reason: "challenge_failed", detail: "response did not echo the fresh challenge" };
|
|
53727
|
+
}
|
|
53728
|
+
cache.set(cacheKey, { requestBytes, expiresAt: now() + CHALLENGE_TTL_MS });
|
|
53729
|
+
return { ok: true, verificationBytes: requestBytes };
|
|
53730
|
+
}
|
|
53731
|
+
function canonicalizeJcs(value) {
|
|
53732
|
+
if (value === null) return "null";
|
|
53733
|
+
switch (typeof value) {
|
|
53734
|
+
case "boolean":
|
|
53735
|
+
return value ? "true" : "false";
|
|
53736
|
+
case "number":
|
|
53737
|
+
if (!Number.isFinite(value)) throw new Error("JCS: non-finite number is not JSON");
|
|
53738
|
+
return JSON.stringify(value);
|
|
53739
|
+
case "string":
|
|
53740
|
+
return JSON.stringify(value);
|
|
53741
|
+
case "object":
|
|
53742
|
+
break;
|
|
53743
|
+
default:
|
|
53744
|
+
throw new Error(`JCS: unsupported value type "${typeof value}"`);
|
|
53745
|
+
}
|
|
53746
|
+
if (Array.isArray(value)) {
|
|
53747
|
+
return `[${value.map(canonicalizeJcs).join(",")}]`;
|
|
53748
|
+
}
|
|
53749
|
+
const obj = value;
|
|
53750
|
+
const keys = Object.keys(obj).sort();
|
|
53751
|
+
const members = keys.map((key) => `${JSON.stringify(key)}:${canonicalizeJcs(obj[key])}`);
|
|
53752
|
+
return `{${members.join(",")}}`;
|
|
53753
|
+
}
|
|
53754
|
+
function subscriptionId(identity) {
|
|
53755
|
+
const canonical3 = canonicalizeJcs({
|
|
53756
|
+
principal: identity.principal,
|
|
53757
|
+
callbackUrl: identity.callbackUrl,
|
|
53758
|
+
eventName: identity.eventName,
|
|
53759
|
+
args: identity.args
|
|
53760
|
+
});
|
|
53761
|
+
const digest = createHash("sha256").update(canonical3, "utf8").digest("hex");
|
|
53762
|
+
return `sub_${digest.slice(0, 32)}`;
|
|
53763
|
+
}
|
|
53764
|
+
|
|
53765
|
+
// src/mcp-events/events-registry.ts
|
|
53766
|
+
function daemonBearerPrincipal() {
|
|
53767
|
+
return "daemon-bearer";
|
|
53768
|
+
}
|
|
53769
|
+
function sessionPrincipal(sessionId) {
|
|
53770
|
+
return `session:${sessionId}`;
|
|
53771
|
+
}
|
|
53772
|
+
function typeMatches(type, value) {
|
|
53773
|
+
if (Array.isArray(type)) return type.some((t) => typeMatches(t, value));
|
|
53774
|
+
switch (type) {
|
|
53775
|
+
case "object":
|
|
53776
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
53777
|
+
case "array":
|
|
53778
|
+
return Array.isArray(value);
|
|
53779
|
+
case "string":
|
|
53780
|
+
return typeof value === "string";
|
|
53781
|
+
case "number":
|
|
53782
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
53783
|
+
case "integer":
|
|
53784
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
53785
|
+
case "boolean":
|
|
53786
|
+
return typeof value === "boolean";
|
|
53787
|
+
case "null":
|
|
53788
|
+
return value === null;
|
|
53789
|
+
default:
|
|
53790
|
+
return true;
|
|
53791
|
+
}
|
|
53792
|
+
}
|
|
53793
|
+
function deepEqual2(a, b) {
|
|
53794
|
+
if (a === b) return true;
|
|
53795
|
+
if (typeof a !== typeof b) return false;
|
|
53796
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
53797
|
+
return a.length === b.length && a.every((v, i) => deepEqual2(v, b[i]));
|
|
53798
|
+
}
|
|
53799
|
+
if (typeof a === "object" && a !== null && typeof b === "object" && b !== null) {
|
|
53800
|
+
const ao = a;
|
|
53801
|
+
const bo = b;
|
|
53802
|
+
const ak = Object.keys(ao);
|
|
53803
|
+
const bk = Object.keys(bo);
|
|
53804
|
+
return ak.length === bk.length && ak.every((k) => deepEqual2(ao[k], bo[k]));
|
|
53805
|
+
}
|
|
53806
|
+
return false;
|
|
53807
|
+
}
|
|
53808
|
+
function validateNode(schema, value, path) {
|
|
53809
|
+
const at = path || "$";
|
|
53810
|
+
if (schema.type !== void 0 && !typeMatches(schema.type, value)) {
|
|
53811
|
+
return { ok: false, reason: `${at}: expected ${String(schema.type)}` };
|
|
53812
|
+
}
|
|
53813
|
+
if (schema.const !== void 0 && !deepEqual2(schema.const, value)) {
|
|
53814
|
+
return { ok: false, reason: `${at}: must equal the const value` };
|
|
53815
|
+
}
|
|
53816
|
+
if (Array.isArray(schema.enum) && !schema.enum.some((e) => deepEqual2(e, value))) {
|
|
53817
|
+
return { ok: false, reason: `${at}: not one of the allowed values` };
|
|
53818
|
+
}
|
|
53819
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
53820
|
+
const obj = value;
|
|
53821
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
53822
|
+
for (const key of required) {
|
|
53823
|
+
if (!(key in obj)) return { ok: false, reason: `${at}: missing required property "${key}"` };
|
|
53824
|
+
}
|
|
53825
|
+
const properties = schema.properties ?? {};
|
|
53826
|
+
if (schema.additionalProperties === false) {
|
|
53827
|
+
for (const key of Object.keys(obj)) {
|
|
53828
|
+
if (!(key in properties)) return { ok: false, reason: `${at}: unexpected property "${key}"` };
|
|
53829
|
+
}
|
|
53830
|
+
}
|
|
53831
|
+
for (const [key, sub] of Object.entries(properties)) {
|
|
53832
|
+
if (key in obj) {
|
|
53833
|
+
const result = validateNode(sub, obj[key], `${path}.${key}`);
|
|
53834
|
+
if (!result.ok) return result;
|
|
53835
|
+
}
|
|
53836
|
+
}
|
|
53837
|
+
}
|
|
53838
|
+
if (Array.isArray(value) && schema.items !== void 0) {
|
|
53839
|
+
const items = schema.items;
|
|
53840
|
+
for (let i = 0; i < value.length; i++) {
|
|
53841
|
+
const result = validateNode(items, value[i], `${path}[${i}]`);
|
|
53842
|
+
if (!result.ok) return result;
|
|
53843
|
+
}
|
|
53844
|
+
}
|
|
53845
|
+
if (typeof value === "string") {
|
|
53846
|
+
if (typeof schema.minLength === "number" && value.length < schema.minLength) {
|
|
53847
|
+
return { ok: false, reason: `${at}: shorter than ${schema.minLength}` };
|
|
53848
|
+
}
|
|
53849
|
+
if (typeof schema.pattern === "string" && !new RegExp(schema.pattern).test(value)) {
|
|
53850
|
+
return { ok: false, reason: `${at}: does not match the required pattern` };
|
|
53851
|
+
}
|
|
53852
|
+
}
|
|
53853
|
+
if (typeof value === "number" && typeof schema.minimum === "number" && value < schema.minimum) {
|
|
53854
|
+
return { ok: false, reason: `${at}: below the minimum ${schema.minimum}` };
|
|
53855
|
+
}
|
|
53856
|
+
return { ok: true };
|
|
53857
|
+
}
|
|
53858
|
+
function validateAgainstInputSchema(schema, args) {
|
|
53859
|
+
return validateNode(schema, args, "");
|
|
53860
|
+
}
|
|
53861
|
+
var PR_ARGS_INPUT_SCHEMA = {
|
|
53862
|
+
type: "object",
|
|
53863
|
+
properties: {
|
|
53864
|
+
repo: {
|
|
53865
|
+
type: "string",
|
|
53866
|
+
description: "Repository in `owner/name` form, e.g. `agentproto/ts`.",
|
|
53867
|
+
pattern: "^[^/\\s]+/[^/\\s]+$"
|
|
53868
|
+
},
|
|
53869
|
+
number: {
|
|
53870
|
+
type: "integer",
|
|
53871
|
+
description: "Pull request number.",
|
|
53872
|
+
minimum: 1
|
|
53873
|
+
}
|
|
53874
|
+
},
|
|
53875
|
+
required: ["repo", "number"],
|
|
53876
|
+
additionalProperties: false
|
|
53877
|
+
};
|
|
53878
|
+
var ENVELOPE_DATA_PROPERTIES = {
|
|
53879
|
+
subject: { type: "string", description: "CloudEvents subject the event is filed under." },
|
|
53880
|
+
summary: { type: "string", description: "One-line human-readable summary." }
|
|
53881
|
+
};
|
|
53882
|
+
function payloadSchema2(properties, required) {
|
|
53883
|
+
return {
|
|
53884
|
+
type: "object",
|
|
53885
|
+
properties: { ...properties, ...ENVELOPE_DATA_PROPERTIES },
|
|
53886
|
+
required: [...required, "subject", "summary"],
|
|
53887
|
+
additionalProperties: false
|
|
53888
|
+
};
|
|
53889
|
+
}
|
|
53890
|
+
function githubPrArgumentsToMatch(eventName) {
|
|
53891
|
+
return (args) => {
|
|
53892
|
+
const repo = args.repo;
|
|
53893
|
+
const number = args.number;
|
|
53894
|
+
if (typeof repo !== "string" || !/^[^/\s]+\/[^/\s]+$/.test(repo)) {
|
|
53895
|
+
return { ok: false, reason: "`repo` must be `owner/name`" };
|
|
53896
|
+
}
|
|
53897
|
+
if (typeof number !== "number" || !Number.isInteger(number) || number <= 0) {
|
|
53898
|
+
return { ok: false, reason: "`number` must be a positive integer" };
|
|
53899
|
+
}
|
|
53900
|
+
return {
|
|
53901
|
+
ok: true,
|
|
53902
|
+
matchClauses: [{ subject: `github:${repo}#${number}`, types: [eventName] }],
|
|
53903
|
+
providerSlug: "local-gh"
|
|
53904
|
+
};
|
|
53905
|
+
};
|
|
53906
|
+
}
|
|
53907
|
+
function githubAuthorize(_args, _principal) {
|
|
53908
|
+
return true;
|
|
53909
|
+
}
|
|
53910
|
+
function githubEvent(input) {
|
|
53911
|
+
return {
|
|
53912
|
+
definition: {
|
|
53913
|
+
name: input.name,
|
|
53914
|
+
description: input.description,
|
|
53915
|
+
delivery: ["webhook"],
|
|
53916
|
+
inputSchema: PR_ARGS_INPUT_SCHEMA,
|
|
53917
|
+
payloadSchema: input.payloadSchema
|
|
53918
|
+
},
|
|
53919
|
+
meta: {
|
|
53920
|
+
// v1 REALITY: no provider has historical replay (plan §2) — every
|
|
53921
|
+
// definition is non-replayable and always returns `cursor: null`.
|
|
53922
|
+
replayable: false,
|
|
53923
|
+
argumentsToMatch: githubPrArgumentsToMatch(input.name),
|
|
53924
|
+
authorize: githubAuthorize
|
|
53925
|
+
}
|
|
53926
|
+
};
|
|
53927
|
+
}
|
|
53928
|
+
var GITHUB_SCHEME = {
|
|
53929
|
+
scheme: "github",
|
|
53930
|
+
events: [
|
|
53931
|
+
githubEvent({
|
|
53932
|
+
name: "github.pull_request.closed",
|
|
53933
|
+
description: "A pull request was closed or merged.",
|
|
53934
|
+
payloadSchema: payloadSchema2(
|
|
53935
|
+
{
|
|
53936
|
+
action: { type: "string", const: "closed" },
|
|
53937
|
+
merged: { type: "boolean", description: "True when the PR was merged rather than closed unmerged." },
|
|
53938
|
+
repo: { type: "string" },
|
|
53939
|
+
number: { type: "integer" }
|
|
53940
|
+
},
|
|
53941
|
+
["action", "merged", "repo", "number"]
|
|
53942
|
+
)
|
|
53943
|
+
}),
|
|
53944
|
+
githubEvent({
|
|
53945
|
+
name: "github.pull_request.synchronize",
|
|
53946
|
+
description: "New commits were pushed to a pull request's head branch.",
|
|
53947
|
+
payloadSchema: payloadSchema2(
|
|
53948
|
+
{
|
|
53949
|
+
action: { type: "string", const: "synchronize" },
|
|
53950
|
+
repo: { type: "string" },
|
|
53951
|
+
number: { type: "integer" },
|
|
53952
|
+
headSha: { type: "string" }
|
|
53953
|
+
},
|
|
53954
|
+
["action", "repo", "number", "headSha"]
|
|
53955
|
+
)
|
|
53956
|
+
}),
|
|
53957
|
+
githubEvent({
|
|
53958
|
+
name: "github.pull_request_review.submitted",
|
|
53959
|
+
description: "A review was submitted on a pull request.",
|
|
53960
|
+
payloadSchema: payloadSchema2(
|
|
53961
|
+
{
|
|
53962
|
+
action: { type: "string", const: "submitted" },
|
|
53963
|
+
state: { type: "string", description: "Review state, e.g. `approved`, `changes_requested`." },
|
|
53964
|
+
repo: { type: "string" },
|
|
53965
|
+
number: { type: "integer" },
|
|
53966
|
+
actor: { type: "string" }
|
|
53967
|
+
},
|
|
53968
|
+
["action", "state", "repo", "number", "actor"]
|
|
53969
|
+
)
|
|
53970
|
+
}),
|
|
53971
|
+
githubEvent({
|
|
53972
|
+
name: "github.check_suite.completed",
|
|
53973
|
+
description: "The checks on a pull request finished (a `failure` conclusion is the build-failed signal).",
|
|
53974
|
+
payloadSchema: payloadSchema2(
|
|
53975
|
+
{
|
|
53976
|
+
action: { type: "string", const: "completed" },
|
|
53977
|
+
conclusion: { type: "string", description: "Rolled-up worst-of conclusion across the completed checks." },
|
|
53978
|
+
repo: { type: "string" },
|
|
53979
|
+
number: { type: "integer" },
|
|
53980
|
+
checks: {
|
|
53981
|
+
type: "array",
|
|
53982
|
+
items: {
|
|
53983
|
+
type: "object",
|
|
53984
|
+
properties: {
|
|
53985
|
+
name: { type: "string" },
|
|
53986
|
+
conclusion: { type: ["string", "null"] }
|
|
53987
|
+
},
|
|
53988
|
+
required: ["name", "conclusion"],
|
|
53989
|
+
additionalProperties: true
|
|
53990
|
+
}
|
|
53991
|
+
}
|
|
53992
|
+
},
|
|
53993
|
+
["action", "conclusion", "repo", "number", "checks"]
|
|
53994
|
+
)
|
|
53995
|
+
})
|
|
53996
|
+
]
|
|
53997
|
+
};
|
|
53998
|
+
var EVENT_REGISTRY = [GITHUB_SCHEME];
|
|
53999
|
+
function tenantScope(_principal) {
|
|
54000
|
+
return EVENT_REGISTRY;
|
|
54001
|
+
}
|
|
54002
|
+
function findEventDefinition(name) {
|
|
54003
|
+
for (const scheme of EVENT_REGISTRY) {
|
|
54004
|
+
for (const event of scheme.events) {
|
|
54005
|
+
if (event.definition.name === name) return event;
|
|
54006
|
+
}
|
|
54007
|
+
}
|
|
54008
|
+
return void 0;
|
|
54009
|
+
}
|
|
54010
|
+
|
|
54011
|
+
// src/mcp-events/adapter.ts
|
|
54012
|
+
var DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
54013
|
+
var MAX_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
54014
|
+
var MIN_TTL_MS = 60 * 1e3;
|
|
54015
|
+
function computeRefreshBefore(until) {
|
|
54016
|
+
return until.kind === "at" ? new Date(until.ms).toISOString() : null;
|
|
54017
|
+
}
|
|
54018
|
+
function untilForTtl(ttlMs, now) {
|
|
54019
|
+
if (ttlMs === null) return { kind: "never" };
|
|
54020
|
+
const requested = ttlMs === void 0 ? DEFAULT_TTL_MS : ttlMs;
|
|
54021
|
+
const granted = Math.max(MIN_TTL_MS, Math.min(requested, MAX_TTL_MS));
|
|
54022
|
+
return { kind: "at", ms: now + granted };
|
|
54023
|
+
}
|
|
54024
|
+
var McpEventsError = class extends Error {
|
|
54025
|
+
code;
|
|
54026
|
+
data;
|
|
54027
|
+
constructor(code, message, data) {
|
|
54028
|
+
super(message);
|
|
54029
|
+
this.name = "McpEventsError";
|
|
54030
|
+
this.code = code;
|
|
54031
|
+
this.data = data;
|
|
54032
|
+
}
|
|
54033
|
+
};
|
|
54034
|
+
function invalidParams(reason, detail) {
|
|
54035
|
+
return new McpEventsError(-32602, `Invalid params: ${detail}`, { reason });
|
|
54036
|
+
}
|
|
54037
|
+
function callbackEndpointError(reason, detail) {
|
|
54038
|
+
return new McpEventsError(-32015, `CallbackEndpointError: ${detail}`, { reason });
|
|
54039
|
+
}
|
|
54040
|
+
var mutationChain = Promise.resolve();
|
|
54041
|
+
function withSubscribeMutex(fn) {
|
|
54042
|
+
const run = mutationChain.then(fn, fn);
|
|
54043
|
+
mutationChain = run.catch(() => void 0);
|
|
54044
|
+
return run;
|
|
54045
|
+
}
|
|
54046
|
+
function isRecord10(value) {
|
|
54047
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
54048
|
+
}
|
|
54049
|
+
var LIST_PAGE_DEFAULT = 50;
|
|
54050
|
+
var LIST_PAGE_MAX = 200;
|
|
54051
|
+
function encodeListCursor(offset, scheme) {
|
|
54052
|
+
return Buffer.from(JSON.stringify({ offset, scheme }), "utf8").toString("base64url");
|
|
54053
|
+
}
|
|
54054
|
+
function decodeListCursor(cursor) {
|
|
54055
|
+
if (cursor === void 0 || cursor === "") return 0;
|
|
54056
|
+
try {
|
|
54057
|
+
const parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
54058
|
+
if (typeof parsed.offset !== "number" || !Number.isInteger(parsed.offset) || parsed.offset < 0) {
|
|
54059
|
+
throw new Error("bad offset");
|
|
54060
|
+
}
|
|
54061
|
+
return parsed.offset;
|
|
54062
|
+
} catch {
|
|
54063
|
+
throw invalidParams("invalid_cursor", "`cursor` is not a cursor issued by a previous events/list response");
|
|
54064
|
+
}
|
|
54065
|
+
}
|
|
54066
|
+
function requireWebhookDelivery(delivery) {
|
|
54067
|
+
if (!isRecord10(delivery) || delivery.mode !== "webhook") {
|
|
54068
|
+
throw invalidParams("unsupported_delivery_mode", 'delivery.mode must be "webhook"');
|
|
54069
|
+
}
|
|
54070
|
+
if (typeof delivery.url !== "string" || delivery.url.length === 0) {
|
|
54071
|
+
throw invalidParams("invalid_callback_url", "delivery.url is required");
|
|
54072
|
+
}
|
|
54073
|
+
return { mode: "webhook", url: delivery.url, ...typeof delivery.secret === "string" ? { secret: delivery.secret } : {} };
|
|
54074
|
+
}
|
|
54075
|
+
function validateArgsOrThrow(name, registration, args) {
|
|
54076
|
+
if (!isRecord10(args)) throw invalidParams("invalid_arguments", "`arguments` must be an object");
|
|
54077
|
+
const schemaCheck = validateAgainstInputSchema(registration.definition.inputSchema, args);
|
|
54078
|
+
if (!schemaCheck.ok) {
|
|
54079
|
+
throw invalidParams("invalid_arguments", `arguments for "${name}": ${schemaCheck.reason}`);
|
|
54080
|
+
}
|
|
54081
|
+
return args;
|
|
54082
|
+
}
|
|
54083
|
+
async function eventsList(r, ctx) {
|
|
54084
|
+
const schemes = tenantScope(ctx.principal);
|
|
54085
|
+
const definitions = schemes.flatMap((scheme2) => scheme2.events.map((event) => event.definition));
|
|
54086
|
+
const requested = r.pageSize ?? LIST_PAGE_DEFAULT;
|
|
54087
|
+
const pageSize = Math.max(1, Math.min(Number.isFinite(requested) ? Math.floor(requested) : LIST_PAGE_DEFAULT, LIST_PAGE_MAX));
|
|
54088
|
+
const offset = decodeListCursor(r.cursor);
|
|
54089
|
+
const page = definitions.slice(offset, offset + pageSize);
|
|
54090
|
+
const next = offset + page.length;
|
|
54091
|
+
const scheme = schemes[0]?.scheme ?? "*";
|
|
54092
|
+
return { events: page, nextCursor: next < definitions.length ? encodeListCursor(next, scheme) : null };
|
|
54093
|
+
}
|
|
54094
|
+
async function eventsSubscribe(input, ctx) {
|
|
54095
|
+
const now = ctx.nowMs ?? Date.now;
|
|
54096
|
+
const registration = findEventDefinition(input.name);
|
|
54097
|
+
if (!registration) throw invalidParams("unknown_event", `unknown event "${input.name}"`);
|
|
54098
|
+
const args = validateArgsOrThrow(input.name, registration, input.arguments);
|
|
54099
|
+
if (!registration.meta.authorize(args, ctx.principal)) {
|
|
54100
|
+
throw invalidParams("unauthorized", `not authorized to subscribe to "${input.name}" with the given arguments`);
|
|
54101
|
+
}
|
|
54102
|
+
const mapped = registration.meta.argumentsToMatch(args);
|
|
54103
|
+
if (!mapped.ok) throw invalidParams("invalid_arguments", `arguments for "${input.name}": ${mapped.reason}`);
|
|
54104
|
+
const delivery = requireWebhookDelivery(input.delivery);
|
|
54105
|
+
const secret = delivery.secret;
|
|
54106
|
+
if (secret === void 0 || decodeWhsecSecret(secret) === null) {
|
|
54107
|
+
throw invalidParams(
|
|
54108
|
+
"invalid_secret",
|
|
54109
|
+
"delivery.secret must be `whsec_` followed by base64 that decodes to 24..64 bytes"
|
|
54110
|
+
);
|
|
54111
|
+
}
|
|
54112
|
+
if (input.ttlMs !== void 0 && input.ttlMs !== null && (typeof input.ttlMs !== "number" || !Number.isFinite(input.ttlMs))) {
|
|
54113
|
+
throw invalidParams("invalid_ttl", "`ttlMs` must be a finite number or null");
|
|
54114
|
+
}
|
|
54115
|
+
const id = subscriptionId({
|
|
54116
|
+
principal: ctx.principal,
|
|
54117
|
+
callbackUrl: delivery.url,
|
|
54118
|
+
eventName: input.name,
|
|
54119
|
+
args
|
|
54120
|
+
});
|
|
54121
|
+
const verify = ctx.verify ?? verifyCallback;
|
|
54122
|
+
const outcome = await verify({ principal: ctx.principal, url: delivery.url, subscriptionId: id, secret });
|
|
54123
|
+
if (!outcome.ok) throw callbackEndpointError(outcome.reason, outcome.detail);
|
|
54124
|
+
return withSubscribeMutex(async () => {
|
|
54125
|
+
const until = untilForTtl(input.ttlMs, now());
|
|
54126
|
+
const existing = ctx.store.get(id);
|
|
54127
|
+
if (existing) {
|
|
54128
|
+
const target = existing.spec.target;
|
|
54129
|
+
if (target.kind !== "webhook") {
|
|
54130
|
+
throw invalidParams("identity_conflict", `subscription ${id} exists with a non-webhook target`);
|
|
54131
|
+
}
|
|
54132
|
+
const ref = ctx.store.materializeWebhookTargetRef(target);
|
|
54133
|
+
if (ref !== void 0) ctx.store.putSentinelSecret(ref, { secret });
|
|
54134
|
+
ctx.store.update(id, { spec: { ...existing.spec, until }, status: "active" });
|
|
54135
|
+
return { id, refreshBefore: computeRefreshBefore(until), cursor: null };
|
|
54136
|
+
}
|
|
54137
|
+
const provider = await ctx.resolveProvider(mapped.providerSlug);
|
|
54138
|
+
if (!provider) {
|
|
54139
|
+
throw invalidParams("provider_unavailable", `sentinel provider "${mapped.providerSlug}" is not available`);
|
|
54140
|
+
}
|
|
54141
|
+
const spec = {
|
|
54142
|
+
match: mapped.matchClauses,
|
|
54143
|
+
until,
|
|
54144
|
+
target: { kind: "webhook", url: delivery.url, secret },
|
|
54145
|
+
provider: mapped.providerSlug
|
|
54146
|
+
};
|
|
54147
|
+
const handle = await provider.create(spec, deliveryPreferenceFor(provider, ctx.activeIntervalMs ?? 15e3), {
|
|
54148
|
+
sentinelId: id
|
|
54149
|
+
});
|
|
54150
|
+
ctx.store.create({ id, spec, provider: mapped.providerSlug, handle });
|
|
54151
|
+
return { id, refreshBefore: computeRefreshBefore(until), cursor: null };
|
|
54152
|
+
});
|
|
54153
|
+
}
|
|
54154
|
+
async function eventsUnsubscribe(input, ctx) {
|
|
54155
|
+
const registration = findEventDefinition(input.name);
|
|
54156
|
+
if (!registration) throw invalidParams("unknown_event", `unknown event "${input.name}"`);
|
|
54157
|
+
const args = validateArgsOrThrow(input.name, registration, input.arguments);
|
|
54158
|
+
if (!registration.meta.authorize(args, ctx.principal)) {
|
|
54159
|
+
throw invalidParams("unauthorized", `not authorized to unsubscribe from "${input.name}" with the given arguments`);
|
|
54160
|
+
}
|
|
54161
|
+
const delivery = requireWebhookDelivery(input.delivery);
|
|
54162
|
+
const id = subscriptionId({
|
|
54163
|
+
principal: ctx.principal,
|
|
54164
|
+
callbackUrl: delivery.url,
|
|
54165
|
+
eventName: input.name,
|
|
54166
|
+
args
|
|
54167
|
+
});
|
|
54168
|
+
await withSubscribeMutex(async () => {
|
|
54169
|
+
const existing = ctx.store.get(id);
|
|
54170
|
+
if (!existing) return;
|
|
54171
|
+
const provider = await ctx.resolveProvider(existing.provider);
|
|
54172
|
+
if (provider) {
|
|
54173
|
+
try {
|
|
54174
|
+
await provider.cancel(existing.handle);
|
|
54175
|
+
} catch {
|
|
54176
|
+
}
|
|
54177
|
+
}
|
|
54178
|
+
ctx.store.remove(id);
|
|
54179
|
+
});
|
|
54180
|
+
return {};
|
|
54181
|
+
}
|
|
54182
|
+
function toMcpEvent(event) {
|
|
54183
|
+
return {
|
|
54184
|
+
eventId: event.id,
|
|
54185
|
+
name: event.type,
|
|
54186
|
+
timestamp: event.time,
|
|
54187
|
+
data: { ...event.data, subject: event.subject, summary: event.summary },
|
|
54188
|
+
cursor: null
|
|
54189
|
+
};
|
|
54190
|
+
}
|
|
53106
54191
|
|
|
53107
54192
|
// src/sentinel-webhook-outbox.ts
|
|
53108
54193
|
function agentprotoHome3() {
|
|
@@ -53118,13 +54203,7 @@ function webhookRequestId(sentinelId, eventId) {
|
|
|
53118
54203
|
return `sub_${digest.slice(0, 32)}`;
|
|
53119
54204
|
}
|
|
53120
54205
|
function toWebhookEnvelope(event) {
|
|
53121
|
-
return
|
|
53122
|
-
eventId: event.id,
|
|
53123
|
-
name: event.type,
|
|
53124
|
-
timestamp: event.time,
|
|
53125
|
-
data: { ...event.data, subject: event.subject, summary: event.summary },
|
|
53126
|
-
cursor: null
|
|
53127
|
-
};
|
|
54206
|
+
return toMcpEvent(event);
|
|
53128
54207
|
}
|
|
53129
54208
|
function createSentinelWebhookOutbox(opts) {
|
|
53130
54209
|
const filePath = opts.filePath ?? resolve(agentprotoHome3(), "sentinel-webhook-outbox.json");
|
|
@@ -55026,12 +56105,12 @@ function canonicalJson(value) {
|
|
|
55026
56105
|
}
|
|
55027
56106
|
function isToolAppVisible(tool) {
|
|
55028
56107
|
const meta = tool._meta;
|
|
55029
|
-
const ui =
|
|
56108
|
+
const ui = isRecord11(meta?.ui) ? meta.ui : void 0;
|
|
55030
56109
|
const visibility = ui?.visibility;
|
|
55031
56110
|
if (!Array.isArray(visibility)) return true;
|
|
55032
56111
|
return visibility.includes("app");
|
|
55033
56112
|
}
|
|
55034
|
-
function
|
|
56113
|
+
function isRecord11(v) {
|
|
55035
56114
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
55036
56115
|
}
|
|
55037
56116
|
function buildUiToolIndex(tools) {
|
|
@@ -55556,19 +56635,19 @@ function classifyMcpError(err) {
|
|
|
55556
56635
|
return { status: "unreachable", error };
|
|
55557
56636
|
}
|
|
55558
56637
|
function uiMetaOf(meta) {
|
|
55559
|
-
if (!
|
|
56638
|
+
if (!isRecord12(meta) || !isRecord12(meta.ui)) return {};
|
|
55560
56639
|
const ui = meta.ui;
|
|
55561
56640
|
const csp = cspOf(ui.csp);
|
|
55562
56641
|
return {
|
|
55563
56642
|
...csp ? { csp } : {},
|
|
55564
|
-
...
|
|
56643
|
+
...isRecord12(ui.permissions) ? { permissions: ui.permissions } : {},
|
|
55565
56644
|
...typeof ui.prefersBorder === "boolean" ? { prefersBorder: ui.prefersBorder } : {},
|
|
55566
56645
|
...typeof ui.domain === "string" ? { domain: ui.domain } : {}
|
|
55567
56646
|
};
|
|
55568
56647
|
}
|
|
55569
56648
|
var CSP_DOMAIN_KEYS = ["connectDomains", "resourceDomains", "frameDomains", "baseUriDomains"];
|
|
55570
56649
|
function cspOf(raw) {
|
|
55571
|
-
if (!
|
|
56650
|
+
if (!isRecord12(raw)) return void 0;
|
|
55572
56651
|
const csp = {};
|
|
55573
56652
|
for (const key of CSP_DOMAIN_KEYS) {
|
|
55574
56653
|
const value = raw[key];
|
|
@@ -55578,7 +56657,7 @@ function cspOf(raw) {
|
|
|
55578
56657
|
}
|
|
55579
56658
|
return Object.keys(csp).length > 0 ? csp : void 0;
|
|
55580
56659
|
}
|
|
55581
|
-
function
|
|
56660
|
+
function isRecord12(v) {
|
|
55582
56661
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
55583
56662
|
}
|
|
55584
56663
|
function errorMessage(err) {
|
|
@@ -58087,7 +59166,7 @@ function humanizeKey(key) {
|
|
|
58087
59166
|
const words = key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_\-.]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase();
|
|
58088
59167
|
return words.length === 0 ? "Value" : words.charAt(0).toUpperCase() + words.slice(1);
|
|
58089
59168
|
}
|
|
58090
|
-
function
|
|
59169
|
+
function isRecord13(value) {
|
|
58091
59170
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
58092
59171
|
}
|
|
58093
59172
|
function scalarText(value) {
|
|
@@ -58117,7 +59196,7 @@ function flattenRows(value, label, depth, out) {
|
|
|
58117
59196
|
});
|
|
58118
59197
|
return;
|
|
58119
59198
|
}
|
|
58120
|
-
if (
|
|
59199
|
+
if (isRecord13(value)) {
|
|
58121
59200
|
if (depth >= MAX_DEPTH) return;
|
|
58122
59201
|
for (const [key, child] of Object.entries(value)) {
|
|
58123
59202
|
flattenRows(child, label ? `${label} / ${humanizeKey(key)}` : humanizeKey(key), depth + 1, out);
|
|
@@ -58139,7 +59218,7 @@ function renderMail(preview2) {
|
|
|
58139
59218
|
const cc = addressList(preview2.cc);
|
|
58140
59219
|
const subject = scalarText(preview2.subject) ?? "";
|
|
58141
59220
|
const body = scalarText(preview2.body) ?? "";
|
|
58142
|
-
const attachments = Array.isArray(preview2.attachments) ? preview2.attachments.filter(
|
|
59221
|
+
const attachments = Array.isArray(preview2.attachments) ? preview2.attachments.filter(isRecord13).map((a) => {
|
|
58143
59222
|
const name = scalarText(a.fileName) ?? "";
|
|
58144
59223
|
const size = typeof a.sizeBytes === "number" ? humanSize(a.sizeBytes) : "";
|
|
58145
59224
|
return size ? `${name} (${size})` : name;
|
|
@@ -58154,9 +59233,9 @@ function renderMail(preview2) {
|
|
|
58154
59233
|
}
|
|
58155
59234
|
function renderPreview(record2) {
|
|
58156
59235
|
const preview2 = record2.preview;
|
|
58157
|
-
if (
|
|
59236
|
+
if (isRecord13(preview2) && preview2.kind === "mail") return renderMail(preview2);
|
|
58158
59237
|
const rows = [];
|
|
58159
|
-
if (
|
|
59238
|
+
if (isRecord13(preview2)) {
|
|
58160
59239
|
for (const [key, value] of Object.entries(preview2)) flattenRows(value, humanizeKey(key), 1, rows);
|
|
58161
59240
|
} else {
|
|
58162
59241
|
flattenRows(preview2, "Details", 1, rows);
|
|
@@ -59608,6 +60687,8 @@ async function reconcileSandboxLedger(deps2) {
|
|
|
59608
60687
|
// src/index.ts
|
|
59609
60688
|
init_session_outcome();
|
|
59610
60689
|
init_session_end_reason();
|
|
60690
|
+
init_transcript_writer();
|
|
60691
|
+
init_session_index();
|
|
59611
60692
|
init_sessions();
|
|
59612
60693
|
init_sessions();
|
|
59613
60694
|
init_process_stats();
|
|
@@ -59627,12 +60708,12 @@ function measureToolList(tools) {
|
|
|
59627
60708
|
}
|
|
59628
60709
|
var packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
59629
60710
|
var helpDir = join(packageRoot, "docs", "mcp-tools");
|
|
59630
|
-
var
|
|
60711
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
59631
60712
|
function getToolHelp(name) {
|
|
59632
|
-
if (
|
|
60713
|
+
if (cache2.has(name)) return cache2.get(name);
|
|
59633
60714
|
const path = join(helpDir, `${name}.md`);
|
|
59634
60715
|
const content = existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
59635
|
-
|
|
60716
|
+
cache2.set(name, content);
|
|
59636
60717
|
return content;
|
|
59637
60718
|
}
|
|
59638
60719
|
function listToolHelpTopics() {
|
|
@@ -61925,7 +63006,7 @@ async function registerSentinelAdapterTools(server, opts = {}) {
|
|
|
61925
63006
|
makeListTool({
|
|
61926
63007
|
server,
|
|
61927
63008
|
toolName: "list_sentinel_adapters",
|
|
61928
|
-
description: "List known sentinel providers with their status (supported/available/ready), version, and declared capabilities (subjects, push, poll, durable, needsPublicUrl, requiresAuth, typicalLatencyMs). Credentials are never returned. Use `setup_sentinel_provider` to configure a provider that needs creds.",
|
|
63009
|
+
description: "List known sentinel providers with their status (supported/available/ready), version, and declared capabilities (subjects, push, poll, durable, needsPublicUrl, requiresAuth, typicalLatencyMs). Credentials are never returned. Use `setup_sentinel_provider` to configure a provider that needs creds. A `webhook` sentinel target (Standard Webhooks signed delivery to an external HTTP callback, with persisted outbox and resume post-restart) is accepted since W-B; the `mcp-events` MCP surface (events/list, events/subscribe, events/unsubscribe) ships with W-C.",
|
|
61929
63010
|
lister: makeSentinelLister({ credsStore, ledger })
|
|
61930
63011
|
});
|
|
61931
63012
|
const { validSlugs, fields } = await collectSetupSchema3();
|
|
@@ -62050,102 +63131,6 @@ function createWorkspaceFs(opts) {
|
|
|
62050
63131
|
|
|
62051
63132
|
// src/index.ts
|
|
62052
63133
|
init_role();
|
|
62053
|
-
function challengeReasonForSsrf(reason) {
|
|
62054
|
-
if (reason === "non_https") return "non_https";
|
|
62055
|
-
if (reason === "private_target" || reason === "redirect") return "ssrf_blocked";
|
|
62056
|
-
return "timeout";
|
|
62057
|
-
}
|
|
62058
|
-
var CHALLENGE_TTL_MS = 10 * 60 * 1e3;
|
|
62059
|
-
var encoder = new TextEncoder();
|
|
62060
|
-
var cache2 = /* @__PURE__ */ new Map();
|
|
62061
|
-
function challengeCacheSize() {
|
|
62062
|
-
return cache2.size;
|
|
62063
|
-
}
|
|
62064
|
-
function resetChallengeCacheForTests() {
|
|
62065
|
-
cache2.clear();
|
|
62066
|
-
}
|
|
62067
|
-
function normalizeCallbackUrl(url) {
|
|
62068
|
-
try {
|
|
62069
|
-
const u = new URL(url);
|
|
62070
|
-
const port = u.port === "443" ? "" : `:${u.port}`;
|
|
62071
|
-
return `${u.protocol.toLowerCase()}//${u.hostname.toLowerCase()}${port}${u.pathname}${u.search}`;
|
|
62072
|
-
} catch {
|
|
62073
|
-
return null;
|
|
62074
|
-
}
|
|
62075
|
-
}
|
|
62076
|
-
function hashSecret(secret) {
|
|
62077
|
-
return createHash("sha256").update(secret, "utf8").digest("hex");
|
|
62078
|
-
}
|
|
62079
|
-
function constantTimeEq(a, b) {
|
|
62080
|
-
const da = createHash("sha256").update(a, "utf8").digest();
|
|
62081
|
-
const db = createHash("sha256").update(b, "utf8").digest();
|
|
62082
|
-
return timingSafeEqual(da, db);
|
|
62083
|
-
}
|
|
62084
|
-
async function verifyCallback(input, deps2 = {}) {
|
|
62085
|
-
const now = deps2.now ?? (() => Date.now());
|
|
62086
|
-
const normalized = normalizeCallbackUrl(input.url);
|
|
62087
|
-
if (normalized === null || !normalized.startsWith("https://")) {
|
|
62088
|
-
return { ok: false, reason: "non_https", detail: "callback URL must be an https URL" };
|
|
62089
|
-
}
|
|
62090
|
-
if (decodeWhsecSecret(input.secret) === null) {
|
|
62091
|
-
return {
|
|
62092
|
-
ok: false,
|
|
62093
|
-
reason: "challenge_failed",
|
|
62094
|
-
detail: "invalid secret format \u2014 must be whsec_ + base64 decoding to 24..64 bytes (the caller validates before this; a bad secret is never cached)"
|
|
62095
|
-
};
|
|
62096
|
-
}
|
|
62097
|
-
const cacheKey = `${input.principal}|${normalized}|${hashSecret(input.secret)}`;
|
|
62098
|
-
const cached = cache2.get(cacheKey);
|
|
62099
|
-
if (cached && cached.expiresAt > now()) {
|
|
62100
|
-
return { ok: true, verificationBytes: cached.requestBytes };
|
|
62101
|
-
}
|
|
62102
|
-
if (cached) cache2.delete(cacheKey);
|
|
62103
|
-
const challenge = randomBytes(32).toString("hex");
|
|
62104
|
-
const requestBytes = encoder.encode(JSON.stringify({ type: "verification", challenge }));
|
|
62105
|
-
const msgId = `msg_verification_${randomBytes(12).toString("hex")}`;
|
|
62106
|
-
const timestamp = Math.floor(now() / 1e3);
|
|
62107
|
-
let headers;
|
|
62108
|
-
try {
|
|
62109
|
-
const signed = signWebhook({ msgId, timestamp, payload: requestBytes, secrets: [input.secret] });
|
|
62110
|
-
headers = {
|
|
62111
|
-
...signed,
|
|
62112
|
-
"content-type": "application/json",
|
|
62113
|
-
"X-MCP-Subscription-Id": input.subscriptionId
|
|
62114
|
-
};
|
|
62115
|
-
} catch (err) {
|
|
62116
|
-
return { ok: false, reason: "challenge_failed", detail: `signing failed: ${err.message}` };
|
|
62117
|
-
}
|
|
62118
|
-
let response;
|
|
62119
|
-
try {
|
|
62120
|
-
response = await (deps2.fetch ?? ssrfFetch)(input.url, {
|
|
62121
|
-
method: "POST",
|
|
62122
|
-
headers,
|
|
62123
|
-
body: requestBytes,
|
|
62124
|
-
timeoutMs: 1e4
|
|
62125
|
-
// default challenge timeout (delivery uses 15_000)
|
|
62126
|
-
});
|
|
62127
|
-
} catch (err) {
|
|
62128
|
-
if (err instanceof SsrfFetchError) {
|
|
62129
|
-
return { ok: false, reason: challengeReasonForSsrf(err.reason), detail: `${err.reason}: ${err.message}` };
|
|
62130
|
-
}
|
|
62131
|
-
return { ok: false, reason: "timeout", detail: err.message };
|
|
62132
|
-
}
|
|
62133
|
-
if (response.status < 200 || response.status > 299) {
|
|
62134
|
-
return { ok: false, reason: "non_2xx", detail: `callback responded with status ${response.status}` };
|
|
62135
|
-
}
|
|
62136
|
-
let parsedBody;
|
|
62137
|
-
try {
|
|
62138
|
-
parsedBody = JSON.parse(response.body);
|
|
62139
|
-
} catch {
|
|
62140
|
-
return { ok: false, reason: "challenge_failed", detail: "response body is not JSON" };
|
|
62141
|
-
}
|
|
62142
|
-
const echoed = parsedBody?.challenge;
|
|
62143
|
-
if (typeof echoed !== "string" || !constantTimeEq(echoed, challenge)) {
|
|
62144
|
-
return { ok: false, reason: "challenge_failed", detail: "response did not echo the fresh challenge" };
|
|
62145
|
-
}
|
|
62146
|
-
cache2.set(cacheKey, { requestBytes, expiresAt: now() + CHALLENGE_TTL_MS });
|
|
62147
|
-
return { ok: true, verificationBytes: requestBytes };
|
|
62148
|
-
}
|
|
62149
63134
|
async function hasNamedLlmEndpoints() {
|
|
62150
63135
|
const override = process.env.LLM_ENDPOINT_ENDPOINTS_FILE?.trim();
|
|
62151
63136
|
const path = override && override.length > 0 ? override : join(homedir(), ".agentproto", "llm-endpoints.json");
|
|
@@ -62174,7 +63159,7 @@ init_worktree_isolation();
|
|
|
62174
63159
|
var pairing_registry_exports = {};
|
|
62175
63160
|
__reExport(pairing_registry_exports, pairing_host_star);
|
|
62176
63161
|
var JOIN_TOKENS_VERSION = 1;
|
|
62177
|
-
var
|
|
63162
|
+
var DEFAULT_TTL_MS2 = 90 * 864e5;
|
|
62178
63163
|
var DEFAULT_RECONNECT_MIN_MS = 1e3;
|
|
62179
63164
|
var DEFAULT_RECONNECT_MAX_MS = 3e4;
|
|
62180
63165
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 11e4;
|
|
@@ -62284,7 +63269,7 @@ function createJoinTokenRegistry(deps2) {
|
|
|
62284
63269
|
const secret = b64url(randomBytes(16));
|
|
62285
63270
|
const id = randomBytes(6).toString("hex");
|
|
62286
63271
|
const nowIso2 = new Date(now()).toISOString();
|
|
62287
|
-
const ttlMs = input.ttlMs ??
|
|
63272
|
+
const ttlMs = input.ttlMs ?? DEFAULT_TTL_MS2;
|
|
62288
63273
|
const expiresAt = new Date(now() + ttlMs).toISOString();
|
|
62289
63274
|
const record2 = {
|
|
62290
63275
|
id,
|
|
@@ -63456,6 +64441,20 @@ async function createGateway(opts) {
|
|
|
63456
64441
|
});
|
|
63457
64442
|
registerEvalReporterTools(server);
|
|
63458
64443
|
registerPresetTools(server);
|
|
64444
|
+
const eventsPrincipal = callerSessionId ? sessionPrincipal(callerSessionId) : daemonBearerPrincipal();
|
|
64445
|
+
registerEventsMethods(server, {
|
|
64446
|
+
list: (params) => eventsList(params, { principal: eventsPrincipal }),
|
|
64447
|
+
subscribe: (params) => eventsSubscribe(params, {
|
|
64448
|
+
principal: eventsPrincipal,
|
|
64449
|
+
store: sentinelStore,
|
|
64450
|
+
resolveProvider: resolveSentinelProviderResolved
|
|
64451
|
+
}),
|
|
64452
|
+
unsubscribe: (params) => eventsUnsubscribe(params, {
|
|
64453
|
+
principal: eventsPrincipal,
|
|
64454
|
+
store: sentinelStore,
|
|
64455
|
+
resolveProvider: resolveSentinelProviderResolved
|
|
64456
|
+
})
|
|
64457
|
+
});
|
|
63459
64458
|
return server;
|
|
63460
64459
|
};
|
|
63461
64460
|
let internalToolServerPromise;
|
|
@@ -63780,6 +64779,15 @@ async function createGateway(opts) {
|
|
|
63780
64779
|
...passOpts?.isServed ? { isServed: passOpts.isServed } : {}
|
|
63781
64780
|
});
|
|
63782
64781
|
},
|
|
64782
|
+
backfillSessionIndexes() {
|
|
64783
|
+
try {
|
|
64784
|
+
return backfillSessionIndexes(sessions.transcriptBaseDir, {
|
|
64785
|
+
descriptors: sessions.list({ includeArchived: true })
|
|
64786
|
+
});
|
|
64787
|
+
} catch {
|
|
64788
|
+
return { scanned: 0, created: 0, skipped: 0 };
|
|
64789
|
+
}
|
|
64790
|
+
},
|
|
63783
64791
|
async stop() {
|
|
63784
64792
|
heartbeat.stop();
|
|
63785
64793
|
if (idleReapTimer) clearInterval(idleReapTimer);
|
|
@@ -63852,6 +64860,6 @@ var export_readPairingsSnapshot = pairing_registry_exports.readPairingsSnapshot;
|
|
|
63852
64860
|
var export_removeProviderKey = providers_store_exports.removeProviderKey;
|
|
63853
64861
|
var export_setProviderKey = providers_store_exports.setProviderKey;
|
|
63854
64862
|
|
|
63855
|
-
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_WORKTREE_ISOLATION, DEFAULT_WORKTREE_PROVISION_CONCURRENCY, DEVICE_PROMPT_PATH_PREFIX, GC_REAPABLE_STATES, HOSTS_VERSION, HOST_HANDSHAKE_REMEDIATION_HINT, HOST_SCOPE_HEADER, HarnessPresetValidationError, INBOUND_PROVIDERS, JOIN_TOKENS_VERSION, LEGACY_SESSIONS_FILE, MAX_ATTEMPTS, MAX_AUTO_CONTINUE_ATTEMPTS, MAX_MESSAGE_DATA_BYTES, MCP_APP_BRIDGE_SCRIPT, MESSAGE_KINDS, MESSAGE_PREAMBLE, MESSAGE_TAG, MESSAGE_URGENCIES, MODEL_ROLE_REF_PREFIX, 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, SsrfFetchError, SubscriptionSourceError, TASK_STATUSES, WORKSPACE_SLUG_ENV, WORKTREE_ISOLATION_ENV, WORKTREE_PROVISION_CONCURRENCY_ENV, activityCounts, addHarnessPreset, allowedSignersLine, appendConversationRecord, attachSandbox, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogModels, buildCatalogProviderModels, buildHostLoadReport, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, canonicalForModeId, challengeCacheSize, challengeReasonForSsrf, claudeProjectSlug, collectGcCandidates, collectHostSample, compactOutcome, composeMode, composeSessionObservers, composedFromRangeSha, computeHostWarnings, 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, createSessionMessage, createSupervisorTaskGateRunner, createTaskLedger, createWorkspaceBrainSubscriber, createWorkspaceBrains, createWorkspaceFs, credentialFingerprint, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, decodeWhsecSecret, decomposeMode, defaultBrowserAdapterIds, defaultBrowserAdapterResolution, defaultReviewKeysDir, defaultReviewLedgerRoot, defaultReviewPackCacheDir, defineBraveSearchHttpDriver, defineSerperHttpDriver, deleteUserPreset, deliverEventEnvelope, deliveryBackoffDelay, deriveSessionOutcome, deriveSessionUsage, describeOwner, encodeWhsecSecret, enrichRollupWithProviderQuota, enrichWithRemainingQuota, ensureReviewSigningKey, envelopeClampedBytes, escapeHumanPrompt, escapeMessageBody, evaluateCostBudget, execGh, extractHelpSection, fetchHostTurns, fetchPrStatus, fileConversationStore, fileExists3 as fileExists, filterActivities, findComposeCandidate, findConversationRecord, findNativeMode, findPrForCommit, formatToolCall, formatToolResult, getDefaultHarnessPreset, getHarnessPreset, getHostLoadService, getMcpCredentialDeps, getProcessStatsService, export_getProviderKey as getProviderKey, getToolHelp, getUserPreset, githubRepoOf, harnessPresetsPath, hostPlaceholders, hostRecordToMirrorRecord, injectMcpAppBridge, export_injectProviderKeysIntoEnv as injectProviderKeysIntoEnv, isAgentCliAuthConfigured, isClosedTaskStatus, isKnownSessionEndReason, isMessageAllowed, isNoSessionPromptFailure, isProviderLimitError, isPubliclyRoutable, isSafeBucketSlug, isTerminalActivityState, listBuckets, listHarnessPresets, listModelRoles, listPresets, listToolHelpTopics, listUserPresets, loadHarnessPresets, export_loadProviders as loadProviders, loadQuotaStore, loadUserPresets, loadWorkspaceModelRoles, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, makeSandboxCredsStore, makeSandboxResolver, matchesMessageFilter, 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, readConversationIndex, readDaemonRegistry, readHostsSnapshot, export_readPairingsSnapshot as readPairingsSnapshot, readProfileQuota, readRegisteredSlugs, readRuntimeMeta, readSandboxLedger, readSessionForBrain, 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, rollupSessionSubtree, rollupUsage, runContinueOnBootPass, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runShellLane, runStallWatchdogPass, sandboxLedgerPath, sanitizeLabel, saveUserPreset, seedWalkForTranscript, serializeEnvelope, setDefaultPreset, setEgressDispatcherForTests, setMcpCredentialDeps, export_setProviderKey as setProviderKey, signAttestation, signWebhook, ssrfFetch, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, syncDeviceMirror, toWebhookEnvelope, toWorktreeStatusView, trackWorktreeProvision, turnToActivities, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, updateHarnessPreset, upsertSandboxLedger, userPresetsPath, verifyCallback, verifyInboundSignature, verifySignedAttestation, webSearchTool, webhookRequestId, withPr, withPrStatus, workflowToActivities, writeDaemonRegistryEntry };
|
|
64863
|
+
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, 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, 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, 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, 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, isClosedTaskStatus, isKnownSessionEndReason, isMessageAllowed, isNoSessionPromptFailure, isProviderLimitError, isPubliclyRoutable, isSafeBucketSlug, isTerminalActivityState, listBuckets, listHarnessPresets, listModelRoles, listPresets, listToolHelpTopics, listUserPresets, loadHarnessPresets, export_loadProviders as loadProviders, loadQuotaStore, loadUserPresets, loadWorkspaceModelRoles, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, 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, 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, withPr, withPrStatus, workflowToActivities, writeDaemonRegistryEntry, writeSessionIndex };
|
|
63856
64864
|
//# sourceMappingURL=index.mjs.map
|
|
63857
64865
|
//# sourceMappingURL=index.mjs.map
|