@agentproto/runtime 5.7.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 +775 -60
- package/dist/index.mjs +1421 -240
- 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-DHSLsPHA.d.ts → sessions-Cse9PhLG.d.ts} +113 -6
- package/dist/user-presets.d.ts +1 -1
- package/package.json +12 -12
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",
|
|
@@ -9046,6 +9085,20 @@ var init_mcp_credential_deps = __esm({
|
|
|
9046
9085
|
});
|
|
9047
9086
|
|
|
9048
9087
|
// src/sandbox-agent-session-proxy.ts
|
|
9088
|
+
function stripAnsiCodes(s) {
|
|
9089
|
+
return s.replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "");
|
|
9090
|
+
}
|
|
9091
|
+
async function* harvestHostErrorNotice(host, remoteSessionId) {
|
|
9092
|
+
let tail;
|
|
9093
|
+
try {
|
|
9094
|
+
tail = await host.output(remoteSessionId, MAX_OUTPUT_LINES);
|
|
9095
|
+
} catch {
|
|
9096
|
+
return;
|
|
9097
|
+
}
|
|
9098
|
+
const lines = tail.split(/\r?\n/).map((l) => stripAnsiCodes(l).trim()).filter((l) => l.length > 0 && HOST_ERROR_LINE_RE.test(l));
|
|
9099
|
+
if (lines.length === 0) return;
|
|
9100
|
+
yield { kind: "notice", text: lines.join("\n") };
|
|
9101
|
+
}
|
|
9049
9102
|
function extractPromptText(message) {
|
|
9050
9103
|
if (typeof message === "string") return message;
|
|
9051
9104
|
if (message && typeof message === "object" && "text" in message) {
|
|
@@ -9168,13 +9221,18 @@ function createSandboxAgentSessionProxy(opts) {
|
|
|
9168
9221
|
let lastPrompt;
|
|
9169
9222
|
let closed = false;
|
|
9170
9223
|
let transcriptCursor = 0;
|
|
9224
|
+
let turnsSent = 0;
|
|
9171
9225
|
return {
|
|
9172
9226
|
sessionId: remoteSessionId,
|
|
9173
9227
|
async *send(message) {
|
|
9174
9228
|
const prompt = extractPromptText(message);
|
|
9175
9229
|
lastPrompt = prompt;
|
|
9230
|
+
const isFirstTurn = turnsSent === 0;
|
|
9231
|
+
turnsSent++;
|
|
9176
9232
|
const since = await host.currentEventsCursor();
|
|
9177
|
-
|
|
9233
|
+
if (!(opts.promptCarriedInStart && isFirstTurn)) {
|
|
9234
|
+
await host.prompt(remoteSessionId, prompt);
|
|
9235
|
+
}
|
|
9178
9236
|
const controller = new AbortController();
|
|
9179
9237
|
let sseBody;
|
|
9180
9238
|
try {
|
|
@@ -9193,15 +9251,23 @@ function createSandboxAgentSessionProxy(opts) {
|
|
|
9193
9251
|
}
|
|
9194
9252
|
try {
|
|
9195
9253
|
let sawTurnEnd = false;
|
|
9254
|
+
let sawAssistantText = false;
|
|
9255
|
+
let sawToolCall = false;
|
|
9196
9256
|
for await (const record2 of readSseRecords(sseBody)) {
|
|
9197
9257
|
if (typeof record2.seq === "number") transcriptCursor = record2.seq;
|
|
9198
9258
|
const evt = recordToStreamEvent(record2);
|
|
9199
9259
|
if (!evt) continue;
|
|
9200
|
-
|
|
9260
|
+
if (evt.kind === "text-delta" && evt.text?.trim()) sawAssistantText = true;
|
|
9261
|
+
else if (evt.kind === "tool-call") sawToolCall = true;
|
|
9201
9262
|
if (evt.kind === "turn-end") {
|
|
9202
9263
|
sawTurnEnd = true;
|
|
9264
|
+
if (opts.surfaceHostTurnErrors && isFirstTurn && (evt.reason === "error" || !sawAssistantText && !sawToolCall)) {
|
|
9265
|
+
yield* harvestHostErrorNotice(host, remoteSessionId);
|
|
9266
|
+
}
|
|
9267
|
+
yield evt;
|
|
9203
9268
|
break;
|
|
9204
9269
|
}
|
|
9270
|
+
yield evt;
|
|
9205
9271
|
}
|
|
9206
9272
|
if (!sawTurnEnd) {
|
|
9207
9273
|
throw new Error(
|
|
@@ -9249,7 +9315,7 @@ function createSandboxAgentSessionProxy(opts) {
|
|
|
9249
9315
|
}
|
|
9250
9316
|
};
|
|
9251
9317
|
}
|
|
9252
|
-
var MAX_POLL_MS, MAX_OUTPUT_LINES, MAX_CONSECUTIVE_POLL_FAILURES, POLL_RETRY_DELAY_MS, STREAM_EVENT_RECORD_KINDS;
|
|
9318
|
+
var MAX_POLL_MS, MAX_OUTPUT_LINES, MAX_CONSECUTIVE_POLL_FAILURES, POLL_RETRY_DELAY_MS, HOST_ERROR_LINE_RE, STREAM_EVENT_RECORD_KINDS;
|
|
9253
9319
|
var init_sandbox_agent_session_proxy = __esm({
|
|
9254
9320
|
"src/sandbox-agent-session-proxy.ts"() {
|
|
9255
9321
|
init_sandbox_ledger();
|
|
@@ -9257,6 +9323,7 @@ var init_sandbox_agent_session_proxy = __esm({
|
|
|
9257
9323
|
MAX_OUTPUT_LINES = 500;
|
|
9258
9324
|
MAX_CONSECUTIVE_POLL_FAILURES = 6;
|
|
9259
9325
|
POLL_RETRY_DELAY_MS = 5e3;
|
|
9326
|
+
HOST_ERROR_LINE_RE = /\[(?:error|warning)\]|\berror\b|\bwarning\b|invalid model|model not found|unknown model|unsupported model/i;
|
|
9260
9327
|
STREAM_EVENT_RECORD_KINDS = /* @__PURE__ */ new Set([
|
|
9261
9328
|
"text-delta",
|
|
9262
9329
|
"thought",
|
|
@@ -10077,35 +10144,10 @@ function findWorktreeLabelCwdCollision(registry, excludeId, label, cwd) {
|
|
|
10077
10144
|
function profileMethodToAuthMode(method) {
|
|
10078
10145
|
return method === "oauth-bearer" ? "subscription" : "api-key";
|
|
10079
10146
|
}
|
|
10080
|
-
function directAuthMethods(descriptor, endpoint) {
|
|
10081
|
-
const methods = [];
|
|
10082
|
-
if (subscriptionSurfaceFor(descriptor?.authSubscription, endpoint) !== void 0) {
|
|
10083
|
-
methods.push("oauth-bearer");
|
|
10084
|
-
}
|
|
10085
|
-
if (descriptor?.provider || descriptor?.modelDerivedApiKey) methods.push("api-key");
|
|
10086
|
-
return methods;
|
|
10087
|
-
}
|
|
10088
10147
|
function subscriptionOauthMethodId(descriptor, provider) {
|
|
10089
10148
|
if (!Array.isArray(descriptor?.authSubscription) || !provider) return void 0;
|
|
10090
10149
|
return `${provider}-oauth`;
|
|
10091
10150
|
}
|
|
10092
|
-
function spawnEligibilityManifest(adapter, descriptor, route, model) {
|
|
10093
|
-
const directEndpoint = descriptor?.provider ?? (model ? descriptor?.modelProviders?.[model] : void 0) ?? (model && descriptor?.modelDerivedApiKey ? modelIdPrefixProvider(model) : void 0) ?? (model ? getModelProvider(model) : void 0);
|
|
10094
|
-
const routeId = route?.gateway ?? directEndpoint;
|
|
10095
|
-
if (!routeId) return void 0;
|
|
10096
|
-
const direct = directEndpoint !== void 0 && routeId === directEndpoint;
|
|
10097
|
-
return {
|
|
10098
|
-
manifest: {
|
|
10099
|
-
id: adapter,
|
|
10100
|
-
endpointByRoute: { [routeId]: direct ? directEndpoint : routeId },
|
|
10101
|
-
methodsByRoute: {
|
|
10102
|
-
[routeId]: direct ? directAuthMethods(descriptor, directEndpoint) : ["api-key"]
|
|
10103
|
-
}
|
|
10104
|
-
},
|
|
10105
|
-
routeId,
|
|
10106
|
-
direct
|
|
10107
|
-
};
|
|
10108
|
-
}
|
|
10109
10151
|
function resolveProfileAwareRoute(adapter, authDescriptor, profile, model) {
|
|
10110
10152
|
if (!model) return void 0;
|
|
10111
10153
|
const eligibleCandidates = serviceableModelRoutes(model).map((gateway) => spawnEligibilityManifest(adapter, authDescriptor, { gateway }, model)).filter(
|
|
@@ -10428,6 +10470,7 @@ async function spawnAgentSession(deps2, input) {
|
|
|
10428
10470
|
const {
|
|
10429
10471
|
registry,
|
|
10430
10472
|
resolveAgentAdapter,
|
|
10473
|
+
listAgentAdapters,
|
|
10431
10474
|
buildOrchestratorMcp,
|
|
10432
10475
|
daemonMcpUrl,
|
|
10433
10476
|
callerScope,
|
|
@@ -10914,10 +10957,16 @@ async function spawnAgentSession(deps2, input) {
|
|
|
10914
10957
|
if (input.sandbox === void 0 && !resolved) {
|
|
10915
10958
|
const profileHint = await authProfileAsAdapterHint(input.adapter, getAuthProfile);
|
|
10916
10959
|
const gatewayHint = profileHint ? void 0 : gatewayAsAdapterHint(input.adapter);
|
|
10960
|
+
let installedHint;
|
|
10961
|
+
if (!profileHint && !gatewayHint) {
|
|
10962
|
+
const installed = await listAgentAdapters?.().catch(() => void 0);
|
|
10963
|
+
installedHint = installed && installed.length > 0 ? `Installed adapters: ${installed.map((a) => a.slug).sort().join(", ")}.` : void 0;
|
|
10964
|
+
}
|
|
10965
|
+
const genericHint = `If it was working a moment ago, something may be mid-rebuild \u2014 wait and retry. ` + (installedHint ?? `If it has never been installed, run \`agentproto install ${input.adapter}\` first.`);
|
|
10917
10966
|
return {
|
|
10918
10967
|
ok: false,
|
|
10919
10968
|
code: "adapter_not_found",
|
|
10920
|
-
message: profileHint ? `agent_start: adapter "${input.adapter}" could not be resolved. ${profileHint}` : gatewayHint ? `agent_start: adapter "${input.adapter}" could not be resolved. ${gatewayHint}` : `agent_start: adapter "${input.adapter}" could not be resolved.
|
|
10969
|
+
message: profileHint ? `agent_start: adapter "${input.adapter}" could not be resolved. ${profileHint}` : gatewayHint ? `agent_start: adapter "${input.adapter}" could not be resolved. ${gatewayHint}` : `agent_start: adapter "${input.adapter}" could not be resolved. ${genericHint}`
|
|
10921
10970
|
};
|
|
10922
10971
|
}
|
|
10923
10972
|
if (resolveHostAuth && !resolved) {
|
|
@@ -11528,7 +11577,15 @@ ${asyncPrompt}`;
|
|
|
11528
11577
|
// (never the value) before the box boots.
|
|
11529
11578
|
...authSpec ? { authSpec } : {},
|
|
11530
11579
|
...descriptorRoute ? { route: descriptorRoute } : {},
|
|
11531
|
-
...input.appServe ? { appServe: input.appServe } : {}
|
|
11580
|
+
...input.appServe ? { appServe: input.appServe } : {},
|
|
11581
|
+
// F2 single-dial spawn — DEVICE ONLY: carry the composed initial
|
|
11582
|
+
// prompt INSIDE the inner `agent_start` (see `bootSandboxAgentSession`'s
|
|
11583
|
+
// `initialPrompt`) so the device bridge makes ONE dial, not two. The
|
|
11584
|
+
// controller still drives/records the first turn through the proxy
|
|
11585
|
+
// below (`registry.spawnAgent`'s `initialPrompt` / the `wait`
|
|
11586
|
+
// `sendPrompt`); `promptCarriedInStart` stops the proxy from
|
|
11587
|
+
// re-sending it. Non-device sandboxes are untouched (two-dial shape).
|
|
11588
|
+
...isDeviceSpawn && effectivePrompt !== void 0 ? { initialPrompt: effectivePrompt } : {}
|
|
11532
11589
|
});
|
|
11533
11590
|
if (!booted.ok) return booted;
|
|
11534
11591
|
agentSession = booted.agentSession;
|
|
@@ -11902,6 +11959,29 @@ function withSandboxInstallAdapters(spec) {
|
|
|
11902
11959
|
function looksLikeHostOnlyPath(p) {
|
|
11903
11960
|
return HOST_ONLY_PATH_PATTERNS.some((re) => re.test(p));
|
|
11904
11961
|
}
|
|
11962
|
+
function isDeviceTransportError(err) {
|
|
11963
|
+
return DEVICE_TRANSPORT_ERROR_RE.test(err instanceof Error ? err.message : String(err));
|
|
11964
|
+
}
|
|
11965
|
+
function deviceTargetOf(sandbox) {
|
|
11966
|
+
const slug = typeof sandbox === "string" ? sandbox : sandbox.provider;
|
|
11967
|
+
return slug.startsWith("device:") ? slug.slice("device:".length) : void 0;
|
|
11968
|
+
}
|
|
11969
|
+
async function startDeviceSessionWithRetry(host, args, target) {
|
|
11970
|
+
const attempts = 2;
|
|
11971
|
+
let lastErr;
|
|
11972
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
11973
|
+
try {
|
|
11974
|
+
return await host.start(args);
|
|
11975
|
+
} catch (err) {
|
|
11976
|
+
lastErr = err;
|
|
11977
|
+
if (!isDeviceTransportError(err)) throw err;
|
|
11978
|
+
if (attempt < attempts) {
|
|
11979
|
+
await new Promise((resolve42) => setTimeout(resolve42, DEVICE_SPAWN_RETRY_DELAY_MS));
|
|
11980
|
+
}
|
|
11981
|
+
}
|
|
11982
|
+
}
|
|
11983
|
+
throw new DeviceSpawnUnreachableError(target, attempts, lastErr);
|
|
11984
|
+
}
|
|
11905
11985
|
async function bootSandboxAgentSession(opts) {
|
|
11906
11986
|
const providerSlug = typeof opts.sandbox === "string" ? opts.sandbox : opts.sandbox.provider;
|
|
11907
11987
|
if (!opts.resolveSandboxProvider) {
|
|
@@ -12014,10 +12094,12 @@ async function bootSandboxAgentSession(opts) {
|
|
|
12014
12094
|
...lifecyclePolicy.pauseAfterIdleMs !== void 0 ? { expiresAt: new Date(Date.now() + lifecyclePolicy.pauseAfterIdleMs).toISOString() } : {}
|
|
12015
12095
|
});
|
|
12016
12096
|
const omitCwd = handle.omitCwdWhenImplicit === true && !opts.explicitCwd;
|
|
12097
|
+
const deviceTarget = deviceTargetOf(opts.sandbox);
|
|
12098
|
+
const carriedPrompt = deviceTarget !== void 0 && opts.initialPrompt !== void 0 ? typeof opts.initialPrompt === "string" ? [{ type: "text", text: opts.initialPrompt }] : opts.initialPrompt : void 0;
|
|
12017
12099
|
let remoteSessionId;
|
|
12018
12100
|
let resolvedCwd = boxCwd;
|
|
12019
12101
|
try {
|
|
12020
|
-
const
|
|
12102
|
+
const startArgs = {
|
|
12021
12103
|
adapter: opts.adapter,
|
|
12022
12104
|
...omitCwd ? {} : { cwd: boxCwd },
|
|
12023
12105
|
// Issue #1647 — DEVICE-BRIDGE ONLY: forward an EXPLICIT
|
|
@@ -12035,13 +12117,24 @@ async function bootSandboxAgentSession(opts) {
|
|
|
12035
12117
|
...opts.route ? { route: opts.route } : {},
|
|
12036
12118
|
...opts.effort ? { effort: opts.effort } : {},
|
|
12037
12119
|
...opts.label ? { label: opts.label } : {},
|
|
12038
|
-
...opts.auth ? { auth: opts.auth } : {}
|
|
12039
|
-
|
|
12120
|
+
...opts.auth ? { auth: opts.auth } : {},
|
|
12121
|
+
// F2 — the initial prompt rides the SAME dial as the spawn (device only).
|
|
12122
|
+
...carriedPrompt !== void 0 ? { prompt: carriedPrompt } : {}
|
|
12123
|
+
};
|
|
12124
|
+
const remoteDesc = deviceTarget !== void 0 ? await startDeviceSessionWithRetry(host, startArgs, deviceTarget) : await host.start(startArgs);
|
|
12040
12125
|
remoteSessionId = remoteDesc.id;
|
|
12041
12126
|
if (omitCwd && remoteDesc.cwd) resolvedCwd = remoteDesc.cwd;
|
|
12042
12127
|
} catch (err) {
|
|
12043
12128
|
await host.stop().catch(() => void 0);
|
|
12044
12129
|
recordSandboxState(host.sandboxId, "stopped");
|
|
12130
|
+
if (err instanceof DeviceSpawnUnreachableError) {
|
|
12131
|
+
return {
|
|
12132
|
+
ok: false,
|
|
12133
|
+
code: "device_spawn_unreachable",
|
|
12134
|
+
message: err.message,
|
|
12135
|
+
details: { target: err.target, attempts: err.attempts }
|
|
12136
|
+
};
|
|
12137
|
+
}
|
|
12045
12138
|
return {
|
|
12046
12139
|
ok: false,
|
|
12047
12140
|
code: "sandbox_proxy_failed",
|
|
@@ -12068,7 +12161,13 @@ async function bootSandboxAgentSession(opts) {
|
|
|
12068
12161
|
host,
|
|
12069
12162
|
remoteSessionId,
|
|
12070
12163
|
lifecyclePolicy,
|
|
12071
|
-
ledger: { sandboxId: host.sandboxId, provider: providerSlug }
|
|
12164
|
+
ledger: { sandboxId: host.sandboxId, provider: providerSlug },
|
|
12165
|
+
// Device spawns only: surface a first-turn failure's raw host line
|
|
12166
|
+
// (see `surfaceHostTurnErrors`).
|
|
12167
|
+
...deviceTarget !== void 0 ? { surfaceHostTurnErrors: true } : {},
|
|
12168
|
+
// F2 — when the first prompt rode the spawn dial, don't re-send it as a
|
|
12169
|
+
// second `agent_prompt` dial (see `promptCarriedInStart`).
|
|
12170
|
+
...carriedPrompt !== void 0 ? { promptCarriedInStart: true } : {}
|
|
12072
12171
|
}),
|
|
12073
12172
|
commandPreview: `sandbox:${providerSlug} \u2192 ${opts.adapter}`,
|
|
12074
12173
|
sandboxId: host.sandboxId,
|
|
@@ -12148,7 +12247,7 @@ async function resolveEffectiveCommandSandbox(requested, cwd) {
|
|
|
12148
12247
|
return void 0;
|
|
12149
12248
|
}
|
|
12150
12249
|
}
|
|
12151
|
-
var SPAWN_CLAIM_WINDOW_MS, IMPLICIT_SPAWN_CLAIM_WINDOW_MS, MAX_RESOLVED_CLAIMS, spawnClaimsByRegistry, HOST_ONLY_PATH_PATTERNS;
|
|
12250
|
+
var SPAWN_CLAIM_WINDOW_MS, IMPLICIT_SPAWN_CLAIM_WINDOW_MS, MAX_RESOLVED_CLAIMS, spawnClaimsByRegistry, HOST_ONLY_PATH_PATTERNS, DEVICE_TRANSPORT_ERROR_RE, DEVICE_SPAWN_RETRY_DELAY_MS, DeviceSpawnUnreachableError;
|
|
12152
12251
|
var init_session_spawn = __esm({
|
|
12153
12252
|
"src/session-spawn.ts"() {
|
|
12154
12253
|
init_process_stats();
|
|
@@ -12161,6 +12260,7 @@ var init_session_spawn = __esm({
|
|
|
12161
12260
|
init_bundles();
|
|
12162
12261
|
init_mcp_imports();
|
|
12163
12262
|
init_launch_config();
|
|
12263
|
+
init_eligibility_manifest();
|
|
12164
12264
|
init_claude_code_oauth_source();
|
|
12165
12265
|
init_providers_store();
|
|
12166
12266
|
init_catalog_models();
|
|
@@ -12197,6 +12297,21 @@ var init_session_spawn = __esm({
|
|
|
12197
12297
|
/^\/Users\//,
|
|
12198
12298
|
/^[A-Za-z]:[\\/]/
|
|
12199
12299
|
];
|
|
12300
|
+
DEVICE_TRANSPORT_ERROR_RE = /device_unreachable|transport closed|handshake timed out|did not send hello|closed the channel after handshake|socket hang up|other side closed|ECONNRESET|ECONNREFUSED|EPIPE|ETIMEDOUT|fetch failed/i;
|
|
12301
|
+
DEVICE_SPAWN_RETRY_DELAY_MS = 2e3;
|
|
12302
|
+
DeviceSpawnUnreachableError = class extends Error {
|
|
12303
|
+
target;
|
|
12304
|
+
attempts;
|
|
12305
|
+
constructor(target, attempts, cause) {
|
|
12306
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
12307
|
+
super(
|
|
12308
|
+
`agent_start: could not reach paired device "${target}" over its host channel after ${attempts} attempt${attempts === 1 ? "" : "s"} \u2014 the host channel may be flapping; retry in a few seconds and check \`agentproto devices status ${target}\`. Last error: ${detail}`
|
|
12309
|
+
);
|
|
12310
|
+
this.name = "DeviceSpawnUnreachableError";
|
|
12311
|
+
this.target = target;
|
|
12312
|
+
this.attempts = attempts;
|
|
12313
|
+
}
|
|
12314
|
+
};
|
|
12200
12315
|
}
|
|
12201
12316
|
});
|
|
12202
12317
|
function tryParseJson(value) {
|
|
@@ -13667,7 +13782,10 @@ function registerAgentTools(server, opts) {
|
|
|
13667
13782
|
...provisionWorktree ? { provisionWorktree } : {},
|
|
13668
13783
|
...resolveWorktreeIsolation ? { resolveWorktreeIsolation } : {},
|
|
13669
13784
|
...listCatalogModels ? { listCatalogModels } : {},
|
|
13670
|
-
...ensureLlmEndpointRunning ? { ensureLlmEndpointRunning } : {}
|
|
13785
|
+
...ensureLlmEndpointRunning ? { ensureLlmEndpointRunning } : {},
|
|
13786
|
+
// Lets the generic `adapter_not_found` error name the installed
|
|
13787
|
+
// adapters (session-spawn.ts) instead of only saying "install it".
|
|
13788
|
+
...listAgentAdapters ? { listAgentAdapters } : {}
|
|
13671
13789
|
},
|
|
13672
13790
|
{
|
|
13673
13791
|
...spawnInput,
|
|
@@ -13973,6 +14091,11 @@ function registerAgentTools(server, opts) {
|
|
|
13973
14091
|
// Surfaced so a caller can distinguish "idle" from "mid tool
|
|
13974
14092
|
// call" without guessing from empty output.
|
|
13975
14093
|
...desc.blockedOn ? { blockedOn: desc.blockedOn } : {},
|
|
14094
|
+
// Device-spawn first-turn failure (bad model id / host-side
|
|
14095
|
+
// adapter error) — see `SessionDescriptor.firstTurnFailed`.
|
|
14096
|
+
// The underlying host error line rides the `lines` tail above
|
|
14097
|
+
// (surfaced as a `notice` by the sandbox proxy).
|
|
14098
|
+
...desc.firstTurnFailed ? { firstTurnFailed: true } : {},
|
|
13976
14099
|
...activityFallback ? { activityFallback: true } : {},
|
|
13977
14100
|
// An ended session's derived outcome (what it produced) —
|
|
13978
14101
|
// the ring above is empty for a row reloaded after a restart.
|
|
@@ -14209,6 +14332,7 @@ function registerAgentTools(server, opts) {
|
|
|
14209
14332
|
...s.lastTurnErrorMessage !== void 0 ? { lastTurnErrorMessage: s.lastTurnErrorMessage } : {},
|
|
14210
14333
|
...s.lastTurnReason !== void 0 ? { lastTurnReason: s.lastTurnReason } : {},
|
|
14211
14334
|
...s.lastTurnEmpty !== void 0 ? { lastTurnEmpty: s.lastTurnEmpty } : {},
|
|
14335
|
+
...s.firstTurnFailed ? { firstTurnFailed: true } : {},
|
|
14212
14336
|
...s.stats !== void 0 ? { stats: s.stats } : {}
|
|
14213
14337
|
});
|
|
14214
14338
|
const agentSessionsListSchema = z.object({
|
|
@@ -16529,6 +16653,267 @@ var init_session_end_reason = __esm({
|
|
|
16529
16653
|
PROVIDER_LIMIT_ERROR_RE = /\bhit your (?:session|usage) limit\b/i;
|
|
16530
16654
|
}
|
|
16531
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
|
+
});
|
|
16532
16917
|
function isBackgroundToolCallArguments(args) {
|
|
16533
16918
|
return typeof args === "object" && args !== null && args.run_in_background === true;
|
|
16534
16919
|
}
|
|
@@ -16708,6 +17093,7 @@ function toSessionSummary(desc) {
|
|
|
16708
17093
|
blockedOn: desc.blockedOn,
|
|
16709
17094
|
stalledSinceMs: desc.stalledSinceMs,
|
|
16710
17095
|
pendingBgTasks: desc.pendingBgTasks,
|
|
17096
|
+
...desc.wrapupFlag ? { wrapupFlag: desc.wrapupFlag } : {},
|
|
16711
17097
|
backgroundTasks: desc.backgroundTasks,
|
|
16712
17098
|
lastTurnErroredAt: desc.lastTurnErroredAt,
|
|
16713
17099
|
...desc.lastError ? { lastError: desc.lastError.slice(0, 2e3) } : {},
|
|
@@ -16836,6 +17222,18 @@ function stampInterrupted(desc) {
|
|
|
16836
17222
|
delete desc.interrupted;
|
|
16837
17223
|
}
|
|
16838
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
|
+
}
|
|
16839
17237
|
function stampLiveModes(desc, rt) {
|
|
16840
17238
|
const modes = rt.agentSession?.availableModes;
|
|
16841
17239
|
if (modes && modes.length > 0) {
|
|
@@ -16847,6 +17245,9 @@ function stampLiveModes(desc, rt) {
|
|
|
16847
17245
|
function isResumable(desc) {
|
|
16848
17246
|
return desc.kind === "agent-cli" && !!desc.adapterSlug && !!desc.adapterSessionId && !!desc.cwd && !desc.archived;
|
|
16849
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
|
+
}
|
|
16850
17251
|
function canResume(desc) {
|
|
16851
17252
|
return isResumable(desc) && (desc.resumeAttempts ?? 0) < MAX_RESUME_ATTEMPTS;
|
|
16852
17253
|
}
|
|
@@ -16872,18 +17273,18 @@ function worktreeFields(cwd) {
|
|
|
16872
17273
|
...identity.mainRepoPath === void 0 ? {} : { mainRepoPath: identity.mainRepoPath }
|
|
16873
17274
|
};
|
|
16874
17275
|
}
|
|
16875
|
-
function
|
|
17276
|
+
function stripAnsiCodes2(s) {
|
|
16876
17277
|
return s.replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "");
|
|
16877
17278
|
}
|
|
16878
17279
|
function terminalOutputTail(rt, maxChars = 500) {
|
|
16879
17280
|
if (rt.recentBytes.length === 0) return "";
|
|
16880
17281
|
const text13 = Buffer.concat(rt.recentBytes, rt.recentBytesSize).toString("utf8");
|
|
16881
|
-
const plain =
|
|
17282
|
+
const plain = stripAnsiCodes2(text13).replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b[()][A-Za-z0-9]/g, "").replace(/\x1b[0-9A-Za-z=>]/g, "").replace(/[\x00-\x09\x0b-\x1f]/g, "").trim();
|
|
16882
17283
|
if (!plain) return "";
|
|
16883
17284
|
return plain.length > maxChars ? plain.slice(-maxChars) : plain;
|
|
16884
17285
|
}
|
|
16885
17286
|
function deriveHeuristicQuestion(recentLines) {
|
|
16886
|
-
const visible = recentLines.map(
|
|
17287
|
+
const visible = recentLines.map(stripAnsiCodes2).map((l) => l.trim()).filter((l) => l.length > 0 && !SYNTHETIC_LINE.test(l));
|
|
16887
17288
|
if (visible.length === 0) return void 0;
|
|
16888
17289
|
const options = [];
|
|
16889
17290
|
let i = visible.length - 1;
|
|
@@ -17085,6 +17486,7 @@ function createSessionsRegistry(opts) {
|
|
|
17085
17486
|
}
|
|
17086
17487
|
}
|
|
17087
17488
|
recordOutcome(rt);
|
|
17489
|
+
writeIndexNow(rt);
|
|
17088
17490
|
rt.linkProbeStop?.();
|
|
17089
17491
|
cancelPendingPermissionsForSession(rt);
|
|
17090
17492
|
if (runWorktreeAutoReclaim && rt.desc.worktreeAutoProvisioned && rt.desc.worktreePath) {
|
|
@@ -17319,6 +17721,53 @@ function createSessionsRegistry(opts) {
|
|
|
17319
17721
|
void persistSnapshot();
|
|
17320
17722
|
}, PERSIST_DEBOUNCE_MS2);
|
|
17321
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
|
+
};
|
|
17322
17771
|
const conversationLinkProbeMs = opts?.conversationLinkProbeMs ?? {
|
|
17323
17772
|
initialMs: 3e3,
|
|
17324
17773
|
intervalMs: 15e3
|
|
@@ -17481,7 +17930,7 @@ function createSessionsRegistry(opts) {
|
|
|
17481
17930
|
const strategySlug = rt.desc.adapterSlug ?? conversationTerminalSlugFor(rt.desc);
|
|
17482
17931
|
const strategy = strategySlug ? RESUME_STRATEGIES[strategySlug] : void 0;
|
|
17483
17932
|
if (!strategy?.outputHint) return;
|
|
17484
|
-
const plain =
|
|
17933
|
+
const plain = stripAnsiCodes2(line);
|
|
17485
17934
|
const m = plain.match(strategy.outputHint);
|
|
17486
17935
|
if (m && m[1]) {
|
|
17487
17936
|
rt.desc.resumeMetadata = {
|
|
@@ -17719,6 +18168,14 @@ function createSessionsRegistry(opts) {
|
|
|
17719
18168
|
}
|
|
17720
18169
|
break;
|
|
17721
18170
|
}
|
|
18171
|
+
case "notice": {
|
|
18172
|
+
if (evt.text) {
|
|
18173
|
+
for (const line of evt.text.split(/\r?\n/)) {
|
|
18174
|
+
if (line.trim()) appendLine(rt, `\x1B[2m[notice] ${line}\x1B[0m`, "stderr");
|
|
18175
|
+
}
|
|
18176
|
+
}
|
|
18177
|
+
break;
|
|
18178
|
+
}
|
|
17722
18179
|
case "plan": {
|
|
17723
18180
|
const entries = evt.entries ?? [];
|
|
17724
18181
|
const done = entries.filter((e) => e.status === "completed").length;
|
|
@@ -17913,7 +18370,12 @@ function createSessionsRegistry(opts) {
|
|
|
17913
18370
|
schedulePersist();
|
|
17914
18371
|
};
|
|
17915
18372
|
const maybeResumeAgent = async (rt, resumedFrom = "daemon-restart") => {
|
|
17916
|
-
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
|
+
}
|
|
17917
18379
|
if (!resumeAgent) return;
|
|
17918
18380
|
if (!isResumable(rt.desc)) return;
|
|
17919
18381
|
if (!canResume(rt.desc)) {
|
|
@@ -17959,7 +18421,7 @@ function createSessionsRegistry(opts) {
|
|
|
17959
18421
|
recordFailedResume(rt);
|
|
17960
18422
|
return;
|
|
17961
18423
|
}
|
|
17962
|
-
rt
|
|
18424
|
+
bindAgentSession(rt, fresh);
|
|
17963
18425
|
bindOutOfTurnEvents(rt);
|
|
17964
18426
|
stampCapabilities(rt);
|
|
17965
18427
|
rt.adapterSlug = adapterSlug;
|
|
@@ -18016,6 +18478,48 @@ function createSessionsRegistry(opts) {
|
|
|
18016
18478
|
rt.resumePromise = void 0;
|
|
18017
18479
|
}
|
|
18018
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
|
+
};
|
|
18019
18523
|
const buildUsageSnapshot = (rt) => deriveSessionUsage({
|
|
18020
18524
|
...rt.desc.model !== void 0 ? { model: rt.desc.model } : {},
|
|
18021
18525
|
...rt.adapterReportedCost && rt.desc.costUsd !== void 0 ? { adapterCostUsd: rt.desc.costUsd } : {},
|
|
@@ -18475,6 +18979,7 @@ ${message}`;
|
|
|
18475
18979
|
...messageTurn ? { messages: turnOpts.messages } : {}
|
|
18476
18980
|
} : void 0
|
|
18477
18981
|
);
|
|
18982
|
+
rt.lastUserPrompt = { ts: (/* @__PURE__ */ new Date()).toISOString(), text: promptTextForIndex(message, turnOpts?.system) };
|
|
18478
18983
|
const wrapped = typeof message === "string" ? { type: "text", text: message } : message;
|
|
18479
18984
|
const switchCandidate = typeof message === "string" ? parseModelSwitchCommand(message) : void 0;
|
|
18480
18985
|
let switchLearned = false;
|
|
@@ -18638,6 +19143,10 @@ ${message}`;
|
|
|
18638
19143
|
} else if (rt.desc.lastTurnReason !== void 0) {
|
|
18639
19144
|
delete rt.desc.lastTurnReason;
|
|
18640
19145
|
}
|
|
19146
|
+
if (rt.desc.remote === true && rt.desc.sandboxProvider?.startsWith("device:") && rt.desc.turnsCompleted === 1 && (emptyTurn || turnEndReason === "error")) {
|
|
19147
|
+
rt.desc.firstTurnFailed = true;
|
|
19148
|
+
schedulePersist();
|
|
19149
|
+
}
|
|
18641
19150
|
const nextActivity = regenerateActivitySummary(rt.desc, rt.recentLines, Date.now());
|
|
18642
19151
|
if (nextActivity) {
|
|
18643
19152
|
rt.desc.activitySummary = nextActivity;
|
|
@@ -18692,6 +19201,10 @@ ${message}`;
|
|
|
18692
19201
|
} else if (rt.desc.lastTurnReason !== void 0) {
|
|
18693
19202
|
delete rt.desc.lastTurnReason;
|
|
18694
19203
|
}
|
|
19204
|
+
if (rt.desc.remote === true && rt.desc.sandboxProvider?.startsWith("device:") && rt.desc.turnsCompleted === 1 && turnEndReason === "error") {
|
|
19205
|
+
rt.desc.firstTurnFailed = true;
|
|
19206
|
+
schedulePersist();
|
|
19207
|
+
}
|
|
18695
19208
|
if (sessionEvents) {
|
|
18696
19209
|
sessionEvents.emit({
|
|
18697
19210
|
type: "session:turn-end",
|
|
@@ -18704,6 +19217,7 @@ ${message}`;
|
|
|
18704
19217
|
});
|
|
18705
19218
|
}
|
|
18706
19219
|
}
|
|
19220
|
+
scheduleIndexWrite(rt);
|
|
18707
19221
|
if (!interruptedBy) dispatchQueuedPrompt(rt);
|
|
18708
19222
|
else if (interruptedBy.deliverQueueId) {
|
|
18709
19223
|
dispatchQueuedPrompt(rt, interruptedBy.deliverQueueId);
|
|
@@ -18998,6 +19512,10 @@ ${message}`;
|
|
|
18998
19512
|
};
|
|
18999
19513
|
const registry = {
|
|
19000
19514
|
bootId,
|
|
19515
|
+
transcriptBaseDir,
|
|
19516
|
+
flushSessionIndexes() {
|
|
19517
|
+
flushDirtyIndexes();
|
|
19518
|
+
},
|
|
19001
19519
|
recordAutoContinue(id) {
|
|
19002
19520
|
const rt = sessions.get(id);
|
|
19003
19521
|
if (!rt) return;
|
|
@@ -19074,6 +19592,7 @@ ${message}`;
|
|
|
19074
19592
|
emitExited(rt);
|
|
19075
19593
|
});
|
|
19076
19594
|
schedulePersist();
|
|
19595
|
+
writeIndexNow(rt);
|
|
19077
19596
|
return desc;
|
|
19078
19597
|
},
|
|
19079
19598
|
register(input) {
|
|
@@ -19123,6 +19642,7 @@ ${message}`;
|
|
|
19123
19642
|
emitExited(rt);
|
|
19124
19643
|
});
|
|
19125
19644
|
schedulePersist();
|
|
19645
|
+
writeIndexNow(rt);
|
|
19126
19646
|
return desc;
|
|
19127
19647
|
},
|
|
19128
19648
|
spawnAgent(input) {
|
|
@@ -19224,7 +19744,6 @@ ${message}`;
|
|
|
19224
19744
|
}
|
|
19225
19745
|
const rt = {
|
|
19226
19746
|
desc,
|
|
19227
|
-
agentSession: input.agentSession,
|
|
19228
19747
|
adapterSlug: input.adapterSlug,
|
|
19229
19748
|
recentLines: [],
|
|
19230
19749
|
recentBytes: [],
|
|
@@ -19241,6 +19760,7 @@ ${message}`;
|
|
|
19241
19760
|
rt.emitter.setMaxListeners(50);
|
|
19242
19761
|
sessions.set(id, rt);
|
|
19243
19762
|
linkContinuedTo(input.resumedFrom, id);
|
|
19763
|
+
bindAgentSession(rt, input.agentSession);
|
|
19244
19764
|
bindOutOfTurnEvents(rt);
|
|
19245
19765
|
stampCapabilities(rt);
|
|
19246
19766
|
armUsageRefresh(rt);
|
|
@@ -19258,6 +19778,7 @@ ${message}`;
|
|
|
19258
19778
|
"stdout"
|
|
19259
19779
|
);
|
|
19260
19780
|
schedulePersist();
|
|
19781
|
+
writeIndexNow(rt);
|
|
19261
19782
|
recordConversationLink(rt);
|
|
19262
19783
|
desc.eventsPath = sessionEventsPath(desc.id, transcriptBaseDir);
|
|
19263
19784
|
if (input.initialPrompt) {
|
|
@@ -19376,6 +19897,7 @@ ${message}`;
|
|
|
19376
19897
|
"stdout"
|
|
19377
19898
|
);
|
|
19378
19899
|
schedulePersist();
|
|
19900
|
+
writeIndexNow(rt);
|
|
19379
19901
|
desc.eventsPath = sessionEventsPath(desc.id, transcriptBaseDir);
|
|
19380
19902
|
return desc;
|
|
19381
19903
|
},
|
|
@@ -19431,7 +19953,7 @@ ${message}`;
|
|
|
19431
19953
|
emitExited(rt);
|
|
19432
19954
|
return;
|
|
19433
19955
|
}
|
|
19434
|
-
rt
|
|
19956
|
+
bindAgentSession(rt, outcome.agentSession);
|
|
19435
19957
|
bindOutOfTurnEvents(rt);
|
|
19436
19958
|
stampCapabilities(rt);
|
|
19437
19959
|
rt.readUsage = outcome.readUsage;
|
|
@@ -19453,6 +19975,7 @@ ${message}`;
|
|
|
19453
19975
|
"stdout"
|
|
19454
19976
|
);
|
|
19455
19977
|
schedulePersist();
|
|
19978
|
+
writeIndexNow(rt);
|
|
19456
19979
|
recordConversationLink(rt);
|
|
19457
19980
|
if (outcome.initialPrompt) {
|
|
19458
19981
|
void runAgentTurn(
|
|
@@ -19622,6 +20145,7 @@ ${message}`;
|
|
|
19622
20145
|
emitExited(rt);
|
|
19623
20146
|
});
|
|
19624
20147
|
schedulePersist();
|
|
20148
|
+
writeIndexNow(rt);
|
|
19625
20149
|
return desc;
|
|
19626
20150
|
},
|
|
19627
20151
|
recordCommand(input) {
|
|
@@ -20246,6 +20770,7 @@ ${message}`;
|
|
|
20246
20770
|
stampCurrentStatus(rt);
|
|
20247
20771
|
stampWatchers(desc);
|
|
20248
20772
|
stampLiveModes(desc, rt);
|
|
20773
|
+
stampAdapterConnected(desc, rt);
|
|
20249
20774
|
desc.childrenBusy = childrenBusy.get(desc.id) ?? 0;
|
|
20250
20775
|
desc.queuedPrompts = desc.promptQueue?.length ?? 0;
|
|
20251
20776
|
return desc;
|
|
@@ -20303,6 +20828,7 @@ ${message}`;
|
|
|
20303
20828
|
stampCurrentStatus(rt);
|
|
20304
20829
|
stampWatchers(desc);
|
|
20305
20830
|
stampLiveModes(desc, rt);
|
|
20831
|
+
stampAdapterConnected(desc, rt);
|
|
20306
20832
|
desc.childrenBusy = childrenBusyCounts().get(desc.id) ?? 0;
|
|
20307
20833
|
desc.queuedPrompts = desc.promptQueue?.length ?? 0;
|
|
20308
20834
|
}
|
|
@@ -20558,34 +21084,8 @@ ${message}`;
|
|
|
20558
21084
|
emitExited(rt);
|
|
20559
21085
|
return true;
|
|
20560
21086
|
},
|
|
20561
|
-
markCrashed(id) {
|
|
20562
|
-
|
|
20563
|
-
if (!rt) return false;
|
|
20564
|
-
if (rt.desc.kind !== "agent-cli" || rt.desc.status !== "running") {
|
|
20565
|
-
return false;
|
|
20566
|
-
}
|
|
20567
|
-
const pid = rt.desc.pid;
|
|
20568
|
-
const providerLimitMessage = isProviderLimitError(rt.lastErrorMessage) ? rt.lastErrorMessage : void 0;
|
|
20569
|
-
rt.desc.status = "error";
|
|
20570
|
-
rt.desc.endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20571
|
-
rt.desc.endedReason = providerLimitMessage ? "provider-limit" : "crashed";
|
|
20572
|
-
rt.desc.crashedAt = rt.desc.endedAt;
|
|
20573
|
-
rt.desc.lastError = providerLimitMessage ? `provider usage limit hit: ${providerLimitMessage}` : `adapter process gone (pid ${pid}) \u2014 session crashed`;
|
|
20574
|
-
if (rt.agentSession) {
|
|
20575
|
-
releaseOutOfTurnEvents(rt);
|
|
20576
|
-
delete rt.desc.backgroundTasks;
|
|
20577
|
-
recordExitUsageSnapshot(rt);
|
|
20578
|
-
void rt.agentSession.close().catch(() => void 0);
|
|
20579
|
-
void transcriptWriter.close(rt.desc.id);
|
|
20580
|
-
tracedSessions.delete(rt.desc.id);
|
|
20581
|
-
rt.agentSession = void 0;
|
|
20582
|
-
}
|
|
20583
|
-
schedulePersist();
|
|
20584
|
-
const banner = providerLimitMessage ? `[provider-limit] ${providerLimitMessage}` : `[crashed] adapter process gone (pid ${pid}) \u2014 session crashed`;
|
|
20585
|
-
appendLine(rt, banner, "stderr");
|
|
20586
|
-
transcriptWriter.recordEvent(rt.desc.id, { kind: "notice", text: banner });
|
|
20587
|
-
emitExited(rt);
|
|
20588
|
-
return true;
|
|
21087
|
+
markCrashed(id, reason = "process-gone") {
|
|
21088
|
+
return markCrashedInternal(id, reason);
|
|
20589
21089
|
},
|
|
20590
21090
|
markStalled(id, stalledSinceMs) {
|
|
20591
21091
|
const rt = sessions.get(id);
|
|
@@ -20751,6 +21251,7 @@ ${message}`;
|
|
|
20751
21251
|
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
20752
21252
|
});
|
|
20753
21253
|
stampReadLiveness(rt.desc);
|
|
21254
|
+
writeIndexNow(rt);
|
|
20754
21255
|
return rt.desc;
|
|
20755
21256
|
},
|
|
20756
21257
|
setKeepAlive(id, keepAlive) {
|
|
@@ -20874,6 +21375,7 @@ ${message}`;
|
|
|
20874
21375
|
if (shutdownDone) return;
|
|
20875
21376
|
shutdownDone = true;
|
|
20876
21377
|
if (persistTimer) clearTimeout(persistTimer);
|
|
21378
|
+
flushDirtyIndexes();
|
|
20877
21379
|
if (persist) {
|
|
20878
21380
|
try {
|
|
20879
21381
|
process.off("exit", onProcessExit);
|
|
@@ -21026,6 +21528,13 @@ function loadHistorySnapshot(persistPath, sessions, sessionEvents, transcriptBas
|
|
|
21026
21528
|
}
|
|
21027
21529
|
}
|
|
21028
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
|
+
}
|
|
21029
21538
|
function quoteArg(arg) {
|
|
21030
21539
|
if (arg === "") return '""';
|
|
21031
21540
|
if (/^[a-zA-Z0-9._/=:@,+-]+$/.test(arg)) return arg;
|
|
@@ -21065,6 +21574,7 @@ var init_sessions = __esm({
|
|
|
21065
21574
|
init_session_continue_fresh();
|
|
21066
21575
|
init_session_outcome();
|
|
21067
21576
|
init_session_end_reason();
|
|
21577
|
+
init_session_index();
|
|
21068
21578
|
init_session_message();
|
|
21069
21579
|
SESSIONS_FILE_PATH = () => resolve(homedir(), ".agentproto", "sessions.json");
|
|
21070
21580
|
SESSION_ID_ENV = "AGENTPROTO_SESSION_ID";
|
|
@@ -22812,7 +23322,7 @@ init_resume_strategies();
|
|
|
22812
23322
|
init_spawn_defaults();
|
|
22813
23323
|
init_launch_config();
|
|
22814
23324
|
init_resume_context_digest();
|
|
22815
|
-
|
|
23325
|
+
init_eligibility_manifest();
|
|
22816
23326
|
init_providers_store();
|
|
22817
23327
|
init_catalog_models();
|
|
22818
23328
|
init_config();
|
|
@@ -23310,7 +23820,7 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
23310
23820
|
desc = await spawnWithResume(strategy.resumeSessionId);
|
|
23311
23821
|
} catch (err) {
|
|
23312
23822
|
const msg = err instanceof Error ? err.message : String(err);
|
|
23313
|
-
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))) {
|
|
23314
23824
|
desc = await spawnWithResume(void 0);
|
|
23315
23825
|
resumeFallback = true;
|
|
23316
23826
|
} else {
|
|
@@ -23601,7 +24111,7 @@ var EMPTY_SKILLS = {
|
|
|
23601
24111
|
byHarness: [],
|
|
23602
24112
|
defaults: { global: [], byAdapter: {} }
|
|
23603
24113
|
};
|
|
23604
|
-
function
|
|
24114
|
+
function isRecord6(value) {
|
|
23605
24115
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23606
24116
|
}
|
|
23607
24117
|
function classifyDaemonMount(adapter) {
|
|
@@ -23754,15 +24264,15 @@ var slugToCamel2 = (slug) => slug.replace(/-([a-z0-9])/g, (_m, c) => c.toUpperCa
|
|
|
23754
24264
|
async function readAdapterManifest(adapter) {
|
|
23755
24265
|
try {
|
|
23756
24266
|
const mod = await import(adapter.packageName);
|
|
23757
|
-
if (!
|
|
24267
|
+
if (!isRecord6(mod)) return void 0;
|
|
23758
24268
|
const candidate = mod[slugToCamel2(adapter.slug)] ?? mod.default ?? mod.handle;
|
|
23759
|
-
return
|
|
24269
|
+
return isRecord6(candidate) ? candidate : void 0;
|
|
23760
24270
|
} catch {
|
|
23761
24271
|
return void 0;
|
|
23762
24272
|
}
|
|
23763
24273
|
}
|
|
23764
24274
|
function asSkillsTarget(value) {
|
|
23765
|
-
if (!
|
|
24275
|
+
if (!isRecord6(value) || typeof value.format !== "string") return void 0;
|
|
23766
24276
|
const out = { format: value.format };
|
|
23767
24277
|
if (typeof value.dir === "string") out.dir = value.dir;
|
|
23768
24278
|
if (typeof value.outDir === "string") out.outDir = value.outDir;
|
|
@@ -23779,10 +24289,10 @@ async function listNativeSkills(adapter) {
|
|
|
23779
24289
|
}
|
|
23780
24290
|
async function buildHarnessEntry(adapter) {
|
|
23781
24291
|
const manifest = await readAdapterManifest(adapter);
|
|
23782
|
-
const metadata = manifest &&
|
|
24292
|
+
const metadata = manifest && isRecord6(manifest.metadata) ? manifest.metadata : void 0;
|
|
23783
24293
|
const target = asSkillsTarget(metadata?.skills);
|
|
23784
24294
|
const options = manifest && Array.isArray(manifest.options) ? manifest.options : [];
|
|
23785
|
-
const spawnOption = options.some((o) =>
|
|
24295
|
+
const spawnOption = options.some((o) => isRecord6(o) && o.id === "skills");
|
|
23786
24296
|
const [installed, native] = await Promise.all([
|
|
23787
24297
|
target ? listInstalledForTarget(target) : Promise.resolve([]),
|
|
23788
24298
|
listNativeSkills(adapter)
|
|
@@ -24168,6 +24678,8 @@ async function processTreeRss(rootPids, exec = defaultPsExecutor) {
|
|
|
24168
24678
|
}
|
|
24169
24679
|
|
|
24170
24680
|
// src/session-tools.ts
|
|
24681
|
+
init_transcript_writer();
|
|
24682
|
+
init_session_index();
|
|
24171
24683
|
init_process_stats();
|
|
24172
24684
|
|
|
24173
24685
|
// src/host-load.ts
|
|
@@ -25961,6 +26473,7 @@ var publicSessionDescriptor = (session) => {
|
|
|
25961
26473
|
var compactSessionItem = (s) => ({
|
|
25962
26474
|
id: s.id,
|
|
25963
26475
|
kind: s.kind,
|
|
26476
|
+
...s.origin ? { origin: s.origin } : {},
|
|
25964
26477
|
name: s.name,
|
|
25965
26478
|
label: s.label,
|
|
25966
26479
|
status: s.status,
|
|
@@ -25995,6 +26508,7 @@ var compactSessionItem = (s) => ({
|
|
|
25995
26508
|
...s.lastTurnErrorMessage !== void 0 ? { lastTurnErrorMessage: s.lastTurnErrorMessage } : {},
|
|
25996
26509
|
...s.lastTurnReason !== void 0 ? { lastTurnReason: s.lastTurnReason } : {},
|
|
25997
26510
|
...s.lastTurnEmpty !== void 0 ? { lastTurnEmpty: s.lastTurnEmpty } : {},
|
|
26511
|
+
...s.firstTurnFailed ? { firstTurnFailed: true } : {},
|
|
25998
26512
|
...s.interrupted ? { interrupted: true } : {},
|
|
25999
26513
|
...s.rssBytes !== void 0 ? { rssBytes: s.rssBytes } : {},
|
|
26000
26514
|
...s.stats !== void 0 ? { stats: s.stats } : {},
|
|
@@ -26248,6 +26762,66 @@ function registerSessionTools(rawServer, opts) {
|
|
|
26248
26762
|
})
|
|
26249
26763
|
]
|
|
26250
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
|
+
});
|
|
26251
26825
|
registerBuiltinTool(server, {
|
|
26252
26826
|
id: "session_stats",
|
|
26253
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).',
|
|
@@ -28495,8 +29069,8 @@ function registerSessionTools(rawServer, opts) {
|
|
|
28495
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.',
|
|
28496
29070
|
{
|
|
28497
29071
|
sessionIds: z.array(z.string().min(1)).min(1).describe("Session ids or names, from `session_wrapup_plan`."),
|
|
28498
|
-
verdict: z.enum(["done", "abandoned", "blocked", "needs-input"]).describe(
|
|
28499
|
-
'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.'
|
|
28500
29074
|
),
|
|
28501
29075
|
note: z.string().optional().describe("Free-text note recorded on the outcome or the flag."),
|
|
28502
29076
|
judgedBy: z.string().optional().describe(
|
|
@@ -28571,6 +29145,70 @@ function registerSessionTools(rawServer, opts) {
|
|
|
28571
29145
|
}
|
|
28572
29146
|
}
|
|
28573
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
|
+
);
|
|
28574
29212
|
server.tool(
|
|
28575
29213
|
"session_evidence",
|
|
28576
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.",
|
|
@@ -31672,12 +32310,18 @@ function registerMcpApps(server, apps) {
|
|
|
31672
32310
|
uri: resourceUri,
|
|
31673
32311
|
html,
|
|
31674
32312
|
description: app.description,
|
|
31675
|
-
csp: app.csp
|
|
32313
|
+
csp: app.csp,
|
|
32314
|
+
...app.openai?.resource !== void 0 ? {
|
|
32315
|
+
// Namespaced under `openai/ui` per §3.2 — a sibling of the
|
|
32316
|
+
// canonical `_meta.ui`, never an overwrite of it.
|
|
32317
|
+
meta: { "openai/ui": JSON.parse(JSON.stringify(app.openai.resource)) }
|
|
32318
|
+
} : {}
|
|
31676
32319
|
});
|
|
31677
32320
|
server.registerTool(
|
|
31678
32321
|
app.id,
|
|
31679
32322
|
{
|
|
31680
32323
|
description: app.description ?? app.title,
|
|
32324
|
+
...app.openai !== void 0 ? { title: app.title } : {},
|
|
31681
32325
|
inputSchema: app.inputSchema.shape,
|
|
31682
32326
|
annotations: {
|
|
31683
32327
|
readOnlyHint: true,
|
|
@@ -31687,7 +32331,13 @@ function registerMcpApps(server, apps) {
|
|
|
31687
32331
|
ui: {
|
|
31688
32332
|
resourceUri,
|
|
31689
32333
|
visibility: ["model", "app"]
|
|
31690
|
-
}
|
|
32334
|
+
},
|
|
32335
|
+
...app.openai?.tool?.entrypoints !== void 0 || app.openai?.icons !== void 0 ? {
|
|
32336
|
+
"openai/ui": {
|
|
32337
|
+
...app.openai.tool?.entrypoints !== void 0 ? { entrypoints: JSON.parse(JSON.stringify(app.openai.tool.entrypoints)) } : {},
|
|
32338
|
+
...app.openai.icons !== void 0 ? { icons: JSON.parse(JSON.stringify(app.openai.icons)) } : {}
|
|
32339
|
+
}
|
|
32340
|
+
} : {}
|
|
31691
32341
|
}
|
|
31692
32342
|
},
|
|
31693
32343
|
async (args) => {
|
|
@@ -34786,11 +35436,11 @@ function verifySignatureV2(secret, headers, body, nowMs, skewMs = SIGNATURE_V2_S
|
|
|
34786
35436
|
if (a.length !== b.length || !timingSafeEqual(a, b)) return { ok: false, reason: "signature_mismatch" };
|
|
34787
35437
|
return { ok: true, timestampSec };
|
|
34788
35438
|
}
|
|
34789
|
-
var
|
|
35439
|
+
var isRecord7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
34790
35440
|
function toSentinelEvent(raw, seq) {
|
|
34791
|
-
if (!
|
|
35441
|
+
if (!isRecord7(raw)) return null;
|
|
34792
35442
|
const { id, source, type, subject, time, data, summary, subjects, terminal, consumerref } = raw;
|
|
34793
|
-
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") {
|
|
34794
35444
|
return null;
|
|
34795
35445
|
}
|
|
34796
35446
|
const envSeq = typeof raw.seq === "number" ? raw.seq : seq;
|
|
@@ -34896,7 +35546,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
34896
35546
|
json3 = void 0;
|
|
34897
35547
|
}
|
|
34898
35548
|
if (!res.ok) {
|
|
34899
|
-
const detail =
|
|
35549
|
+
const detail = isRecord7(json3) && typeof json3.error === "string" ? json3.error : text13.slice(0, 200);
|
|
34900
35550
|
throw new AgentpushHttpError(res.status, `agentpush ${method} ${path} \u2192 HTTP ${res.status}${detail ? `: ${detail}` : ""}`);
|
|
34901
35551
|
}
|
|
34902
35552
|
return json3;
|
|
@@ -34982,7 +35632,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
34982
35632
|
...push ? { callback_url: callbackUrl2(delivery.callbackUrl, hookKey), callback_secret: callbackSecret } : {}
|
|
34983
35633
|
}
|
|
34984
35634
|
});
|
|
34985
|
-
const id =
|
|
35635
|
+
const id = isRecord7(json3) && isRecord7(json3.subscription) ? json3.subscription.id : void 0;
|
|
34986
35636
|
if (typeof id !== "string" || id === "") throw new Error("agentpush: create returned no subscription id");
|
|
34987
35637
|
return {
|
|
34988
35638
|
provider: AGENTPUSH_SLUG,
|
|
@@ -35009,7 +35659,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35009
35659
|
let sub;
|
|
35010
35660
|
try {
|
|
35011
35661
|
const json3 = await api("GET", subPath(handle));
|
|
35012
|
-
sub =
|
|
35662
|
+
sub = isRecord7(json3) && isRecord7(json3.subscription) ? json3.subscription : void 0;
|
|
35013
35663
|
} catch (err) {
|
|
35014
35664
|
if (isHttp(err, 404)) {
|
|
35015
35665
|
throw new Error(`agentpush subscription ${handle.remoteId} no longer exists \u2014 re-create the sentinel`);
|
|
@@ -35040,7 +35690,7 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35040
35690
|
async status(handle) {
|
|
35041
35691
|
try {
|
|
35042
35692
|
const json3 = await api("GET", subPath(handle));
|
|
35043
|
-
const sub =
|
|
35693
|
+
const sub = isRecord7(json3) && isRecord7(json3.subscription) ? json3.subscription : void 0;
|
|
35044
35694
|
const status = sub && typeof sub.status === "string" ? sub.status : "unknown";
|
|
35045
35695
|
if (status === "active") return { ok: true };
|
|
35046
35696
|
return { ok: false, detail: `the agentpush subscription is ${status}` };
|
|
@@ -35052,12 +35702,12 @@ function agentpushSentinelProvider(opts = {}) {
|
|
|
35052
35702
|
const after = handle.cursor ?? "0";
|
|
35053
35703
|
if (stateOf(handle).mode === "push") return { events: [], cursor: after };
|
|
35054
35704
|
const json3 = await api("GET", `${subPath(handle)}/events`, { query: { after, limit: Math.max(1, Math.min(limit, 1e3)) } });
|
|
35055
|
-
const items =
|
|
35705
|
+
const items = isRecord7(json3) && Array.isArray(json3.items) ? json3.items : [];
|
|
35056
35706
|
const events = [];
|
|
35057
35707
|
let cursor = Number(after);
|
|
35058
35708
|
if (!Number.isFinite(cursor)) cursor = 0;
|
|
35059
35709
|
for (const item of items) {
|
|
35060
|
-
if (!
|
|
35710
|
+
if (!isRecord7(item)) continue;
|
|
35061
35711
|
const seq = typeof item.seq === "number" ? item.seq : void 0;
|
|
35062
35712
|
if (seq !== void 0 && seq > cursor) cursor = seq;
|
|
35063
35713
|
const event = toSentinelEvent(item.envelope, seq);
|
|
@@ -37433,11 +38083,11 @@ function sanitize(cacheKey) {
|
|
|
37433
38083
|
const cleaned = cacheKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
37434
38084
|
return cleaned.length > 0 ? cleaned : "default";
|
|
37435
38085
|
}
|
|
37436
|
-
function
|
|
38086
|
+
function isRecord8(v) {
|
|
37437
38087
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
37438
38088
|
}
|
|
37439
38089
|
function isEntry2(v) {
|
|
37440
|
-
return
|
|
38090
|
+
return isRecord8(v) && typeof v.resolvedInputHash === "string" && "output" in v;
|
|
37441
38091
|
}
|
|
37442
38092
|
function createFileStepCache(cacheKey, opts) {
|
|
37443
38093
|
const dir = opts?.dir ?? DEFAULT_CACHE_DIR();
|
|
@@ -37450,7 +38100,7 @@ function createFileStepCache(cacheKey, opts) {
|
|
|
37450
38100
|
} catch {
|
|
37451
38101
|
return {};
|
|
37452
38102
|
}
|
|
37453
|
-
if (!
|
|
38103
|
+
if (!isRecord8(parsed)) return {};
|
|
37454
38104
|
const out = {};
|
|
37455
38105
|
for (const [k, v] of Object.entries(parsed)) if (isEntry2(v)) out[k] = v;
|
|
37456
38106
|
return out;
|
|
@@ -43534,7 +44184,15 @@ async function performInstall(dir, appRegistry, listRegisteredToolIds, resolveAg
|
|
|
43534
44184
|
...handle.ui?.description !== void 0 ? { description: handle.ui.description } : {},
|
|
43535
44185
|
...handle.ui?.tools !== void 0 ? { tools: handle.ui.tools } : {},
|
|
43536
44186
|
...handle.ui?.csp !== void 0 ? { csp: handle.ui.csp } : {},
|
|
43537
|
-
...handle.ui?.build !== void 0 ? { build: handle.ui.build } : {}
|
|
44187
|
+
...handle.ui?.build !== void 0 ? { build: handle.ui.build } : {},
|
|
44188
|
+
// OpenAI MCP-extensions carrier (plan W-B): the normalized,
|
|
44189
|
+
// app-kit-validated `ui.extensions` block persists verbatim on the
|
|
44190
|
+
// installed record — `makeInstalledAppUiApps` (W-C) is the only
|
|
44191
|
+
// consumer. Frozen already by app-kit; spread-cloned here so the
|
|
44192
|
+
// persisted shape stays a plain JSON-safe object (apps.json is
|
|
44193
|
+
// what actually freezes it). Apps without the block install
|
|
44194
|
+
// identically to before (plan I1).
|
|
44195
|
+
...handle.ui?.extensions !== void 0 ? { extensions: handle.ui.extensions } : {}
|
|
43538
44196
|
} : void 0;
|
|
43539
44197
|
const artifact = refs.artifact ? {
|
|
43540
44198
|
path: refs.artifact.path,
|
|
@@ -44576,12 +45234,12 @@ async function readBody2(req) {
|
|
|
44576
45234
|
}
|
|
44577
45235
|
return { raw: Buffer.concat(chunks).toString("utf8") };
|
|
44578
45236
|
}
|
|
44579
|
-
var
|
|
45237
|
+
var isRecord9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
44580
45238
|
function parseParts(raw) {
|
|
44581
45239
|
if (!Array.isArray(raw)) throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "message.parts must be an array");
|
|
44582
45240
|
const parts = [];
|
|
44583
45241
|
for (const p of raw) {
|
|
44584
|
-
if (!
|
|
45242
|
+
if (!isRecord9(p)) throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "each message part must be an object");
|
|
44585
45243
|
if ("text" in p) {
|
|
44586
45244
|
if (typeof p.text !== "string") throw new RpcFailure(JSON_RPC_ERROR.invalidParams, "part.text must be a string");
|
|
44587
45245
|
parts.push({ text: p.text });
|
|
@@ -44614,13 +45272,13 @@ async function handleA2aTaskRequest(req, res, path, deps2) {
|
|
|
44614
45272
|
send(res, 200, { jsonrpc: "2.0", id: null, error: { code: JSON_RPC_ERROR.parse, message: "parse error: body is not valid JSON" } });
|
|
44615
45273
|
return true;
|
|
44616
45274
|
}
|
|
44617
|
-
if (!
|
|
45275
|
+
if (!isRecord9(rpc) || rpc.jsonrpc !== "2.0" || typeof rpc.method !== "string") {
|
|
44618
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)' } });
|
|
44619
45277
|
return true;
|
|
44620
45278
|
}
|
|
44621
45279
|
const id = typeof rpc.id === "string" || typeof rpc.id === "number" ? rpc.id : null;
|
|
44622
45280
|
const method = rpc.method;
|
|
44623
|
-
const params =
|
|
45281
|
+
const params = isRecord9(rpc.params) ? rpc.params : {};
|
|
44624
45282
|
const requested = negotiateVersion(
|
|
44625
45283
|
typeof req.headers["a2a-version"] === "string" ? req.headers["a2a-version"] : void 0,
|
|
44626
45284
|
new URL(req.url ?? "/", "http://localhost").searchParams.get("version")
|
|
@@ -44678,14 +45336,14 @@ async function handleA2aTaskRequest(req, res, path, deps2) {
|
|
|
44678
45336
|
throw new RpcFailure(JSON_RPC_ERROR.unsupportedOperation, `method "SendMessage" is not allowed for app "${appId}": its manifest does not declare accepts.tasks: true`);
|
|
44679
45337
|
}
|
|
44680
45338
|
const rawMessage = params.message;
|
|
44681
|
-
if (!
|
|
45339
|
+
if (!isRecord9(rawMessage) || rawMessage.role !== "ROLE_USER") {
|
|
44682
45340
|
throw new RpcFailure(JSON_RPC_ERROR.invalidParams, 'params.message must be an object with role "ROLE_USER"');
|
|
44683
45341
|
}
|
|
44684
45342
|
const parts = parseParts(rawMessage.parts);
|
|
44685
45343
|
const { skill, prompt } = extractSkillRequest(
|
|
44686
|
-
{ parts, ...
|
|
45344
|
+
{ parts, ...isRecord9(rawMessage.metadata) ? { metadata: rawMessage.metadata } : {} },
|
|
44687
45345
|
appId,
|
|
44688
|
-
|
|
45346
|
+
isRecord9(params.metadata) ? params.metadata : void 0
|
|
44689
45347
|
);
|
|
44690
45348
|
if (!skill) {
|
|
44691
45349
|
throw new RpcFailure(JSON_RPC_ERROR.invalidParams, 'no skill requested: set message.metadata.skill or start the first text part with "skill:<id>"');
|
|
@@ -46565,6 +47223,7 @@ async function startHttpServer(opts) {
|
|
|
46565
47223
|
opts.resolveSandboxProvider,
|
|
46566
47224
|
opts.webhookNotifier,
|
|
46567
47225
|
opts.ensureLlmEndpointRunning,
|
|
47226
|
+
opts.listAgentAdapters,
|
|
46568
47227
|
opts.deviceMirrorSync
|
|
46569
47228
|
);
|
|
46570
47229
|
if (handled) return;
|
|
@@ -48617,7 +49276,7 @@ async function handleSandboxes(_req, res, path, resolveSandboxProvider2) {
|
|
|
48617
49276
|
json3(200, { alive: true, ...probe.state ? { state: probe.state } : { state: row.state }, checkedAt });
|
|
48618
49277
|
return true;
|
|
48619
49278
|
}
|
|
48620
|
-
async function handleSessions(req, res, path, registry, resolveAgentAdapter, ptyEnabled = false, resolveBrowserAdapter, listBrowserAdapters, sessionEvents, eventRing, buildOrchestratorMcp, daemonMcpUrl, provisionWorktree, listCatalogModels, resolveSandboxProvider2, webhookNotifier, ensureLlmEndpointRunning, deviceMirrorSync) {
|
|
49279
|
+
async function handleSessions(req, res, path, registry, resolveAgentAdapter, ptyEnabled = false, resolveBrowserAdapter, listBrowserAdapters, sessionEvents, eventRing, buildOrchestratorMcp, daemonMcpUrl, provisionWorktree, listCatalogModels, resolveSandboxProvider2, webhookNotifier, ensureLlmEndpointRunning, listAgentAdapters, deviceMirrorSync) {
|
|
48621
49280
|
const json3 = (status, body) => {
|
|
48622
49281
|
res.writeHead(status, { "content-type": "application/json" });
|
|
48623
49282
|
res.end(JSON.stringify(body));
|
|
@@ -48775,12 +49434,13 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
48775
49434
|
...listCatalogModels ? { listCatalogModels } : {},
|
|
48776
49435
|
...resolveSandboxProvider2 ? { resolveSandboxProvider: resolveSandboxProvider2 } : {},
|
|
48777
49436
|
...webhookNotifier ? { webhookNotifier } : {},
|
|
48778
|
-
...ensureLlmEndpointRunning ? { ensureLlmEndpointRunning } : {}
|
|
49437
|
+
...ensureLlmEndpointRunning ? { ensureLlmEndpointRunning } : {},
|
|
49438
|
+
...listAgentAdapters ? { listAgentAdapters } : {}
|
|
48779
49439
|
},
|
|
48780
49440
|
spawnArgs
|
|
48781
49441
|
);
|
|
48782
49442
|
if (!result.ok) {
|
|
48783
|
-
const status = result.code === "adapter_not_found" || result.code === "no_cwd" ? 404 : result.code === "orchestrator_not_enabled" ? 501 : result.code === "orchestrator_max_depth_exceeded" || result.code === "orchestrator_child_quota_exceeded" || result.code === "role_spawn_denied" ? 409 : result.code === "invalid_role" || result.code === "browser_unsupported" || result.code === "worktree_requires_explicit_repo" || result.code === "device_spawn_requires_repo_identity" || result.code === "device_bridge_workspace_unknown" || result.code === "access_profile_not_found" || result.code === "access_profile_ineligible" || result.code === "sandbox_cwd_invalid" ? 400 : 500;
|
|
49443
|
+
const status = result.code === "adapter_not_found" || result.code === "no_cwd" ? 404 : result.code === "orchestrator_not_enabled" ? 501 : result.code === "orchestrator_max_depth_exceeded" || result.code === "orchestrator_child_quota_exceeded" || result.code === "role_spawn_denied" ? 409 : result.code === "invalid_role" || result.code === "browser_unsupported" || result.code === "worktree_requires_explicit_repo" || result.code === "device_spawn_requires_repo_identity" || result.code === "device_bridge_workspace_unknown" || result.code === "access_profile_not_found" || result.code === "access_profile_ineligible" || result.code === "sandbox_cwd_invalid" || result.code === "device_spawn_unreachable" ? 400 : 500;
|
|
48784
49444
|
json3(status, {
|
|
48785
49445
|
error: result.code,
|
|
48786
49446
|
message: result.message,
|
|
@@ -48842,12 +49502,13 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
48842
49502
|
...listCatalogModels ? { listCatalogModels } : {},
|
|
48843
49503
|
...resolveSandboxProvider2 ? { resolveSandboxProvider: resolveSandboxProvider2 } : {},
|
|
48844
49504
|
...webhookNotifier ? { webhookNotifier } : {},
|
|
48845
|
-
...ensureLlmEndpointRunning ? { ensureLlmEndpointRunning } : {}
|
|
49505
|
+
...ensureLlmEndpointRunning ? { ensureLlmEndpointRunning } : {},
|
|
49506
|
+
...listAgentAdapters ? { listAgentAdapters } : {}
|
|
48846
49507
|
},
|
|
48847
49508
|
spawnArgs
|
|
48848
49509
|
);
|
|
48849
49510
|
if (!result.ok) {
|
|
48850
|
-
const status = result.code === "adapter_not_found" || result.code === "no_cwd" ? 404 : result.code === "orchestrator_not_enabled" ? 501 : result.code === "orchestrator_max_depth_exceeded" || result.code === "orchestrator_child_quota_exceeded" || result.code === "role_spawn_denied" ? 409 : result.code === "invalid_role" || result.code === "browser_unsupported" || result.code === "worktree_requires_explicit_repo" || result.code === "device_spawn_requires_repo_identity" || result.code === "device_bridge_workspace_unknown" || result.code === "access_profile_not_found" || result.code === "access_profile_ineligible" || result.code === "sandbox_cwd_invalid" ? 400 : 500;
|
|
49511
|
+
const status = result.code === "adapter_not_found" || result.code === "no_cwd" ? 404 : result.code === "orchestrator_not_enabled" ? 501 : result.code === "orchestrator_max_depth_exceeded" || result.code === "orchestrator_child_quota_exceeded" || result.code === "role_spawn_denied" ? 409 : result.code === "invalid_role" || result.code === "browser_unsupported" || result.code === "worktree_requires_explicit_repo" || result.code === "device_spawn_requires_repo_identity" || result.code === "device_bridge_workspace_unknown" || result.code === "access_profile_not_found" || result.code === "access_profile_ineligible" || result.code === "sandbox_cwd_invalid" || result.code === "device_spawn_unreachable" ? 400 : 500;
|
|
48851
49512
|
json3(status, {
|
|
48852
49513
|
error: result.code,
|
|
48853
49514
|
message: result.message,
|
|
@@ -52198,9 +52859,13 @@ function isCrashed(desc) {
|
|
|
52198
52859
|
if (desc.kind !== "agent-cli") return false;
|
|
52199
52860
|
if (desc.status !== "running") return false;
|
|
52200
52861
|
if (desc.remote === true) return false;
|
|
52862
|
+
if (desc.adapterConnected === false) return true;
|
|
52201
52863
|
if (desc.pid === null || desc.pid === void 0) return false;
|
|
52202
52864
|
return desc.processAlive === false;
|
|
52203
52865
|
}
|
|
52866
|
+
function crashReasonFor(desc) {
|
|
52867
|
+
return desc.adapterConnected === false ? "transport-closed" : "process-gone";
|
|
52868
|
+
}
|
|
52204
52869
|
function runCrashDetectPass(opts) {
|
|
52205
52870
|
const { registry, isServed } = opts;
|
|
52206
52871
|
const intervalMs = opts.crashDetectIntervalMs;
|
|
@@ -52216,7 +52881,7 @@ function runCrashDetectPass(opts) {
|
|
|
52216
52881
|
ids: []
|
|
52217
52882
|
};
|
|
52218
52883
|
for (const d of candidates) {
|
|
52219
|
-
if (registry.markCrashed(d.id)) {
|
|
52884
|
+
if (registry.markCrashed(d.id, crashReasonFor(d))) {
|
|
52220
52885
|
summary.crashed++;
|
|
52221
52886
|
summary.ids.push(d.id);
|
|
52222
52887
|
}
|
|
@@ -52386,6 +53051,7 @@ async function resolveMessagingDefaults(loadCfg = loadConfig) {
|
|
|
52386
53051
|
|
|
52387
53052
|
// src/index.ts
|
|
52388
53053
|
init_transcript_writer();
|
|
53054
|
+
init_session_index();
|
|
52389
53055
|
var BINDINGS_FILE_PATH = () => resolve(homedir(), ".agentproto", "transmitter-bindings.json");
|
|
52390
53056
|
var PERSIST_DEBOUNCE_MS5 = 1500;
|
|
52391
53057
|
var keyOf = (alias, source, contactRef) => `${alias}:${source}:${contactRef}`;
|
|
@@ -52799,12 +53465,13 @@ async function ssrfFetch(url, init, io = {}) {
|
|
|
52799
53465
|
if ((init.body?.byteLength ?? 0) > MAX_REQUEST_BODY_BYTES) {
|
|
52800
53466
|
throw new SsrfFetchError("connect", `request body exceeds the ${MAX_REQUEST_BODY_BYTES}-byte clamp`);
|
|
52801
53467
|
}
|
|
53468
|
+
const port = parsed.port ? Number(parsed.port) : 443;
|
|
52802
53469
|
if (testDispatcher) {
|
|
52803
53470
|
const literal = parseIpv4(parsed.hostname);
|
|
52804
53471
|
if (literal && !ipv4Public(literal[0], literal[1], literal[2], literal[3])) {
|
|
52805
53472
|
throw new SsrfFetchError("private_target", `literal non-public address ${parsed.hostname}`);
|
|
52806
53473
|
}
|
|
52807
|
-
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 });
|
|
52808
53475
|
}
|
|
52809
53476
|
const candidates = await resolveHost(parsed.hostname, io.resolvers ?? {});
|
|
52810
53477
|
if (candidates.length === 0) {
|
|
@@ -52816,17 +53483,26 @@ async function ssrfFetch(url, init, io = {}) {
|
|
|
52816
53483
|
}
|
|
52817
53484
|
const connectIp = candidates[0] ?? candidates[candidates.length - 1];
|
|
52818
53485
|
if (connectIp === void 0) throw new SsrfFetchError("connect", "no address available for connect");
|
|
52819
|
-
const port = parsed.port ? Number(parsed.port) : 443;
|
|
52820
53486
|
return await rawPost({
|
|
52821
53487
|
connectIp,
|
|
52822
53488
|
servername: parsed.hostname,
|
|
52823
53489
|
port,
|
|
52824
53490
|
path: `${parsed.pathname}${parsed.search}`,
|
|
52825
|
-
|
|
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),
|
|
52826
53497
|
body: init.body,
|
|
52827
53498
|
timeoutMs: init.timeoutMs
|
|
52828
53499
|
});
|
|
52829
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
|
+
}
|
|
52830
53506
|
function rawPost(args) {
|
|
52831
53507
|
return new Promise((resolve42, reject) => {
|
|
52832
53508
|
const req = request({
|
|
@@ -52837,6 +53513,8 @@ function rawPost(args) {
|
|
|
52837
53513
|
path: args.path,
|
|
52838
53514
|
method: "POST",
|
|
52839
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.
|
|
52840
53518
|
headers: args.headers,
|
|
52841
53519
|
rejectUnauthorized: true
|
|
52842
53520
|
});
|
|
@@ -52954,6 +53632,562 @@ async function deliverEventEnvelope(replay, event, deps2 = {}) {
|
|
|
52954
53632
|
}
|
|
52955
53633
|
return { ok: false, reason: "retries_exhausted", delivery };
|
|
52956
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
|
+
}
|
|
52957
54191
|
|
|
52958
54192
|
// src/sentinel-webhook-outbox.ts
|
|
52959
54193
|
function agentprotoHome3() {
|
|
@@ -52969,13 +54203,7 @@ function webhookRequestId(sentinelId, eventId) {
|
|
|
52969
54203
|
return `sub_${digest.slice(0, 32)}`;
|
|
52970
54204
|
}
|
|
52971
54205
|
function toWebhookEnvelope(event) {
|
|
52972
|
-
return
|
|
52973
|
-
eventId: event.id,
|
|
52974
|
-
name: event.type,
|
|
52975
|
-
timestamp: event.time,
|
|
52976
|
-
data: { ...event.data, subject: event.subject, summary: event.summary },
|
|
52977
|
-
cursor: null
|
|
52978
|
-
};
|
|
54206
|
+
return toMcpEvent(event);
|
|
52979
54207
|
}
|
|
52980
54208
|
function createSentinelWebhookOutbox(opts) {
|
|
52981
54209
|
const filePath = opts.filePath ?? resolve(agentprotoHome3(), "sentinel-webhook-outbox.json");
|
|
@@ -54877,12 +56105,12 @@ function canonicalJson(value) {
|
|
|
54877
56105
|
}
|
|
54878
56106
|
function isToolAppVisible(tool) {
|
|
54879
56107
|
const meta = tool._meta;
|
|
54880
|
-
const ui =
|
|
56108
|
+
const ui = isRecord11(meta?.ui) ? meta.ui : void 0;
|
|
54881
56109
|
const visibility = ui?.visibility;
|
|
54882
56110
|
if (!Array.isArray(visibility)) return true;
|
|
54883
56111
|
return visibility.includes("app");
|
|
54884
56112
|
}
|
|
54885
|
-
function
|
|
56113
|
+
function isRecord11(v) {
|
|
54886
56114
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
54887
56115
|
}
|
|
54888
56116
|
function buildUiToolIndex(tools) {
|
|
@@ -55407,19 +56635,19 @@ function classifyMcpError(err) {
|
|
|
55407
56635
|
return { status: "unreachable", error };
|
|
55408
56636
|
}
|
|
55409
56637
|
function uiMetaOf(meta) {
|
|
55410
|
-
if (!
|
|
56638
|
+
if (!isRecord12(meta) || !isRecord12(meta.ui)) return {};
|
|
55411
56639
|
const ui = meta.ui;
|
|
55412
56640
|
const csp = cspOf(ui.csp);
|
|
55413
56641
|
return {
|
|
55414
56642
|
...csp ? { csp } : {},
|
|
55415
|
-
...
|
|
56643
|
+
...isRecord12(ui.permissions) ? { permissions: ui.permissions } : {},
|
|
55416
56644
|
...typeof ui.prefersBorder === "boolean" ? { prefersBorder: ui.prefersBorder } : {},
|
|
55417
56645
|
...typeof ui.domain === "string" ? { domain: ui.domain } : {}
|
|
55418
56646
|
};
|
|
55419
56647
|
}
|
|
55420
56648
|
var CSP_DOMAIN_KEYS = ["connectDomains", "resourceDomains", "frameDomains", "baseUriDomains"];
|
|
55421
56649
|
function cspOf(raw) {
|
|
55422
|
-
if (!
|
|
56650
|
+
if (!isRecord12(raw)) return void 0;
|
|
55423
56651
|
const csp = {};
|
|
55424
56652
|
for (const key of CSP_DOMAIN_KEYS) {
|
|
55425
56653
|
const value = raw[key];
|
|
@@ -55429,7 +56657,7 @@ function cspOf(raw) {
|
|
|
55429
56657
|
}
|
|
55430
56658
|
return Object.keys(csp).length > 0 ? csp : void 0;
|
|
55431
56659
|
}
|
|
55432
|
-
function
|
|
56660
|
+
function isRecord12(v) {
|
|
55433
56661
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
55434
56662
|
}
|
|
55435
56663
|
function errorMessage(err) {
|
|
@@ -57218,6 +58446,7 @@ function createPrProvenanceReconciler(opts) {
|
|
|
57218
58446
|
const stampedPrUrls = /* @__PURE__ */ new Set();
|
|
57219
58447
|
const costRefreshedPrUrls = /* @__PURE__ */ new Set();
|
|
57220
58448
|
const lastPollAt = /* @__PURE__ */ new Map();
|
|
58449
|
+
const scannedPrUrls = /* @__PURE__ */ new Set();
|
|
57221
58450
|
const reconcile = async (sessionId, terminal) => {
|
|
57222
58451
|
const desc = opts.registry.get(sessionId);
|
|
57223
58452
|
if (!desc || desc.kind !== "agent-cli") return;
|
|
@@ -57256,6 +58485,29 @@ function createPrProvenanceReconciler(opts) {
|
|
|
57256
58485
|
if (!shouldStamp(record2.createdPrUrl)) continue;
|
|
57257
58486
|
await stamp({ number: record2.createdPrNumber, url: record2.createdPrUrl });
|
|
57258
58487
|
}
|
|
58488
|
+
if (desc.eventsPath) {
|
|
58489
|
+
for (const turn of readRecentTurnsSync(desc.eventsPath)) {
|
|
58490
|
+
if (turn.role !== "assistant") continue;
|
|
58491
|
+
const re = /https?:\/\/[^\s<>"]+/g;
|
|
58492
|
+
let m;
|
|
58493
|
+
while ((m = re.exec(turn.text)) !== null) {
|
|
58494
|
+
const url = m[0].replace(/[.,;:)\]]+$/, "");
|
|
58495
|
+
const parsed = parsePrUrl(url);
|
|
58496
|
+
if (!parsed) continue;
|
|
58497
|
+
if (desc.openedPrs?.some((known) => known.url === url)) continue;
|
|
58498
|
+
if (scannedPrUrls.has(url)) continue;
|
|
58499
|
+
scannedPrUrls.add(url);
|
|
58500
|
+
try {
|
|
58501
|
+
opts.registry.recordOpenedPr(sessionId, {
|
|
58502
|
+
adapter: "output-scan",
|
|
58503
|
+
number: parsed.number,
|
|
58504
|
+
url
|
|
58505
|
+
});
|
|
58506
|
+
} catch {
|
|
58507
|
+
}
|
|
58508
|
+
}
|
|
58509
|
+
}
|
|
58510
|
+
}
|
|
57259
58511
|
const pr = await opts.resolveOpenPr(cwd);
|
|
57260
58512
|
if (pr && shouldStamp(pr.url)) await stamp(pr);
|
|
57261
58513
|
await refreshCost(desc, supervisor, cwd);
|
|
@@ -57914,7 +59166,7 @@ function humanizeKey(key) {
|
|
|
57914
59166
|
const words = key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_\-.]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase();
|
|
57915
59167
|
return words.length === 0 ? "Value" : words.charAt(0).toUpperCase() + words.slice(1);
|
|
57916
59168
|
}
|
|
57917
|
-
function
|
|
59169
|
+
function isRecord13(value) {
|
|
57918
59170
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
57919
59171
|
}
|
|
57920
59172
|
function scalarText(value) {
|
|
@@ -57944,7 +59196,7 @@ function flattenRows(value, label, depth, out) {
|
|
|
57944
59196
|
});
|
|
57945
59197
|
return;
|
|
57946
59198
|
}
|
|
57947
|
-
if (
|
|
59199
|
+
if (isRecord13(value)) {
|
|
57948
59200
|
if (depth >= MAX_DEPTH) return;
|
|
57949
59201
|
for (const [key, child] of Object.entries(value)) {
|
|
57950
59202
|
flattenRows(child, label ? `${label} / ${humanizeKey(key)}` : humanizeKey(key), depth + 1, out);
|
|
@@ -57966,7 +59218,7 @@ function renderMail(preview2) {
|
|
|
57966
59218
|
const cc = addressList(preview2.cc);
|
|
57967
59219
|
const subject = scalarText(preview2.subject) ?? "";
|
|
57968
59220
|
const body = scalarText(preview2.body) ?? "";
|
|
57969
|
-
const attachments = Array.isArray(preview2.attachments) ? preview2.attachments.filter(
|
|
59221
|
+
const attachments = Array.isArray(preview2.attachments) ? preview2.attachments.filter(isRecord13).map((a) => {
|
|
57970
59222
|
const name = scalarText(a.fileName) ?? "";
|
|
57971
59223
|
const size = typeof a.sizeBytes === "number" ? humanSize(a.sizeBytes) : "";
|
|
57972
59224
|
return size ? `${name} (${size})` : name;
|
|
@@ -57981,9 +59233,9 @@ function renderMail(preview2) {
|
|
|
57981
59233
|
}
|
|
57982
59234
|
function renderPreview(record2) {
|
|
57983
59235
|
const preview2 = record2.preview;
|
|
57984
|
-
if (
|
|
59236
|
+
if (isRecord13(preview2) && preview2.kind === "mail") return renderMail(preview2);
|
|
57985
59237
|
const rows = [];
|
|
57986
|
-
if (
|
|
59238
|
+
if (isRecord13(preview2)) {
|
|
57987
59239
|
for (const [key, value] of Object.entries(preview2)) flattenRows(value, humanizeKey(key), 1, rows);
|
|
57988
59240
|
} else {
|
|
57989
59241
|
flattenRows(preview2, "Details", 1, rows);
|
|
@@ -59435,6 +60687,8 @@ async function reconcileSandboxLedger(deps2) {
|
|
|
59435
60687
|
// src/index.ts
|
|
59436
60688
|
init_session_outcome();
|
|
59437
60689
|
init_session_end_reason();
|
|
60690
|
+
init_transcript_writer();
|
|
60691
|
+
init_session_index();
|
|
59438
60692
|
init_sessions();
|
|
59439
60693
|
init_sessions();
|
|
59440
60694
|
init_process_stats();
|
|
@@ -59454,12 +60708,12 @@ function measureToolList(tools) {
|
|
|
59454
60708
|
}
|
|
59455
60709
|
var packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
59456
60710
|
var helpDir = join(packageRoot, "docs", "mcp-tools");
|
|
59457
|
-
var
|
|
60711
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
59458
60712
|
function getToolHelp(name) {
|
|
59459
|
-
if (
|
|
60713
|
+
if (cache2.has(name)) return cache2.get(name);
|
|
59460
60714
|
const path = join(helpDir, `${name}.md`);
|
|
59461
60715
|
const content = existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
59462
|
-
|
|
60716
|
+
cache2.set(name, content);
|
|
59463
60717
|
return content;
|
|
59464
60718
|
}
|
|
59465
60719
|
function listToolHelpTopics() {
|
|
@@ -61752,7 +63006,7 @@ async function registerSentinelAdapterTools(server, opts = {}) {
|
|
|
61752
63006
|
makeListTool({
|
|
61753
63007
|
server,
|
|
61754
63008
|
toolName: "list_sentinel_adapters",
|
|
61755
|
-
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.",
|
|
61756
63010
|
lister: makeSentinelLister({ credsStore, ledger })
|
|
61757
63011
|
});
|
|
61758
63012
|
const { validSlugs, fields } = await collectSetupSchema3();
|
|
@@ -61877,102 +63131,6 @@ function createWorkspaceFs(opts) {
|
|
|
61877
63131
|
|
|
61878
63132
|
// src/index.ts
|
|
61879
63133
|
init_role();
|
|
61880
|
-
function challengeReasonForSsrf(reason) {
|
|
61881
|
-
if (reason === "non_https") return "non_https";
|
|
61882
|
-
if (reason === "private_target" || reason === "redirect") return "ssrf_blocked";
|
|
61883
|
-
return "timeout";
|
|
61884
|
-
}
|
|
61885
|
-
var CHALLENGE_TTL_MS = 10 * 60 * 1e3;
|
|
61886
|
-
var encoder = new TextEncoder();
|
|
61887
|
-
var cache2 = /* @__PURE__ */ new Map();
|
|
61888
|
-
function challengeCacheSize() {
|
|
61889
|
-
return cache2.size;
|
|
61890
|
-
}
|
|
61891
|
-
function resetChallengeCacheForTests() {
|
|
61892
|
-
cache2.clear();
|
|
61893
|
-
}
|
|
61894
|
-
function normalizeCallbackUrl(url) {
|
|
61895
|
-
try {
|
|
61896
|
-
const u = new URL(url);
|
|
61897
|
-
const port = u.port === "443" ? "" : `:${u.port}`;
|
|
61898
|
-
return `${u.protocol.toLowerCase()}//${u.hostname.toLowerCase()}${port}${u.pathname}${u.search}`;
|
|
61899
|
-
} catch {
|
|
61900
|
-
return null;
|
|
61901
|
-
}
|
|
61902
|
-
}
|
|
61903
|
-
function hashSecret(secret) {
|
|
61904
|
-
return createHash("sha256").update(secret, "utf8").digest("hex");
|
|
61905
|
-
}
|
|
61906
|
-
function constantTimeEq(a, b) {
|
|
61907
|
-
const da = createHash("sha256").update(a, "utf8").digest();
|
|
61908
|
-
const db = createHash("sha256").update(b, "utf8").digest();
|
|
61909
|
-
return timingSafeEqual(da, db);
|
|
61910
|
-
}
|
|
61911
|
-
async function verifyCallback(input, deps2 = {}) {
|
|
61912
|
-
const now = deps2.now ?? (() => Date.now());
|
|
61913
|
-
const normalized = normalizeCallbackUrl(input.url);
|
|
61914
|
-
if (normalized === null || !normalized.startsWith("https://")) {
|
|
61915
|
-
return { ok: false, reason: "non_https", detail: "callback URL must be an https URL" };
|
|
61916
|
-
}
|
|
61917
|
-
if (decodeWhsecSecret(input.secret) === null) {
|
|
61918
|
-
return {
|
|
61919
|
-
ok: false,
|
|
61920
|
-
reason: "challenge_failed",
|
|
61921
|
-
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)"
|
|
61922
|
-
};
|
|
61923
|
-
}
|
|
61924
|
-
const cacheKey = `${input.principal}|${normalized}|${hashSecret(input.secret)}`;
|
|
61925
|
-
const cached = cache2.get(cacheKey);
|
|
61926
|
-
if (cached && cached.expiresAt > now()) {
|
|
61927
|
-
return { ok: true, verificationBytes: cached.requestBytes };
|
|
61928
|
-
}
|
|
61929
|
-
if (cached) cache2.delete(cacheKey);
|
|
61930
|
-
const challenge = randomBytes(32).toString("hex");
|
|
61931
|
-
const requestBytes = encoder.encode(JSON.stringify({ type: "verification", challenge }));
|
|
61932
|
-
const msgId = `msg_verification_${randomBytes(12).toString("hex")}`;
|
|
61933
|
-
const timestamp = Math.floor(now() / 1e3);
|
|
61934
|
-
let headers;
|
|
61935
|
-
try {
|
|
61936
|
-
const signed = signWebhook({ msgId, timestamp, payload: requestBytes, secrets: [input.secret] });
|
|
61937
|
-
headers = {
|
|
61938
|
-
...signed,
|
|
61939
|
-
"content-type": "application/json",
|
|
61940
|
-
"X-MCP-Subscription-Id": input.subscriptionId
|
|
61941
|
-
};
|
|
61942
|
-
} catch (err) {
|
|
61943
|
-
return { ok: false, reason: "challenge_failed", detail: `signing failed: ${err.message}` };
|
|
61944
|
-
}
|
|
61945
|
-
let response;
|
|
61946
|
-
try {
|
|
61947
|
-
response = await (deps2.fetch ?? ssrfFetch)(input.url, {
|
|
61948
|
-
method: "POST",
|
|
61949
|
-
headers,
|
|
61950
|
-
body: requestBytes,
|
|
61951
|
-
timeoutMs: 1e4
|
|
61952
|
-
// default challenge timeout (delivery uses 15_000)
|
|
61953
|
-
});
|
|
61954
|
-
} catch (err) {
|
|
61955
|
-
if (err instanceof SsrfFetchError) {
|
|
61956
|
-
return { ok: false, reason: challengeReasonForSsrf(err.reason), detail: `${err.reason}: ${err.message}` };
|
|
61957
|
-
}
|
|
61958
|
-
return { ok: false, reason: "timeout", detail: err.message };
|
|
61959
|
-
}
|
|
61960
|
-
if (response.status < 200 || response.status > 299) {
|
|
61961
|
-
return { ok: false, reason: "non_2xx", detail: `callback responded with status ${response.status}` };
|
|
61962
|
-
}
|
|
61963
|
-
let parsedBody;
|
|
61964
|
-
try {
|
|
61965
|
-
parsedBody = JSON.parse(response.body);
|
|
61966
|
-
} catch {
|
|
61967
|
-
return { ok: false, reason: "challenge_failed", detail: "response body is not JSON" };
|
|
61968
|
-
}
|
|
61969
|
-
const echoed = parsedBody?.challenge;
|
|
61970
|
-
if (typeof echoed !== "string" || !constantTimeEq(echoed, challenge)) {
|
|
61971
|
-
return { ok: false, reason: "challenge_failed", detail: "response did not echo the fresh challenge" };
|
|
61972
|
-
}
|
|
61973
|
-
cache2.set(cacheKey, { requestBytes, expiresAt: now() + CHALLENGE_TTL_MS });
|
|
61974
|
-
return { ok: true, verificationBytes: requestBytes };
|
|
61975
|
-
}
|
|
61976
63134
|
async function hasNamedLlmEndpoints() {
|
|
61977
63135
|
const override = process.env.LLM_ENDPOINT_ENDPOINTS_FILE?.trim();
|
|
61978
63136
|
const path = override && override.length > 0 ? override : join(homedir(), ".agentproto", "llm-endpoints.json");
|
|
@@ -62001,7 +63159,7 @@ init_worktree_isolation();
|
|
|
62001
63159
|
var pairing_registry_exports = {};
|
|
62002
63160
|
__reExport(pairing_registry_exports, pairing_host_star);
|
|
62003
63161
|
var JOIN_TOKENS_VERSION = 1;
|
|
62004
|
-
var
|
|
63162
|
+
var DEFAULT_TTL_MS2 = 90 * 864e5;
|
|
62005
63163
|
var DEFAULT_RECONNECT_MIN_MS = 1e3;
|
|
62006
63164
|
var DEFAULT_RECONNECT_MAX_MS = 3e4;
|
|
62007
63165
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 11e4;
|
|
@@ -62111,7 +63269,7 @@ function createJoinTokenRegistry(deps2) {
|
|
|
62111
63269
|
const secret = b64url(randomBytes(16));
|
|
62112
63270
|
const id = randomBytes(6).toString("hex");
|
|
62113
63271
|
const nowIso2 = new Date(now()).toISOString();
|
|
62114
|
-
const ttlMs = input.ttlMs ??
|
|
63272
|
+
const ttlMs = input.ttlMs ?? DEFAULT_TTL_MS2;
|
|
62115
63273
|
const expiresAt = new Date(now() + ttlMs).toISOString();
|
|
62116
63274
|
const record2 = {
|
|
62117
63275
|
id,
|
|
@@ -63283,6 +64441,20 @@ async function createGateway(opts) {
|
|
|
63283
64441
|
});
|
|
63284
64442
|
registerEvalReporterTools(server);
|
|
63285
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
|
+
});
|
|
63286
64458
|
return server;
|
|
63287
64459
|
};
|
|
63288
64460
|
let internalToolServerPromise;
|
|
@@ -63607,6 +64779,15 @@ async function createGateway(opts) {
|
|
|
63607
64779
|
...passOpts?.isServed ? { isServed: passOpts.isServed } : {}
|
|
63608
64780
|
});
|
|
63609
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
|
+
},
|
|
63610
64791
|
async stop() {
|
|
63611
64792
|
heartbeat.stop();
|
|
63612
64793
|
if (idleReapTimer) clearInterval(idleReapTimer);
|
|
@@ -63679,6 +64860,6 @@ var export_readPairingsSnapshot = pairing_registry_exports.readPairingsSnapshot;
|
|
|
63679
64860
|
var export_removeProviderKey = providers_store_exports.removeProviderKey;
|
|
63680
64861
|
var export_setProviderKey = providers_store_exports.setProviderKey;
|
|
63681
64862
|
|
|
63682
|
-
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 };
|
|
63683
64864
|
//# sourceMappingURL=index.mjs.map
|
|
63684
64865
|
//# sourceMappingURL=index.mjs.map
|