@alook/daemon 0.1.28 → 0.1.30
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/README.md +7 -5
- package/dist/cli/index.js +753 -201
- package/dist/index.js +600 -124
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -98,7 +98,7 @@ var init_nanoid = () => {};
|
|
|
98
98
|
// src/cli/index.ts
|
|
99
99
|
import { Command, CommanderError } from "commander";
|
|
100
100
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
101
|
-
import { randomUUID as
|
|
101
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
102
102
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
103
103
|
|
|
104
104
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
@@ -16762,6 +16762,10 @@ var OwnerDiagnosticReportSchema = exports_external.discriminatedUnion("status",
|
|
|
16762
16762
|
// ../shared/src/community-cli-contract.ts
|
|
16763
16763
|
var DM_SERVER = ".dm";
|
|
16764
16764
|
var CONTROL_HEARTBEAT_CAPABILITY = "control-heartbeat-v1";
|
|
16765
|
+
var AgentInterruptRequestSchema = exports_external.strictObject({
|
|
16766
|
+
type: exports_external.literal("agent:interrupt"),
|
|
16767
|
+
agentId: exports_external.string().min(1).max(128)
|
|
16768
|
+
});
|
|
16765
16769
|
function parseRef(ref) {
|
|
16766
16770
|
if (!ref.startsWith("/"))
|
|
16767
16771
|
throw new Error(`ref must start with "/": ${ref}`);
|
|
@@ -16853,6 +16857,7 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
16853
16857
|
type: exports_external.literal("agent:stop"),
|
|
16854
16858
|
agentId: exports_external.string().min(1)
|
|
16855
16859
|
}),
|
|
16860
|
+
AgentInterruptRequestSchema,
|
|
16856
16861
|
exports_external.object({
|
|
16857
16862
|
type: exports_external.literal("agent:reset"),
|
|
16858
16863
|
agentId: exports_external.string().min(1),
|
|
@@ -16920,7 +16925,6 @@ var MAX_FOLDER_NAME_LENGTH = 100;
|
|
|
16920
16925
|
var MAX_PROFILE_NAME_LENGTH = 100;
|
|
16921
16926
|
var MAX_PROFILE_ABOUT_LENGTH = 1000;
|
|
16922
16927
|
var MAX_MESSAGE_CONTENT_LENGTH = 4000;
|
|
16923
|
-
var MAX_EMOJI_BYTES = 32;
|
|
16924
16928
|
var MAX_ATTACHMENTS_PER_MESSAGE = 10;
|
|
16925
16929
|
var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
|
|
16926
16930
|
var MAX_ATTACHMENT_THUMBNAIL_EDGE_PX = 1024;
|
|
@@ -16934,6 +16938,7 @@ var ALLOWED_ICON_MIME_TYPES = [
|
|
|
16934
16938
|
];
|
|
16935
16939
|
var MAX_ICON_SOURCE_FILE_SIZE_BYTES = 15 * 1024 * 1024;
|
|
16936
16940
|
// ../shared/src/provider-telemetry.ts
|
|
16941
|
+
var DAILY_TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
16937
16942
|
var safeToken = exports_external.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
16938
16943
|
var boundedText = exports_external.string().min(1).refine((value) => new TextEncoder().encode(value).length <= 64, { message: "must be at most 64 UTF-8 bytes" });
|
|
16939
16944
|
var DailyUsageMetricSchema = safeToken.nullable();
|
|
@@ -17665,7 +17670,7 @@ var AgentActivityMessageSchema = exports_external.object({
|
|
|
17665
17670
|
state: exports_external.enum(["idle", "starting", "running", "stopping"]),
|
|
17666
17671
|
usageTimeZone: exports_external.string().min(1).max(128).optional(),
|
|
17667
17672
|
usageDay: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
17668
|
-
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(
|
|
17673
|
+
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(DAILY_TOKEN_USAGE_WINDOW_DAYS).optional(),
|
|
17669
17674
|
quota: ProviderQuotaSnapshotSchema.optional()
|
|
17670
17675
|
});
|
|
17671
17676
|
var AgentTypingMessageSchema = exports_external.object({
|
|
@@ -17829,17 +17834,18 @@ var CommunityAgentNapRequestSchema = exports_external.object({
|
|
|
17829
17834
|
message: "handoff is required"
|
|
17830
17835
|
})
|
|
17831
17836
|
});
|
|
17832
|
-
var
|
|
17837
|
+
var CommunityAgentMessagePropertyRequestSchema = exports_external.object({
|
|
17833
17838
|
channel: exports_external.string().min(1),
|
|
17834
17839
|
seq: CommunityAgentPositiveSeqSchema,
|
|
17835
|
-
|
|
17840
|
+
property: exports_external.unknown()
|
|
17836
17841
|
});
|
|
17837
17842
|
var CommunityAgentFriendRequestSchema = exports_external.object({
|
|
17838
17843
|
username: exports_external.string().min(1)
|
|
17839
17844
|
});
|
|
17840
17845
|
var CommunityAgentListFriendsSchema = exports_external.object({});
|
|
17841
17846
|
var AuditLogCliInvocationPayloadSchema = exports_external.object({
|
|
17842
|
-
subcommand: exports_external.string().min(1)
|
|
17847
|
+
subcommand: exports_external.string().min(1),
|
|
17848
|
+
propertyType: exports_external.enum(["emoji", "tag", "mark"]).optional()
|
|
17843
17849
|
});
|
|
17844
17850
|
var AuditLogToolCallPayloadSchema = exports_external.object({
|
|
17845
17851
|
name: exports_external.string().min(1),
|
|
@@ -19135,6 +19141,14 @@ function proxyServerApiFromEnv(prefix = "ALOOK", env = process.env) {
|
|
|
19135
19141
|
function createProxyServerApi(config2) {
|
|
19136
19142
|
const fetchImpl = config2.fetchImpl ?? fetch;
|
|
19137
19143
|
const base = config2.proxyUrl.replace(/\/+$/, "");
|
|
19144
|
+
const propertyAuditQuery = (property) => {
|
|
19145
|
+
if (!property || typeof property !== "object" || Array.isArray(property))
|
|
19146
|
+
return "";
|
|
19147
|
+
const type = property.type;
|
|
19148
|
+
if (type !== "emoji" && type !== "tag" && type !== "mark")
|
|
19149
|
+
return "";
|
|
19150
|
+
return `?type=${encodeURIComponent(type)}`;
|
|
19151
|
+
};
|
|
19138
19152
|
async function parseJsonResponse(res, method) {
|
|
19139
19153
|
let text2;
|
|
19140
19154
|
try {
|
|
@@ -19252,17 +19266,37 @@ function createProxyServerApi(config2) {
|
|
|
19252
19266
|
});
|
|
19253
19267
|
return parseJsonResponse(res, "resolve");
|
|
19254
19268
|
}
|
|
19255
|
-
async function
|
|
19256
|
-
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/
|
|
19269
|
+
async function callMessagePropertySet(req) {
|
|
19270
|
+
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/properties${propertyAuditQuery(req.property)}`, {
|
|
19257
19271
|
method: "PUT",
|
|
19258
19272
|
headers: {
|
|
19259
19273
|
"content-type": "application/json",
|
|
19260
19274
|
authorization: `Bearer ${config2.voucher}`
|
|
19261
19275
|
},
|
|
19262
|
-
body: JSON.stringify(
|
|
19276
|
+
body: JSON.stringify(req)
|
|
19277
|
+
});
|
|
19278
|
+
return parseJsonResponse(res, "messagePropertySet");
|
|
19279
|
+
}
|
|
19280
|
+
async function callMessagePropertyList(req) {
|
|
19281
|
+
const q = new URLSearchParams;
|
|
19282
|
+
q.set("ref", req.channel);
|
|
19283
|
+
q.set("seq", String(req.seq));
|
|
19284
|
+
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/properties?${q.toString()}`, {
|
|
19285
|
+
method: "GET",
|
|
19286
|
+
headers: { authorization: `Bearer ${config2.voucher}` }
|
|
19287
|
+
});
|
|
19288
|
+
return parseJsonResponse(res, "messagePropertyList");
|
|
19289
|
+
}
|
|
19290
|
+
async function callMessagePropertyRemove(req) {
|
|
19291
|
+
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/properties${propertyAuditQuery(req.property)}`, {
|
|
19292
|
+
method: "DELETE",
|
|
19293
|
+
headers: {
|
|
19294
|
+
"content-type": "application/json",
|
|
19295
|
+
authorization: `Bearer ${config2.voucher}`
|
|
19296
|
+
},
|
|
19297
|
+
body: JSON.stringify(req)
|
|
19263
19298
|
});
|
|
19264
|
-
|
|
19265
|
-
return body?.duplicate ? { ok: true, duplicate: true } : { ok: true };
|
|
19299
|
+
return parseJsonResponse(res, "messagePropertyRemove");
|
|
19266
19300
|
}
|
|
19267
19301
|
async function callListMembers(req) {
|
|
19268
19302
|
const q = new URLSearchParams;
|
|
@@ -19314,28 +19348,6 @@ function createProxyServerApi(config2) {
|
|
|
19314
19348
|
});
|
|
19315
19349
|
return parseJsonResponse(res, "inboxPull");
|
|
19316
19350
|
}
|
|
19317
|
-
async function callMarkSet(req) {
|
|
19318
|
-
const res = await fetchImpl(`${base}/api/community/messages/resolve/marks`, {
|
|
19319
|
-
method: "PUT",
|
|
19320
|
-
headers: {
|
|
19321
|
-
"content-type": "application/json",
|
|
19322
|
-
authorization: `Bearer ${config2.voucher}`
|
|
19323
|
-
},
|
|
19324
|
-
body: JSON.stringify(req)
|
|
19325
|
-
});
|
|
19326
|
-
await parseJsonResponse(res, "markSet");
|
|
19327
|
-
}
|
|
19328
|
-
async function callMarkRemove(req) {
|
|
19329
|
-
const res = await fetchImpl(`${base}/api/community/messages/resolve/marks`, {
|
|
19330
|
-
method: "DELETE",
|
|
19331
|
-
headers: {
|
|
19332
|
-
"content-type": "application/json",
|
|
19333
|
-
authorization: `Bearer ${config2.voucher}`
|
|
19334
|
-
},
|
|
19335
|
-
body: JSON.stringify(req)
|
|
19336
|
-
});
|
|
19337
|
-
await parseJsonResponse(res, "markRemove");
|
|
19338
|
-
}
|
|
19339
19351
|
async function callListMarks() {
|
|
19340
19352
|
const res = await fetchImpl(`${base}/api/community/users/me/marks`, {
|
|
19341
19353
|
method: "GET",
|
|
@@ -19492,11 +19504,32 @@ function createProxyServerApi(config2) {
|
|
|
19492
19504
|
}
|
|
19493
19505
|
return { server: projectServer(body.server) };
|
|
19494
19506
|
}
|
|
19507
|
+
async function callLeaveChannel(req) {
|
|
19508
|
+
const parsed = parseRef(req.channel);
|
|
19509
|
+
const scope = parsed.threadRootSeq === undefined ? "channel" : "thread";
|
|
19510
|
+
const collection = scope === "thread" ? "participants" : "members";
|
|
19511
|
+
const res = await fetchImpl(`${base}/api/community/channels/${REF_PLACEHOLDER_ID}/${collection}/self?ref=${encodeURIComponent(req.channel)}`, {
|
|
19512
|
+
method: "DELETE",
|
|
19513
|
+
headers: { authorization: `Bearer ${config2.voucher}` }
|
|
19514
|
+
});
|
|
19515
|
+
await parseJsonResponse(res, "leaveChannel");
|
|
19516
|
+
return { left: req.channel, scope };
|
|
19517
|
+
}
|
|
19518
|
+
async function callLeaveServer(req) {
|
|
19519
|
+
const res = await fetchImpl(`${base}/api/community/servers/${REF_PLACEHOLDER_ID}/leave?server=${encodeURIComponent(req.server)}`, {
|
|
19520
|
+
method: "POST",
|
|
19521
|
+
headers: { authorization: `Bearer ${config2.voucher}` }
|
|
19522
|
+
});
|
|
19523
|
+
await parseJsonResponse(res, "leaveServer");
|
|
19524
|
+
return { left: req.server, scope: "server" };
|
|
19525
|
+
}
|
|
19495
19526
|
return {
|
|
19496
19527
|
listServers: (_r) => callListServers(),
|
|
19497
19528
|
joinServer: callJoinServer,
|
|
19529
|
+
leaveServer: callLeaveServer,
|
|
19498
19530
|
listChannels: callListChannels,
|
|
19499
19531
|
channelMember: callChannelMember,
|
|
19532
|
+
leaveChannel: callLeaveChannel,
|
|
19500
19533
|
inboxPull: callInboxPull,
|
|
19501
19534
|
inboxSnapshot: (_r) => callInboxSnapshot(),
|
|
19502
19535
|
ack: callAck,
|
|
@@ -19507,9 +19540,9 @@ function createProxyServerApi(config2) {
|
|
|
19507
19540
|
attachmentUpload: callUpload,
|
|
19508
19541
|
attachmentDownload: callDownload,
|
|
19509
19542
|
updateProfile: callUpdateProfile,
|
|
19510
|
-
|
|
19511
|
-
|
|
19512
|
-
|
|
19543
|
+
messagePropertySet: callMessagePropertySet,
|
|
19544
|
+
messagePropertyList: callMessagePropertyList,
|
|
19545
|
+
messagePropertyRemove: callMessagePropertyRemove,
|
|
19513
19546
|
listMarks: (_r) => callListMarks(),
|
|
19514
19547
|
friendRequest: callFriendRequest,
|
|
19515
19548
|
listFriends: (_r) => callListFriends(),
|
|
@@ -19556,6 +19589,9 @@ function createDefaultAgentDriverHost(options = {}) {
|
|
|
19556
19589
|
};
|
|
19557
19590
|
}
|
|
19558
19591
|
|
|
19592
|
+
// agent-driver/dist/adapters/claude/index.js
|
|
19593
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
19594
|
+
|
|
19559
19595
|
// agent-driver/dist/controller/process-host.js
|
|
19560
19596
|
import { EventEmitter } from "events";
|
|
19561
19597
|
|
|
@@ -20135,6 +20171,7 @@ class ProcessLane {
|
|
|
20135
20171
|
admissionSequence = 0;
|
|
20136
20172
|
activeTerminalReceipt;
|
|
20137
20173
|
stopPromise;
|
|
20174
|
+
pendingInterrupt;
|
|
20138
20175
|
pendingPromptAdmission;
|
|
20139
20176
|
constructor(driver, ctx, opts = {}) {
|
|
20140
20177
|
this.driver = driver;
|
|
@@ -20174,12 +20211,14 @@ class ProcessLane {
|
|
|
20174
20211
|
try {
|
|
20175
20212
|
spawned = await this.driver.spawn(launchCtx);
|
|
20176
20213
|
} catch (error51) {
|
|
20214
|
+
this.settlePendingInterrupt(false);
|
|
20177
20215
|
this.settlePendingPrompt({ ok: false, reason: "runtime_error", error: String(error51) });
|
|
20178
20216
|
throw error51;
|
|
20179
20217
|
}
|
|
20180
20218
|
const { process: proc } = spawned;
|
|
20181
20219
|
this.process = proc;
|
|
20182
20220
|
this.attachProcess(proc);
|
|
20221
|
+
this.dispatchPendingInterrupt(proc);
|
|
20183
20222
|
this.armPendingPromptTimeout();
|
|
20184
20223
|
if (this.driver.execution.lifetime === "session" && !this.writableStdin(proc)) {
|
|
20185
20224
|
const rejection = this.stdinUnavailableAdmission();
|
|
@@ -20278,6 +20317,7 @@ class ProcessLane {
|
|
|
20278
20317
|
pending.resolve(admission);
|
|
20279
20318
|
}
|
|
20280
20319
|
stop(opts = {}) {
|
|
20320
|
+
this.settlePendingInterrupt(false);
|
|
20281
20321
|
this.settlePendingPrompt({ ok: false, reason: "closed", error: "runtime lane stopped before command admission" });
|
|
20282
20322
|
if (!this.process)
|
|
20283
20323
|
return Promise.resolve();
|
|
@@ -20296,11 +20336,39 @@ class ProcessLane {
|
|
|
20296
20336
|
proc.kill(opts?.signal ?? "SIGTERM");
|
|
20297
20337
|
}
|
|
20298
20338
|
}
|
|
20299
|
-
async interrupt() {
|
|
20339
|
+
async interrupt(input) {
|
|
20300
20340
|
const proc = this.process;
|
|
20301
|
-
if (!proc
|
|
20341
|
+
if (!proc) {
|
|
20342
|
+
if (!this.started)
|
|
20343
|
+
return false;
|
|
20344
|
+
if (this.pendingInterrupt)
|
|
20345
|
+
return this.pendingInterrupt.promise;
|
|
20346
|
+
let resolve;
|
|
20347
|
+
let reject;
|
|
20348
|
+
const promise2 = new Promise((res, rej) => {
|
|
20349
|
+
resolve = res;
|
|
20350
|
+
reject = rej;
|
|
20351
|
+
});
|
|
20352
|
+
this.pendingInterrupt = { input, promise: promise2, resolve, reject };
|
|
20353
|
+
return promise2;
|
|
20354
|
+
}
|
|
20355
|
+
if (this.closed)
|
|
20302
20356
|
return false;
|
|
20303
|
-
return
|
|
20357
|
+
return this.driver.interrupt(input, proc);
|
|
20358
|
+
}
|
|
20359
|
+
dispatchPendingInterrupt(proc) {
|
|
20360
|
+
const pending = this.pendingInterrupt;
|
|
20361
|
+
if (!pending)
|
|
20362
|
+
return;
|
|
20363
|
+
this.pendingInterrupt = undefined;
|
|
20364
|
+
this.driver.interrupt(pending.input, proc).then(pending.resolve, pending.reject);
|
|
20365
|
+
}
|
|
20366
|
+
settlePendingInterrupt(accepted) {
|
|
20367
|
+
const pending = this.pendingInterrupt;
|
|
20368
|
+
if (!pending)
|
|
20369
|
+
return;
|
|
20370
|
+
this.pendingInterrupt = undefined;
|
|
20371
|
+
pending.resolve(accepted);
|
|
20304
20372
|
}
|
|
20305
20373
|
updateSettings(input) {
|
|
20306
20374
|
return this.driver.updateSettings?.(input) ?? Promise.resolve({ status: "unsupported" });
|
|
@@ -20637,11 +20705,40 @@ function tryParseJsonLine(line) {
|
|
|
20637
20705
|
|
|
20638
20706
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
20639
20707
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
20708
|
+
var CLAUDE_RESULT_ERROR_CODES = new Map([
|
|
20709
|
+
["error_max_turns", "claude.error_max_turns"],
|
|
20710
|
+
["error_during_execution", "claude.error_during_execution"],
|
|
20711
|
+
["error_max_budget_usd", "claude.error_max_budget_usd"],
|
|
20712
|
+
["error_max_structured_output_retries", "claude.error_max_structured_output_retries"]
|
|
20713
|
+
]);
|
|
20714
|
+
var CLAUDE_INTERRUPT_TERMINAL_REASONS = new Set(["aborted_streaming", "aborted_tools"]);
|
|
20715
|
+
var CLAUDE_USAGE_COMPONENTS = [
|
|
20716
|
+
"inputTokens",
|
|
20717
|
+
"outputTokens",
|
|
20718
|
+
"cacheReadInputTokens",
|
|
20719
|
+
"cacheCreationInputTokens"
|
|
20720
|
+
];
|
|
20721
|
+
function safeCount(value) {
|
|
20722
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
20723
|
+
}
|
|
20724
|
+
function safeMoney(value) {
|
|
20725
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
20726
|
+
}
|
|
20727
|
+
function safeAdd(left, right) {
|
|
20728
|
+
const total = left + right;
|
|
20729
|
+
return Number.isSafeInteger(total) ? total : null;
|
|
20730
|
+
}
|
|
20731
|
+
function equalCost(left, right) {
|
|
20732
|
+
return Math.abs(left - right) <= Math.max(0.000000000001, Math.abs(right) * 0.000000001);
|
|
20733
|
+
}
|
|
20640
20734
|
|
|
20641
20735
|
class ClaudeEventNormalizer {
|
|
20642
20736
|
turnProtocol;
|
|
20643
20737
|
currentSession = null;
|
|
20644
20738
|
usageProjector = new SettledUsageProjector;
|
|
20739
|
+
claudeUsageSession = null;
|
|
20740
|
+
claudeModelUsageHighWater = new Map;
|
|
20741
|
+
claudeUsageMode = "unknown";
|
|
20645
20742
|
constructor(turnProtocol) {
|
|
20646
20743
|
this.turnProtocol = turnProtocol;
|
|
20647
20744
|
}
|
|
@@ -20708,9 +20805,9 @@ class ClaudeEventNormalizer {
|
|
|
20708
20805
|
out.push({ kind: "assistant_reasoning_completed", text: block.thinking ?? "" });
|
|
20709
20806
|
} else if (block?.type === "text") {
|
|
20710
20807
|
const text2 = block.text ?? "";
|
|
20711
|
-
if (API_ERROR_RE.test(text2))
|
|
20712
|
-
out.push({ kind: "error", message: text2 });
|
|
20713
|
-
else
|
|
20808
|
+
if (API_ERROR_RE.test(text2)) {
|
|
20809
|
+
out.push({ kind: "error", code: "claude.api_error", message: text2 });
|
|
20810
|
+
} else
|
|
20714
20811
|
completedText.push(text2);
|
|
20715
20812
|
} else if (block?.type === "tool_use") {
|
|
20716
20813
|
out.push({ kind: "tool_call", name: block.name ?? "unknown_tool", input: block.input });
|
|
@@ -20736,14 +20833,19 @@ class ClaudeEventNormalizer {
|
|
|
20736
20833
|
}
|
|
20737
20834
|
handleResult(event, out) {
|
|
20738
20835
|
const rawOwner = typeof event.user_message_uuid === "string" && event.user_message_uuid.length > 0 ? event.user_message_uuid : null;
|
|
20739
|
-
const
|
|
20836
|
+
const interruptedTerminal = Boolean(this.turnProtocol && !rawOwner && event.subtype === "error_during_execution" && CLAUDE_INTERRUPT_TERMINAL_REASONS.has(event.terminal_reason));
|
|
20837
|
+
const turnOwner = rawOwner ? this.turnProtocol?.claimResult(rawOwner) ?? (this.turnProtocol ? null : `claude:${rawOwner}`) : interruptedTerminal ? this.turnProtocol.claimInterruptedResult() : null;
|
|
20740
20838
|
if (this.turnProtocol && !turnOwner)
|
|
20741
20839
|
return;
|
|
20742
20840
|
const usage = this.buildUsageTelemetry(event, rawOwner);
|
|
20743
20841
|
if (usage)
|
|
20744
20842
|
out.push(usage);
|
|
20745
|
-
if (event.is_error || event.subtype === "error_during_execution") {
|
|
20746
|
-
out.push({
|
|
20843
|
+
if (!interruptedTerminal && (event.is_error || event.subtype === "error_during_execution")) {
|
|
20844
|
+
out.push({
|
|
20845
|
+
kind: "error",
|
|
20846
|
+
code: CLAUDE_RESULT_ERROR_CODES.get(event.subtype) ?? "claude.result_error",
|
|
20847
|
+
message: String(event.result ?? "Claude runtime error")
|
|
20848
|
+
});
|
|
20747
20849
|
}
|
|
20748
20850
|
out.push({
|
|
20749
20851
|
kind: "turn_end",
|
|
@@ -20755,14 +20857,39 @@ class ClaudeEventNormalizer {
|
|
|
20755
20857
|
return this.turnProtocol?.acceptsTurnWork() ?? true;
|
|
20756
20858
|
}
|
|
20757
20859
|
buildUsageTelemetry(event, rootRequestId) {
|
|
20758
|
-
const u = event?.usage;
|
|
20759
|
-
if (!u)
|
|
20760
|
-
return null;
|
|
20761
20860
|
const backendSessionId = event.session_id ?? this.currentSession;
|
|
20762
20861
|
if (typeof backendSessionId !== "string" || !backendSessionId)
|
|
20763
20862
|
return null;
|
|
20764
20863
|
const providerRecordId = rootRequestId ?? (typeof event.request_id === "string" ? event.request_id : "invocation-result");
|
|
20765
|
-
|
|
20864
|
+
const cumulative = this.prepareClaudeModelUsage(event, backendSessionId);
|
|
20865
|
+
if (cumulative === null)
|
|
20866
|
+
return null;
|
|
20867
|
+
if (cumulative) {
|
|
20868
|
+
const hasDelta = cumulative.input > 0 || cumulative.output > 0 || cumulative.cacheRead > 0 || cumulative.cacheWrite > 0;
|
|
20869
|
+
if (!hasDelta) {
|
|
20870
|
+
this.commitClaudeModelUsage(backendSessionId, cumulative);
|
|
20871
|
+
return null;
|
|
20872
|
+
}
|
|
20873
|
+
const projected2 = this.usageProjector.project({
|
|
20874
|
+
runtime: "claude",
|
|
20875
|
+
backendSessionId,
|
|
20876
|
+
providerRecordId,
|
|
20877
|
+
source: "claude_result_model_usage",
|
|
20878
|
+
input: cumulative.input,
|
|
20879
|
+
output: cumulative.output,
|
|
20880
|
+
cacheRead: cumulative.cacheRead,
|
|
20881
|
+
cacheWrite: cumulative.cacheWrite,
|
|
20882
|
+
inputIncludesCache: false,
|
|
20883
|
+
outputIncludesReasoning: true
|
|
20884
|
+
});
|
|
20885
|
+
if (projected2)
|
|
20886
|
+
this.commitClaudeModelUsage(backendSessionId, cumulative);
|
|
20887
|
+
return projected2;
|
|
20888
|
+
}
|
|
20889
|
+
const u = event?.usage;
|
|
20890
|
+
if (!u)
|
|
20891
|
+
return null;
|
|
20892
|
+
const projected = this.usageProjector.project({
|
|
20766
20893
|
runtime: "claude",
|
|
20767
20894
|
backendSessionId,
|
|
20768
20895
|
providerRecordId,
|
|
@@ -20774,6 +20901,102 @@ class ClaudeEventNormalizer {
|
|
|
20774
20901
|
inputIncludesCache: false,
|
|
20775
20902
|
outputIncludesReasoning: true
|
|
20776
20903
|
});
|
|
20904
|
+
if (projected)
|
|
20905
|
+
this.claudeUsageMode = "legacy";
|
|
20906
|
+
return projected;
|
|
20907
|
+
}
|
|
20908
|
+
prepareClaudeModelUsage(event, backendSessionId) {
|
|
20909
|
+
if (this.claudeUsageMode === "invalid")
|
|
20910
|
+
return null;
|
|
20911
|
+
if (!Object.hasOwn(event ?? {}, "modelUsage")) {
|
|
20912
|
+
if (this.claudeUsageMode !== "model_usage")
|
|
20913
|
+
return;
|
|
20914
|
+
return event?.usage ? this.lockClaudeUsageMode() : null;
|
|
20915
|
+
}
|
|
20916
|
+
if (this.claudeUsageMode === "legacy")
|
|
20917
|
+
return this.lockClaudeUsageMode();
|
|
20918
|
+
if (this.claudeUsageMode === "unknown")
|
|
20919
|
+
this.claudeUsageMode = "model_usage";
|
|
20920
|
+
this.claudeUsageSession ??= backendSessionId;
|
|
20921
|
+
if (this.claudeUsageSession !== null && this.claudeUsageSession !== backendSessionId) {
|
|
20922
|
+
return this.lockClaudeUsageMode();
|
|
20923
|
+
}
|
|
20924
|
+
if (!event.modelUsage || typeof event.modelUsage !== "object" || Array.isArray(event.modelUsage)) {
|
|
20925
|
+
return null;
|
|
20926
|
+
}
|
|
20927
|
+
const entries = Object.entries(event.modelUsage);
|
|
20928
|
+
if (entries.length === 0)
|
|
20929
|
+
return null;
|
|
20930
|
+
const highWater = new Map;
|
|
20931
|
+
let input = 0;
|
|
20932
|
+
let output = 0;
|
|
20933
|
+
let cacheRead = 0;
|
|
20934
|
+
let cacheWrite = 0;
|
|
20935
|
+
let snapshotCost = 0;
|
|
20936
|
+
for (const [model, rawValue] of entries) {
|
|
20937
|
+
if (!model.trim() || !rawValue || typeof rawValue !== "object" || Array.isArray(rawValue)) {
|
|
20938
|
+
return null;
|
|
20939
|
+
}
|
|
20940
|
+
const raw = rawValue;
|
|
20941
|
+
const current = {
|
|
20942
|
+
inputTokens: safeCount(raw.inputTokens),
|
|
20943
|
+
outputTokens: safeCount(raw.outputTokens),
|
|
20944
|
+
cacheReadInputTokens: safeCount(raw.cacheReadInputTokens),
|
|
20945
|
+
cacheCreationInputTokens: safeCount(raw.cacheCreationInputTokens),
|
|
20946
|
+
costUSD: safeMoney(raw.costUSD)
|
|
20947
|
+
};
|
|
20948
|
+
if (Object.values(current).some((value) => value === null)) {
|
|
20949
|
+
return null;
|
|
20950
|
+
}
|
|
20951
|
+
const snapshot = current;
|
|
20952
|
+
const prior = this.claudeModelUsageHighWater.get(model) ?? {
|
|
20953
|
+
inputTokens: 0,
|
|
20954
|
+
outputTokens: 0,
|
|
20955
|
+
cacheReadInputTokens: 0,
|
|
20956
|
+
cacheCreationInputTokens: 0,
|
|
20957
|
+
costUSD: 0
|
|
20958
|
+
};
|
|
20959
|
+
for (const component of CLAUDE_USAGE_COMPONENTS) {
|
|
20960
|
+
if (snapshot[component] < prior[component])
|
|
20961
|
+
return null;
|
|
20962
|
+
}
|
|
20963
|
+
if (snapshot.costUSD < prior.costUSD)
|
|
20964
|
+
return null;
|
|
20965
|
+
const nextInput = safeAdd(input, snapshot.inputTokens - prior.inputTokens);
|
|
20966
|
+
const nextOutput = safeAdd(output, snapshot.outputTokens - prior.outputTokens);
|
|
20967
|
+
const nextCacheRead = safeAdd(cacheRead, snapshot.cacheReadInputTokens - prior.cacheReadInputTokens);
|
|
20968
|
+
const nextCacheWrite = safeAdd(cacheWrite, snapshot.cacheCreationInputTokens - prior.cacheCreationInputTokens);
|
|
20969
|
+
if (nextInput === null || nextOutput === null || nextCacheRead === null || nextCacheWrite === null) {
|
|
20970
|
+
return null;
|
|
20971
|
+
}
|
|
20972
|
+
input = nextInput;
|
|
20973
|
+
output = nextOutput;
|
|
20974
|
+
cacheRead = nextCacheRead;
|
|
20975
|
+
cacheWrite = nextCacheWrite;
|
|
20976
|
+
snapshotCost += snapshot.costUSD;
|
|
20977
|
+
if (!Number.isFinite(snapshotCost))
|
|
20978
|
+
return null;
|
|
20979
|
+
highWater.set(model, snapshot);
|
|
20980
|
+
}
|
|
20981
|
+
for (const model of this.claudeModelUsageHighWater.keys()) {
|
|
20982
|
+
if (!highWater.has(model))
|
|
20983
|
+
return null;
|
|
20984
|
+
}
|
|
20985
|
+
if (Object.hasOwn(event, "total_cost_usd")) {
|
|
20986
|
+
const totalCost = safeMoney(event.total_cost_usd);
|
|
20987
|
+
if (totalCost === null || !equalCost(snapshotCost, totalCost))
|
|
20988
|
+
return null;
|
|
20989
|
+
}
|
|
20990
|
+
return { highWater, input, output, cacheRead, cacheWrite };
|
|
20991
|
+
}
|
|
20992
|
+
commitClaudeModelUsage(backendSessionId, projection) {
|
|
20993
|
+
this.claudeUsageSession ??= backendSessionId;
|
|
20994
|
+
this.claudeModelUsageHighWater = projection.highWater;
|
|
20995
|
+
this.claudeUsageMode = "model_usage";
|
|
20996
|
+
}
|
|
20997
|
+
lockClaudeUsageMode() {
|
|
20998
|
+
this.claudeUsageMode = "invalid";
|
|
20999
|
+
return null;
|
|
20777
21000
|
}
|
|
20778
21001
|
}
|
|
20779
21002
|
|
|
@@ -20900,6 +21123,7 @@ class ClaudeTurnProtocol {
|
|
|
20900
21123
|
segmentOwnerUuid = null;
|
|
20901
21124
|
delivered = new Map;
|
|
20902
21125
|
awaitingFollowOn = false;
|
|
21126
|
+
interruptRequested = false;
|
|
20903
21127
|
finalized = false;
|
|
20904
21128
|
beginTurn() {
|
|
20905
21129
|
const uuid3 = randomUUID4();
|
|
@@ -20908,6 +21132,7 @@ class ClaudeTurnProtocol {
|
|
|
20908
21132
|
this.delivered.clear();
|
|
20909
21133
|
this.delivered.set(uuid3, { acknowledged: false, followOn: false });
|
|
20910
21134
|
this.awaitingFollowOn = false;
|
|
21135
|
+
this.interruptRequested = false;
|
|
20911
21136
|
this.finalized = false;
|
|
20912
21137
|
return this.receipt(uuid3);
|
|
20913
21138
|
}
|
|
@@ -20934,6 +21159,13 @@ class ClaudeTurnProtocol {
|
|
|
20934
21159
|
return false;
|
|
20935
21160
|
return this.delivered.get(this.rootUuid)?.acknowledged === true;
|
|
20936
21161
|
}
|
|
21162
|
+
hasActiveTurn() {
|
|
21163
|
+
return this.rootUuid !== null && !this.finalized;
|
|
21164
|
+
}
|
|
21165
|
+
noteInterruptRequested() {
|
|
21166
|
+
if (this.hasActiveTurn())
|
|
21167
|
+
this.interruptRequested = true;
|
|
21168
|
+
}
|
|
20937
21169
|
claimResult(userMessageUuid) {
|
|
20938
21170
|
if (this.finalized || !this.rootUuid || userMessageUuid !== this.segmentOwnerUuid)
|
|
20939
21171
|
return null;
|
|
@@ -20950,6 +21182,19 @@ class ClaudeTurnProtocol {
|
|
|
20950
21182
|
this.finalized = true;
|
|
20951
21183
|
return this.receipt(this.rootUuid);
|
|
20952
21184
|
}
|
|
21185
|
+
claimInterruptedResult() {
|
|
21186
|
+
if (this.finalized || !this.rootUuid || !this.interruptRequested)
|
|
21187
|
+
return null;
|
|
21188
|
+
const unacknowledged = [...this.delivered.values()].filter((input) => !input.acknowledged);
|
|
21189
|
+
if (unacknowledged.length > 0) {
|
|
21190
|
+
this.awaitingFollowOn = true;
|
|
21191
|
+
for (const input of unacknowledged)
|
|
21192
|
+
input.followOn = true;
|
|
21193
|
+
return null;
|
|
21194
|
+
}
|
|
21195
|
+
this.finalized = true;
|
|
21196
|
+
return this.receipt(this.rootUuid);
|
|
21197
|
+
}
|
|
20953
21198
|
receipt(uuid3) {
|
|
20954
21199
|
return `claude:${uuid3}`;
|
|
20955
21200
|
}
|
|
@@ -20975,7 +21220,9 @@ class ClaudeDriver {
|
|
|
20975
21220
|
};
|
|
20976
21221
|
turnProtocol = new ClaudeTurnProtocol;
|
|
20977
21222
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
21223
|
+
pendingInterrupt;
|
|
20978
21224
|
beginTurn() {
|
|
21225
|
+
this.pendingInterrupt = undefined;
|
|
20979
21226
|
const receipt = this.turnProtocol.beginTurn();
|
|
20980
21227
|
this.eventNormalizer.beginTurn();
|
|
20981
21228
|
return receipt;
|
|
@@ -21014,11 +21261,45 @@ class ClaudeDriver {
|
|
|
21014
21261
|
return { process: proc };
|
|
21015
21262
|
}
|
|
21016
21263
|
normalizeLine(line) {
|
|
21017
|
-
|
|
21264
|
+
const events = this.eventNormalizer.normalizeLine(line);
|
|
21265
|
+
this.flushPendingInterrupt();
|
|
21266
|
+
return events;
|
|
21018
21267
|
}
|
|
21019
21268
|
get currentSessionId() {
|
|
21020
21269
|
return this.eventNormalizer.currentSessionId;
|
|
21021
21270
|
}
|
|
21271
|
+
async interrupt(input, process3) {
|
|
21272
|
+
const stdin = process3.stdin;
|
|
21273
|
+
if (!this.turnProtocol.hasActiveTurn() || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
21274
|
+
return false;
|
|
21275
|
+
this.turnProtocol.noteInterruptRequested();
|
|
21276
|
+
if (!this.turnProtocol.acceptsTurnWork()) {
|
|
21277
|
+
this.pendingInterrupt ??= { input, process: process3 };
|
|
21278
|
+
return true;
|
|
21279
|
+
}
|
|
21280
|
+
this.writeInterrupt(input, process3);
|
|
21281
|
+
return true;
|
|
21282
|
+
}
|
|
21283
|
+
writeInterrupt(input, process3) {
|
|
21284
|
+
process3.stdin.write(JSON.stringify({
|
|
21285
|
+
type: "control_request",
|
|
21286
|
+
request_id: input.requestId ?? randomUUID5(),
|
|
21287
|
+
request: { subtype: "interrupt" }
|
|
21288
|
+
}) + `
|
|
21289
|
+
`);
|
|
21290
|
+
}
|
|
21291
|
+
flushPendingInterrupt() {
|
|
21292
|
+
const pending = this.pendingInterrupt;
|
|
21293
|
+
if (!pending || !this.turnProtocol.acceptsTurnWork())
|
|
21294
|
+
return;
|
|
21295
|
+
this.pendingInterrupt = undefined;
|
|
21296
|
+
const stdin = pending.process.stdin;
|
|
21297
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
21298
|
+
return;
|
|
21299
|
+
try {
|
|
21300
|
+
this.writeInterrupt(pending.input, pending.process);
|
|
21301
|
+
} catch {}
|
|
21302
|
+
}
|
|
21022
21303
|
encodeMessage(text2, sessionId, opts) {
|
|
21023
21304
|
const uuid3 = opts?.mode === "idle" ? this.turnProtocol.rootInputUuid() : this.turnProtocol.steeringInputUuid();
|
|
21024
21305
|
return JSON.stringify({
|
|
@@ -21150,6 +21431,35 @@ import { randomBytes } from "node:crypto";
|
|
|
21150
21431
|
var codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
21151
21432
|
var codexQuotaSourceGeneration = 0;
|
|
21152
21433
|
var codexAccountFingerprint = null;
|
|
21434
|
+
var CODEX_ERROR_INFO_CODES = new Set([
|
|
21435
|
+
"contextWindowExceeded",
|
|
21436
|
+
"sessionBudgetExceeded",
|
|
21437
|
+
"usageLimitExceeded",
|
|
21438
|
+
"serverOverloaded",
|
|
21439
|
+
"cyberPolicy",
|
|
21440
|
+
"misalignmentPolicyViolation",
|
|
21441
|
+
"internalServerError",
|
|
21442
|
+
"unauthorized",
|
|
21443
|
+
"badRequest",
|
|
21444
|
+
"threadRollbackFailed",
|
|
21445
|
+
"sandboxError",
|
|
21446
|
+
"other",
|
|
21447
|
+
"httpConnectionFailed",
|
|
21448
|
+
"responseStreamConnectionFailed",
|
|
21449
|
+
"responseStreamDisconnected",
|
|
21450
|
+
"responseTooManyFailedAttempts",
|
|
21451
|
+
"activeTurnNotSteerable"
|
|
21452
|
+
]);
|
|
21453
|
+
function snakeCase(value) {
|
|
21454
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
21455
|
+
}
|
|
21456
|
+
function codexErrorInfoCode(value, fallback) {
|
|
21457
|
+
const label = typeof value === "string" ? value : value && typeof value === "object" && !Array.isArray(value) ? Object.keys(value)[0] : undefined;
|
|
21458
|
+
return label && CODEX_ERROR_INFO_CODES.has(label) ? `codex.${snakeCase(label)}` : fallback;
|
|
21459
|
+
}
|
|
21460
|
+
function codexRpcErrorCode(value) {
|
|
21461
|
+
return typeof value === "number" && Number.isSafeInteger(value) ? `codex.rpc.${value}` : "codex.rpc_error";
|
|
21462
|
+
}
|
|
21153
21463
|
function rotateCodexQuotaSource() {
|
|
21154
21464
|
codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
21155
21465
|
codexQuotaSourceGeneration += 1;
|
|
@@ -21307,7 +21617,11 @@ class CodexEventNormalizer {
|
|
|
21307
21617
|
return this.replaceQuotaSnapshots(msg.result ?? {});
|
|
21308
21618
|
}
|
|
21309
21619
|
if (msg?.error && msg.id !== undefined) {
|
|
21310
|
-
return [{
|
|
21620
|
+
return [{
|
|
21621
|
+
kind: "error",
|
|
21622
|
+
code: codexRpcErrorCode(msg.error?.code),
|
|
21623
|
+
message: msg.error?.message ?? "Codex RPC error"
|
|
21624
|
+
}];
|
|
21311
21625
|
}
|
|
21312
21626
|
if (msg?.result?.thread?.id) {
|
|
21313
21627
|
return this.adoptAndInit(msg.result.thread.id);
|
|
@@ -21376,20 +21690,26 @@ class CodexEventNormalizer {
|
|
|
21376
21690
|
return [];
|
|
21377
21691
|
this.releaseUsageForTurn(params.threadId, params.turn.id);
|
|
21378
21692
|
if (params.turn.status === "failed") {
|
|
21693
|
+
const error51 = params.turn.error;
|
|
21379
21694
|
return [
|
|
21380
|
-
{
|
|
21695
|
+
{
|
|
21696
|
+
kind: "error",
|
|
21697
|
+
code: codexErrorInfoCode(error51?.codexErrorInfo, "codex.turn_failed"),
|
|
21698
|
+
message: error51?.message ?? "Codex turn failed"
|
|
21699
|
+
},
|
|
21381
21700
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
21382
21701
|
];
|
|
21383
21702
|
}
|
|
21384
|
-
if (params.turn.status === "interrupted") {
|
|
21385
|
-
return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21386
|
-
}
|
|
21387
21703
|
return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21388
21704
|
case "error":
|
|
21389
21705
|
if (params?.willRetry === true) {
|
|
21390
21706
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
21391
21707
|
}
|
|
21392
|
-
return [{
|
|
21708
|
+
return [{
|
|
21709
|
+
kind: "error",
|
|
21710
|
+
code: codexErrorInfoCode(params?.error?.codexErrorInfo, "codex.error"),
|
|
21711
|
+
message: params?.error?.message ?? params?.message ?? "Codex error"
|
|
21712
|
+
}];
|
|
21393
21713
|
case "thread/tokenUsage/updated":
|
|
21394
21714
|
return [];
|
|
21395
21715
|
case "account/rateLimits/updated":
|
|
@@ -21486,42 +21806,46 @@ class CodexEventNormalizer {
|
|
|
21486
21806
|
}
|
|
21487
21807
|
handleItemStarted(params) {
|
|
21488
21808
|
const t = params?.item?.type ?? params?.type;
|
|
21809
|
+
const callId = this.itemCallId(params);
|
|
21810
|
+
const identity = callId ? { callId } : {};
|
|
21489
21811
|
switch (t) {
|
|
21490
21812
|
case "commandExecution":
|
|
21491
|
-
return [{ kind: "tool_call", name: "shell", input: params?.item }];
|
|
21813
|
+
return [{ kind: "tool_call", ...identity, name: "shell", input: params?.item }];
|
|
21492
21814
|
case "contextCompaction":
|
|
21493
21815
|
return [{ kind: "compaction_started" }];
|
|
21494
21816
|
case "enteredReviewMode":
|
|
21495
21817
|
return [{ kind: "review_started" }];
|
|
21496
21818
|
case "fileChange":
|
|
21497
|
-
return [{ kind: "tool_call", name: "file_change", input: normalizeFileChangeInput(params?.item) }];
|
|
21819
|
+
return [{ kind: "tool_call", ...identity, name: "file_change", input: normalizeFileChangeInput(params?.item) }];
|
|
21498
21820
|
case "mcpToolCall":
|
|
21499
|
-
return [{ kind: "tool_call", name: `mcp_${params?.item?.name ?? "tool"}`, input: params?.item }];
|
|
21821
|
+
return [{ kind: "tool_call", ...identity, name: `mcp_${params?.item?.tool ?? params?.item?.name ?? "tool"}`, input: params?.item }];
|
|
21500
21822
|
case "webSearch":
|
|
21501
|
-
return [{ kind: "tool_call", name: "web_search", input: params?.item }];
|
|
21823
|
+
return [{ kind: "tool_call", ...identity, name: "web_search", input: params?.item }];
|
|
21502
21824
|
case "collabAgentToolCall":
|
|
21503
|
-
return [{ kind: "tool_call", name: "collab_tool_call", input: params?.item }];
|
|
21825
|
+
return [{ kind: "tool_call", ...identity, name: "collab_tool_call", input: params?.item }];
|
|
21504
21826
|
default:
|
|
21505
21827
|
return [];
|
|
21506
21828
|
}
|
|
21507
21829
|
}
|
|
21508
21830
|
handleItemCompleted(params) {
|
|
21509
21831
|
const t = params?.item?.type ?? params?.type;
|
|
21832
|
+
const callId = this.itemCallId(params);
|
|
21833
|
+
const identity = callId ? { callId } : {};
|
|
21510
21834
|
switch (t) {
|
|
21511
21835
|
case "commandExecution":
|
|
21512
|
-
return [{ kind: "tool_output", name: "shell" }];
|
|
21836
|
+
return [{ kind: "tool_output", ...identity, name: "shell" }];
|
|
21513
21837
|
case "contextCompaction":
|
|
21514
21838
|
return [{ kind: "compaction_finished" }];
|
|
21515
21839
|
case "exitedReviewMode":
|
|
21516
21840
|
return [{ kind: "review_finished" }];
|
|
21517
21841
|
case "fileChange":
|
|
21518
|
-
return [{ kind: "tool_output", name: "file_change" }];
|
|
21842
|
+
return [{ kind: "tool_output", ...identity, name: "file_change" }];
|
|
21519
21843
|
case "mcpToolCall":
|
|
21520
|
-
return [{ kind: "tool_output", name: `mcp_${params?.item?.name ?? "tool"}` }];
|
|
21844
|
+
return [{ kind: "tool_output", ...identity, name: `mcp_${params?.item?.tool ?? params?.item?.name ?? "tool"}` }];
|
|
21521
21845
|
case "webSearch":
|
|
21522
|
-
return [{ kind: "tool_output", name: "web_search" }];
|
|
21846
|
+
return [{ kind: "tool_output", ...identity, name: "web_search" }];
|
|
21523
21847
|
case "collabAgentToolCall":
|
|
21524
|
-
return [{ kind: "tool_output", name: "collab_tool_call" }];
|
|
21848
|
+
return [{ kind: "tool_output", ...identity, name: "collab_tool_call" }];
|
|
21525
21849
|
case "agentMessage":
|
|
21526
21850
|
return [{ kind: "assistant_message_completed", text: params?.item?.text ?? "" }];
|
|
21527
21851
|
case "reasoning":
|
|
@@ -21530,6 +21854,10 @@ class CodexEventNormalizer {
|
|
|
21530
21854
|
return [];
|
|
21531
21855
|
}
|
|
21532
21856
|
}
|
|
21857
|
+
itemCallId(params) {
|
|
21858
|
+
const value = params?.item?.id ?? params?.itemId;
|
|
21859
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
21860
|
+
}
|
|
21533
21861
|
}
|
|
21534
21862
|
|
|
21535
21863
|
// agent-driver/dist/adapters/codex/home.js
|
|
@@ -22000,6 +22328,16 @@ class CodexDriver {
|
|
|
22000
22328
|
get currentSessionId() {
|
|
22001
22329
|
return this.eventNormalizer.currentSessionId;
|
|
22002
22330
|
}
|
|
22331
|
+
async interrupt(_input, process3) {
|
|
22332
|
+
const threadId = this.eventNormalizer.currentSessionId;
|
|
22333
|
+
const turnId = this.eventNormalizer.currentTurnId;
|
|
22334
|
+
const stdin = process3.stdin;
|
|
22335
|
+
if (!threadId || !turnId || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
22336
|
+
return false;
|
|
22337
|
+
stdin.write(jsonRpcRequest("turn/interrupt", { threadId, turnId }, this.nextRequestId()) + `
|
|
22338
|
+
`);
|
|
22339
|
+
return true;
|
|
22340
|
+
}
|
|
22003
22341
|
buildTurnStart(threadId, text2) {
|
|
22004
22342
|
return jsonRpcRequest("turn/start", { threadId, input: [{ type: "text", text: text2 }] }, this.nextRequestId());
|
|
22005
22343
|
}
|
|
@@ -22255,7 +22593,8 @@ class CursorAcpLane {
|
|
|
22255
22593
|
started = false;
|
|
22256
22594
|
ready = false;
|
|
22257
22595
|
sessionId = null;
|
|
22258
|
-
|
|
22596
|
+
currentPromptRequestId = null;
|
|
22597
|
+
terminalOwner = null;
|
|
22259
22598
|
requestedStopReason;
|
|
22260
22599
|
spawnPromise;
|
|
22261
22600
|
stopPromise;
|
|
@@ -22327,16 +22666,19 @@ class CursorAcpLane {
|
|
|
22327
22666
|
async send(input) {
|
|
22328
22667
|
if (!this.ready || !this.process || this.isClosed())
|
|
22329
22668
|
return { ok: false, reason: "closed" };
|
|
22330
|
-
if (input.mode
|
|
22331
|
-
|
|
22669
|
+
if (input.mode === "busy") {
|
|
22670
|
+
if (this.currentPromptRequestId === null) {
|
|
22671
|
+
return { ok: false, reason: "runtime_busy", error: "Cursor ACP has no active prompt to steer" };
|
|
22672
|
+
}
|
|
22673
|
+
return this.admitPrompt(input.text, "steer");
|
|
22332
22674
|
}
|
|
22333
|
-
if (this.
|
|
22675
|
+
if (this.currentPromptRequestId !== null) {
|
|
22334
22676
|
return { ok: false, reason: "runtime_busy", error: "Cursor ACP prompt is still active" };
|
|
22335
22677
|
}
|
|
22336
22678
|
return this.admitPrompt(input.text);
|
|
22337
22679
|
}
|
|
22338
22680
|
async interrupt(_input) {
|
|
22339
|
-
if (!this.ready || !this.sessionId ||
|
|
22681
|
+
if (!this.ready || !this.sessionId || this.currentPromptRequestId === null || this.isClosed())
|
|
22340
22682
|
return false;
|
|
22341
22683
|
this.write({ jsonrpc: "2.0", method: "session/cancel", params: { sessionId: this.sessionId } });
|
|
22342
22684
|
return true;
|
|
@@ -22344,7 +22686,8 @@ class CursorAcpLane {
|
|
|
22344
22686
|
stop(input = {}) {
|
|
22345
22687
|
this.requestedStopReason ??= input.reason ?? "requested_stop";
|
|
22346
22688
|
this.ready = false;
|
|
22347
|
-
this.
|
|
22689
|
+
this.currentPromptRequestId = null;
|
|
22690
|
+
this.terminalOwner = null;
|
|
22348
22691
|
this.openToolCalls.clear();
|
|
22349
22692
|
this.rejectAllPending(new Error("Cursor ACP lane stopped"));
|
|
22350
22693
|
this.stopPromise ??= this.stopPhysicalOnce(input);
|
|
@@ -22450,19 +22793,22 @@ class CursorAcpLane {
|
|
|
22450
22793
|
throw new CursorAcpIncompatibleError("Cursor ACP did not confirm the exact configured model");
|
|
22451
22794
|
}
|
|
22452
22795
|
}
|
|
22453
|
-
admitPrompt(text2) {
|
|
22796
|
+
admitPrompt(text2, delivery = "prompt") {
|
|
22454
22797
|
if (!this.sessionId)
|
|
22455
22798
|
return { ok: false, reason: "not_ready", error: "Cursor ACP session is not ready" };
|
|
22456
|
-
if (this.activePrompt)
|
|
22457
|
-
return { ok: false, reason: "runtime_busy", error: "Cursor ACP prompt is still active" };
|
|
22458
22799
|
const requestId = ++this.requestSequence;
|
|
22459
|
-
const
|
|
22800
|
+
const prompt = {
|
|
22460
22801
|
requestId,
|
|
22461
22802
|
receipt: `cursor:acp:${requestId}`
|
|
22462
22803
|
};
|
|
22804
|
+
const previousPromptRequestId = this.currentPromptRequestId;
|
|
22805
|
+
const previousTerminalOwner = this.terminalOwner;
|
|
22806
|
+
const previousOpenToolCalls = new Set(this.openToolCalls);
|
|
22807
|
+
if (delivery === "prompt")
|
|
22808
|
+
this.terminalOwner = prompt.receipt;
|
|
22809
|
+
this.currentPromptRequestId = requestId;
|
|
22463
22810
|
this.openToolCalls.clear();
|
|
22464
|
-
this.
|
|
22465
|
-
this.pending.set(requestId, { kind: "prompt", method: "session/prompt", active });
|
|
22811
|
+
this.pending.set(requestId, { kind: "prompt", method: "session/prompt", prompt });
|
|
22466
22812
|
try {
|
|
22467
22813
|
this.write({
|
|
22468
22814
|
jsonrpc: "2.0",
|
|
@@ -22475,41 +22821,51 @@ class CursorAcpLane {
|
|
|
22475
22821
|
});
|
|
22476
22822
|
} catch (error51) {
|
|
22477
22823
|
this.pending.delete(requestId);
|
|
22478
|
-
if (this.
|
|
22479
|
-
this.
|
|
22824
|
+
if (this.currentPromptRequestId === requestId) {
|
|
22825
|
+
this.currentPromptRequestId = previousPromptRequestId;
|
|
22826
|
+
this.terminalOwner = previousTerminalOwner;
|
|
22827
|
+
this.openToolCalls.clear();
|
|
22828
|
+
for (const toolCallId of previousOpenToolCalls)
|
|
22829
|
+
this.openToolCalls.add(toolCallId);
|
|
22830
|
+
}
|
|
22480
22831
|
throw error51;
|
|
22481
22832
|
}
|
|
22482
|
-
return { ok: true, acceptedAs:
|
|
22833
|
+
return { ok: true, acceptedAs: delivery, receipt: prompt.receipt };
|
|
22483
22834
|
}
|
|
22484
|
-
completePrompt(
|
|
22485
|
-
if (this.
|
|
22835
|
+
completePrompt(prompt, value) {
|
|
22836
|
+
if (this.currentPromptRequestId !== prompt.requestId)
|
|
22486
22837
|
return;
|
|
22487
22838
|
const result = record3(value);
|
|
22488
22839
|
if (!result || typeof result.stopReason !== "string" || !PROMPT_STOP_REASONS.has(result.stopReason)) {
|
|
22489
|
-
this.failPrompt(
|
|
22840
|
+
this.failPrompt(prompt, new Error("Cursor ACP prompt response did not contain a supported stopReason"), "cursor.invalid_stop_reason");
|
|
22490
22841
|
return;
|
|
22491
22842
|
}
|
|
22492
|
-
this.
|
|
22843
|
+
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
22844
|
+
this.currentPromptRequestId = null;
|
|
22845
|
+
this.terminalOwner = null;
|
|
22493
22846
|
this.openToolCalls.clear();
|
|
22494
22847
|
this.events.emit("runtime_event", {
|
|
22495
22848
|
kind: "turn_end",
|
|
22496
22849
|
sessionId: this.sessionId ?? undefined,
|
|
22497
|
-
turnOwner:
|
|
22850
|
+
turnOwner: terminalOwner
|
|
22498
22851
|
});
|
|
22499
22852
|
}
|
|
22500
|
-
failPrompt(
|
|
22501
|
-
if (this.
|
|
22853
|
+
failPrompt(prompt, error51, code = "cursor.prompt_failed") {
|
|
22854
|
+
if (this.currentPromptRequestId !== prompt.requestId)
|
|
22502
22855
|
return;
|
|
22503
|
-
this.
|
|
22856
|
+
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
22857
|
+
this.currentPromptRequestId = null;
|
|
22858
|
+
this.terminalOwner = null;
|
|
22504
22859
|
this.openToolCalls.clear();
|
|
22505
22860
|
this.events.emit("runtime_event", {
|
|
22506
22861
|
kind: "error",
|
|
22862
|
+
code,
|
|
22507
22863
|
message: error51 instanceof Error ? error51.message : String(error51)
|
|
22508
22864
|
});
|
|
22509
22865
|
this.events.emit("runtime_event", {
|
|
22510
22866
|
kind: "turn_end",
|
|
22511
22867
|
sessionId: this.sessionId ?? undefined,
|
|
22512
|
-
turnOwner:
|
|
22868
|
+
turnOwner: terminalOwner
|
|
22513
22869
|
});
|
|
22514
22870
|
}
|
|
22515
22871
|
call(method, params) {
|
|
@@ -22595,7 +22951,8 @@ class CursorAcpLane {
|
|
|
22595
22951
|
}
|
|
22596
22952
|
this.processTerminal = true;
|
|
22597
22953
|
this.ready = false;
|
|
22598
|
-
this.
|
|
22954
|
+
this.currentPromptRequestId = null;
|
|
22955
|
+
this.terminalOwner = null;
|
|
22599
22956
|
this.openToolCalls.clear();
|
|
22600
22957
|
this.stopPromise ??= this.stopPhysicalOnce({ reason: "runtime_error", forceAfterMs: 0 });
|
|
22601
22958
|
this.stopPromise.catch(() => {});
|
|
@@ -22613,7 +22970,8 @@ class CursorAcpLane {
|
|
|
22613
22970
|
return;
|
|
22614
22971
|
this.processTerminal = true;
|
|
22615
22972
|
this.ready = false;
|
|
22616
|
-
this.
|
|
22973
|
+
this.currentPromptRequestId = null;
|
|
22974
|
+
this.terminalOwner = null;
|
|
22617
22975
|
this.openToolCalls.clear();
|
|
22618
22976
|
this.rejectAllPending(new Error("Cursor ACP process exited"));
|
|
22619
22977
|
if (this.suppressExit || !this.processActivated)
|
|
@@ -22655,11 +23013,12 @@ class CursorAcpLane {
|
|
|
22655
23013
|
this.pending.delete(id);
|
|
22656
23014
|
if (message2.error !== undefined) {
|
|
22657
23015
|
const payload = record3(message2.error);
|
|
22658
|
-
|
|
23016
|
+
const rpcCode = typeof payload?.code === "number" && Number.isSafeInteger(payload.code) ? payload.code : undefined;
|
|
23017
|
+
this.failPrompt(pending.prompt, new CursorAcpRpcError(pending.method, rpcCode, rpcErrorMessage(message2.error)), rpcCode === undefined ? "cursor.rpc_error" : `cursor.rpc.${rpcCode}`);
|
|
22659
23018
|
} else if (!("result" in message2)) {
|
|
22660
|
-
this.failPrompt(pending.
|
|
23019
|
+
this.failPrompt(pending.prompt, new Error("Cursor ACP response omitted result"), "cursor.invalid_response");
|
|
22661
23020
|
} else {
|
|
22662
|
-
this.completePrompt(pending.
|
|
23021
|
+
this.completePrompt(pending.prompt, message2.result);
|
|
22663
23022
|
}
|
|
22664
23023
|
return;
|
|
22665
23024
|
}
|
|
@@ -22700,7 +23059,7 @@ class CursorAcpLane {
|
|
|
22700
23059
|
const sameSession = payload?.sessionId === this.sessionId;
|
|
22701
23060
|
const options = Array.isArray(payload?.options) ? payload.options.map(record3).filter(Boolean) : [];
|
|
22702
23061
|
const allowOnce = options.find((option) => option.kind === "allow_once" && typeof option.optionId === "string" && option.optionId.trim().length > 0);
|
|
22703
|
-
if (!this.ready ||
|
|
23062
|
+
if (!this.ready || this.currentPromptRequestId === null || !sameSession || !allowOnce) {
|
|
22704
23063
|
this.write({ jsonrpc: "2.0", id, result: { outcome: { outcome: "cancelled" } } });
|
|
22705
23064
|
this.diagnostic("error", "Cursor ACP permission request was not allowed for the active prompt");
|
|
22706
23065
|
return;
|
|
@@ -22724,7 +23083,7 @@ class CursorAcpLane {
|
|
|
22724
23083
|
this.diagnostic("warning", "Cursor ACP emitted an update for a different session");
|
|
22725
23084
|
return;
|
|
22726
23085
|
}
|
|
22727
|
-
if (!this.ready ||
|
|
23086
|
+
if (!this.ready || this.currentPromptRequestId === null) {
|
|
22728
23087
|
this.diagnostic("warning", "Cursor ACP emitted a session update without an active prompt");
|
|
22729
23088
|
return;
|
|
22730
23089
|
}
|
|
@@ -22942,7 +23301,11 @@ function parseModelRef(model) {
|
|
|
22942
23301
|
function messageFromError(value) {
|
|
22943
23302
|
const payload = record4(value);
|
|
22944
23303
|
const message2 = typeof payload?.message === "string" && payload.message.trim() ? payload.message : undefined;
|
|
22945
|
-
return message2
|
|
23304
|
+
return message2 ?? "OpenCode reported an inconsistent turn outcome";
|
|
23305
|
+
}
|
|
23306
|
+
function codeFromError(value) {
|
|
23307
|
+
const payload = record4(value);
|
|
23308
|
+
return payload?.type === "unknown" ? "opencode.unknown" : "opencode.step_failed";
|
|
22946
23309
|
}
|
|
22947
23310
|
|
|
22948
23311
|
class OpenCodeServiceLane {
|
|
@@ -23610,7 +23973,10 @@ class OpenCodeServiceLane {
|
|
|
23610
23973
|
root.outcomes.push({
|
|
23611
23974
|
seq,
|
|
23612
23975
|
ok: successful,
|
|
23613
|
-
...!successful ? {
|
|
23976
|
+
...!successful ? {
|
|
23977
|
+
code: "opencode.unsupported_finish",
|
|
23978
|
+
message: "OpenCode reported an unsupported final step outcome"
|
|
23979
|
+
} : {}
|
|
23614
23980
|
});
|
|
23615
23981
|
}
|
|
23616
23982
|
const tokens = record4(data.tokens);
|
|
@@ -23639,7 +24005,12 @@ class OpenCodeServiceLane {
|
|
|
23639
24005
|
break;
|
|
23640
24006
|
}
|
|
23641
24007
|
case "session.next.step.failed":
|
|
23642
|
-
root.outcomes.push({
|
|
24008
|
+
root.outcomes.push({
|
|
24009
|
+
seq,
|
|
24010
|
+
ok: false,
|
|
24011
|
+
code: codeFromError(data.error),
|
|
24012
|
+
message: messageFromError(data.error)
|
|
24013
|
+
});
|
|
23643
24014
|
break;
|
|
23644
24015
|
default:
|
|
23645
24016
|
break;
|
|
@@ -23819,11 +24190,11 @@ class OpenCodeServiceLane {
|
|
|
23819
24190
|
return;
|
|
23820
24191
|
const outcome = root.outcomes.filter((item) => item.seq > maxAdmission).sort((left, right) => left.seq - right.seq).at(-1);
|
|
23821
24192
|
if (!root.interrupted && !outcome) {
|
|
23822
|
-
this.settleRoot(root, false, "OpenCode drain settled without a durable turn outcome");
|
|
24193
|
+
this.settleRoot(root, false, "OpenCode drain settled without a durable turn outcome", "opencode.missing_outcome");
|
|
23823
24194
|
return;
|
|
23824
24195
|
}
|
|
23825
24196
|
if (outcome && !outcome.ok) {
|
|
23826
|
-
this.settleRoot(root, false, outcome.message ?? "OpenCode turn failed");
|
|
24197
|
+
this.settleRoot(root, false, outcome.message ?? "OpenCode turn failed", outcome.code ?? "opencode.turn_failed");
|
|
23827
24198
|
return;
|
|
23828
24199
|
}
|
|
23829
24200
|
this.settleRoot(root, true);
|
|
@@ -23849,7 +24220,7 @@ class OpenCodeServiceLane {
|
|
|
23849
24220
|
barrierStillCurrent(root, identity, generation) {
|
|
23850
24221
|
return this.activeRoot === root && root.generation === generation && root.pendingAdmissions === 0 && !root.interruptPending && this.isIdentity(identity) && this.identityMatches();
|
|
23851
24222
|
}
|
|
23852
|
-
settleRoot(root, success2, message2) {
|
|
24223
|
+
settleRoot(root, success2, message2, code = "opencode.turn_failed") {
|
|
23853
24224
|
if (this.activeRoot !== root)
|
|
23854
24225
|
return;
|
|
23855
24226
|
this.activeRoot = null;
|
|
@@ -23857,6 +24228,7 @@ class OpenCodeServiceLane {
|
|
|
23857
24228
|
if (!success2) {
|
|
23858
24229
|
this.events.emit("runtime_event", {
|
|
23859
24230
|
kind: "error",
|
|
24231
|
+
code,
|
|
23860
24232
|
message: message2 ?? "OpenCode turn failed"
|
|
23861
24233
|
});
|
|
23862
24234
|
}
|
|
@@ -24372,7 +24744,11 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
24372
24744
|
return [{ kind: "assistant_message_completed", text: d.content ?? "" }];
|
|
24373
24745
|
}
|
|
24374
24746
|
case "error":
|
|
24375
|
-
return [{
|
|
24747
|
+
return [{
|
|
24748
|
+
kind: "error",
|
|
24749
|
+
code: "pi.message_error",
|
|
24750
|
+
message: d.error?.errorMessage ?? "Pi error"
|
|
24751
|
+
}];
|
|
24376
24752
|
default:
|
|
24377
24753
|
return [];
|
|
24378
24754
|
}
|
|
@@ -24652,7 +25028,7 @@ var capabilities = {
|
|
|
24652
25028
|
commandOverride: true,
|
|
24653
25029
|
resume: "by_id",
|
|
24654
25030
|
sessionLifetime: "persistent",
|
|
24655
|
-
midTurnDelivery: "
|
|
25031
|
+
midTurnDelivery: "steer",
|
|
24656
25032
|
interrupt: true
|
|
24657
25033
|
},
|
|
24658
25034
|
opencode: {
|
|
@@ -24960,7 +25336,9 @@ class LogicalAgentSession {
|
|
|
24960
25336
|
interruptedTurnId;
|
|
24961
25337
|
processTurnEnded = false;
|
|
24962
25338
|
stopRequestId;
|
|
24963
|
-
|
|
25339
|
+
anonymousOutstandingToolUses = 0;
|
|
25340
|
+
outstandingToolCallIds = new Set;
|
|
25341
|
+
toolLifecycleMismatchCount = 0;
|
|
24964
25342
|
compacting = false;
|
|
24965
25343
|
reviewing = false;
|
|
24966
25344
|
steeringDeliveries = new Set;
|
|
@@ -25150,6 +25528,9 @@ class LogicalAgentSession {
|
|
|
25150
25528
|
queueDwellCount: this.metricValue(this.queueDwellCount),
|
|
25151
25529
|
queueDwellTotalMs: this.metricValue(this.queueDwellTotalMs),
|
|
25152
25530
|
sseReconnectCount: this.metricValue(this.sseReconnectCount),
|
|
25531
|
+
outstandingToolUses: this.outstandingToolUseCount(),
|
|
25532
|
+
anonymousOutstandingToolUses: this.metricValue(this.anonymousOutstandingToolUses),
|
|
25533
|
+
toolLifecycleMismatchCount: this.metricValue(this.toolLifecycleMismatchCount),
|
|
25153
25534
|
resumeOutcome: this.resumeOutcome,
|
|
25154
25535
|
terminalOwnerKind: this.adapter.execution.terminalOwnership
|
|
25155
25536
|
}
|
|
@@ -25469,15 +25850,36 @@ class LogicalAgentSession {
|
|
|
25469
25850
|
}
|
|
25470
25851
|
return;
|
|
25471
25852
|
case "tool_call":
|
|
25472
|
-
|
|
25473
|
-
|
|
25474
|
-
|
|
25853
|
+
if (!turnId) {
|
|
25854
|
+
this.toolLifecycleMismatchCount += 1;
|
|
25855
|
+
return;
|
|
25856
|
+
}
|
|
25857
|
+
if (!this.startToolUse(event.callId))
|
|
25858
|
+
return;
|
|
25859
|
+
const startedCallId = this.toolCallId(event.callId);
|
|
25860
|
+
this.emit({
|
|
25861
|
+
type: "tool_started",
|
|
25862
|
+
turnId,
|
|
25863
|
+
...startedCallId ? { callId: startedCallId } : {},
|
|
25864
|
+
name: event.name,
|
|
25865
|
+
input: jsonValue(event.input)
|
|
25866
|
+
});
|
|
25475
25867
|
return;
|
|
25476
25868
|
case "tool_output":
|
|
25477
|
-
|
|
25478
|
-
|
|
25479
|
-
|
|
25480
|
-
|
|
25869
|
+
if (!turnId) {
|
|
25870
|
+
this.toolLifecycleMismatchCount += 1;
|
|
25871
|
+
return;
|
|
25872
|
+
}
|
|
25873
|
+
if (!this.finishToolUse(event.callId))
|
|
25874
|
+
return;
|
|
25875
|
+
const finishedCallId = this.toolCallId(event.callId);
|
|
25876
|
+
this.emit({
|
|
25877
|
+
type: "tool_finished",
|
|
25878
|
+
turnId,
|
|
25879
|
+
...finishedCallId ? { callId: finishedCallId } : {},
|
|
25880
|
+
name: event.name
|
|
25881
|
+
});
|
|
25882
|
+
if (this.outstandingToolUseCount() === 0 && !this.toolBoundaryFlushDisabled)
|
|
25481
25883
|
this.flushSafeBoundaryQueue();
|
|
25482
25884
|
return;
|
|
25483
25885
|
case "compaction_started":
|
|
@@ -25533,7 +25935,7 @@ class LogicalAgentSession {
|
|
|
25533
25935
|
}
|
|
25534
25936
|
case "error":
|
|
25535
25937
|
this.toolBoundaryFlushDisabled = true;
|
|
25536
|
-
this.turnError = driverError("process", "runtime_error", event.message, true);
|
|
25938
|
+
this.turnError = driverError("process", stableErrorCode(event.code, "runtime_error"), event.message, true);
|
|
25537
25939
|
this.emit({
|
|
25538
25940
|
type: "diagnostic",
|
|
25539
25941
|
turnId,
|
|
@@ -25620,7 +26022,7 @@ class LogicalAgentSession {
|
|
|
25620
26022
|
this.activeTurn = undefined;
|
|
25621
26023
|
this.turnError = undefined;
|
|
25622
26024
|
this.interruptedTurnId = undefined;
|
|
25623
|
-
this.
|
|
26025
|
+
this.clearOutstandingToolUses();
|
|
25624
26026
|
this.compacting = false;
|
|
25625
26027
|
this.reviewing = false;
|
|
25626
26028
|
this.toolBoundaryFlushDisabled = false;
|
|
@@ -25644,7 +26046,7 @@ class LogicalAgentSession {
|
|
|
25644
26046
|
return this.safeBoundaryFlush;
|
|
25645
26047
|
}
|
|
25646
26048
|
canFlushSafeBoundaryQueue() {
|
|
25647
|
-
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.
|
|
26049
|
+
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.outstandingToolUseCount() === 0 && !this.compacting && !this.reviewing && this.activeTurn !== undefined && this.lane !== null && this.queued.length > 0;
|
|
25648
26050
|
}
|
|
25649
26051
|
async drainSafeBoundaryQueue() {
|
|
25650
26052
|
while (this.canFlushSafeBoundaryQueue()) {
|
|
@@ -25825,7 +26227,7 @@ class LogicalAgentSession {
|
|
|
25825
26227
|
return "compacting";
|
|
25826
26228
|
if (this.reviewing)
|
|
25827
26229
|
return "reviewing";
|
|
25828
|
-
if (this.
|
|
26230
|
+
if (this.outstandingToolUseCount() > 0)
|
|
25829
26231
|
return "tool_wait";
|
|
25830
26232
|
if (this.activeTurn)
|
|
25831
26233
|
return "working";
|
|
@@ -25835,6 +26237,46 @@ class LogicalAgentSession {
|
|
|
25835
26237
|
const now = this.host.now();
|
|
25836
26238
|
return Number.isFinite(now) && now >= 0 ? now : 0;
|
|
25837
26239
|
}
|
|
26240
|
+
outstandingToolUseCount() {
|
|
26241
|
+
return this.anonymousOutstandingToolUses + this.outstandingToolCallIds.size;
|
|
26242
|
+
}
|
|
26243
|
+
startToolUse(rawCallId) {
|
|
26244
|
+
const callId = this.toolCallId(rawCallId);
|
|
26245
|
+
if (!callId) {
|
|
26246
|
+
this.anonymousOutstandingToolUses += 1;
|
|
26247
|
+
return true;
|
|
26248
|
+
}
|
|
26249
|
+
if (this.outstandingToolCallIds.has(callId)) {
|
|
26250
|
+
this.toolLifecycleMismatchCount += 1;
|
|
26251
|
+
return false;
|
|
26252
|
+
}
|
|
26253
|
+
this.outstandingToolCallIds.add(callId);
|
|
26254
|
+
return true;
|
|
26255
|
+
}
|
|
26256
|
+
finishToolUse(rawCallId) {
|
|
26257
|
+
const callId = this.toolCallId(rawCallId);
|
|
26258
|
+
if (!callId) {
|
|
26259
|
+
if (this.anonymousOutstandingToolUses === 0) {
|
|
26260
|
+
this.toolLifecycleMismatchCount += 1;
|
|
26261
|
+
return false;
|
|
26262
|
+
}
|
|
26263
|
+
this.anonymousOutstandingToolUses -= 1;
|
|
26264
|
+
return true;
|
|
26265
|
+
}
|
|
26266
|
+
if (!this.outstandingToolCallIds.delete(callId)) {
|
|
26267
|
+
this.toolLifecycleMismatchCount += 1;
|
|
26268
|
+
return false;
|
|
26269
|
+
}
|
|
26270
|
+
return true;
|
|
26271
|
+
}
|
|
26272
|
+
clearOutstandingToolUses() {
|
|
26273
|
+
this.anonymousOutstandingToolUses = 0;
|
|
26274
|
+
this.outstandingToolCallIds.clear();
|
|
26275
|
+
}
|
|
26276
|
+
toolCallId(rawCallId) {
|
|
26277
|
+
const callId = rawCallId?.trim();
|
|
26278
|
+
return callId && callId.length <= 1024 ? callId : undefined;
|
|
26279
|
+
}
|
|
25838
26280
|
metricValue(value) {
|
|
25839
26281
|
return Number.isFinite(value) && value >= 0 ? value : 0;
|
|
25840
26282
|
}
|
|
@@ -27473,10 +27915,11 @@ var DEFAULT_CAPABILITY_RESOLVER = (method, pathname) => {
|
|
|
27473
27915
|
const isMessagesDoor = /\/channels\/[^/]+\/messages(\/|$|\?)/.test(pathname);
|
|
27474
27916
|
if (isMessagesDoor)
|
|
27475
27917
|
return method === "GET" ? "read" : "send";
|
|
27918
|
+
if (/\/messages\/[^/]+\/properties(\/|$|\?)/.test(pathname)) {
|
|
27919
|
+
return method === "GET" ? "read" : "send";
|
|
27920
|
+
}
|
|
27476
27921
|
if (/\/messages\/[^/]+\/reactions\//.test(pathname))
|
|
27477
27922
|
return "send";
|
|
27478
|
-
if ((method === "PUT" || method === "DELETE") && /\/messages\/[^/]+\/marks(\/|$|\?)/.test(pathname))
|
|
27479
|
-
return "send";
|
|
27480
27923
|
if (method === "GET" && /\/users\/me\/marks(\/|$|\?)/.test(pathname))
|
|
27481
27924
|
return "read";
|
|
27482
27925
|
if (method === "GET" && /\/messages\/[^/]+(\?|$)/.test(pathname))
|
|
@@ -27517,6 +27960,12 @@ function isCanonicalChannelScope(channel2) {
|
|
|
27517
27960
|
return false;
|
|
27518
27961
|
}
|
|
27519
27962
|
}
|
|
27963
|
+
function propertyAuditMetadata(method, pathname, requestUrl) {
|
|
27964
|
+
if (method !== "PUT" && method !== "DELETE" || !/^\/api\/community\/messages\/[^/]+\/properties$/.test(pathname))
|
|
27965
|
+
return;
|
|
27966
|
+
const type = new URL2(requestUrl, "http://placeholder").searchParams.get("type");
|
|
27967
|
+
return type === "emoji" || type === "tag" || type === "mark" ? { propertyType: type } : undefined;
|
|
27968
|
+
}
|
|
27520
27969
|
function parseLocalMessageReminderBody(body, agentId) {
|
|
27521
27970
|
let value;
|
|
27522
27971
|
try {
|
|
@@ -27655,7 +28104,12 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
27655
28104
|
}
|
|
27656
28105
|
if (onProxyRequest) {
|
|
27657
28106
|
try {
|
|
27658
|
-
|
|
28107
|
+
const method = req.method ?? "GET";
|
|
28108
|
+
const metadata = propertyAuditMetadata(method, pathname, req.url ?? pathname);
|
|
28109
|
+
if (metadata)
|
|
28110
|
+
onProxyRequest(reg.agentId, method, pathname, metadata);
|
|
28111
|
+
else
|
|
28112
|
+
onProxyRequest(reg.agentId, method, pathname);
|
|
27659
28113
|
} catch {}
|
|
27660
28114
|
}
|
|
27661
28115
|
const outHeaders = { ...req.headers };
|
|
@@ -27938,6 +28392,7 @@ function reduceManager(state, event) {
|
|
|
27938
28392
|
if ((lease.state === "active" || lease.state === "suspect_active") && lease.outstandingToolUses !== undefined) {
|
|
27939
28393
|
const unblockedLease = { ...lease };
|
|
27940
28394
|
delete unblockedLease.outstandingToolUses;
|
|
28395
|
+
delete unblockedLease.outstandingToolCallIds;
|
|
27941
28396
|
a.execution.lease = unblockedLease;
|
|
27942
28397
|
}
|
|
27943
28398
|
});
|
|
@@ -28198,26 +28653,40 @@ function onTurnToolLifecycle(state, event, lifecycle) {
|
|
|
28198
28653
|
const matchesTerminal = lifecycle === "started" && current.state === "none" && current.lastTerminal !== null && sameIdentity(current.lastTerminal.identity, identity);
|
|
28199
28654
|
if (!matchesActive && !matchesTerminal)
|
|
28200
28655
|
return { state, effects: [] };
|
|
28201
|
-
if (lifecycle === "finished" && matchesActive && (current.outstandingToolUses ?? 0) === 0) {
|
|
28202
|
-
return { state, effects: [] };
|
|
28203
|
-
}
|
|
28204
28656
|
return mutate(state, event.agentId, (agent2) => {
|
|
28205
28657
|
if (!matchesSession(agent2, event.sessionInstanceId))
|
|
28206
28658
|
return;
|
|
28207
28659
|
const lease = agent2.execution.lease;
|
|
28660
|
+
const callId = normalizedToolCallId(event.callId);
|
|
28208
28661
|
if ((lease.state === "active" || lease.state === "suspect_active") && sameIdentity(lease.identity, identity)) {
|
|
28209
|
-
const
|
|
28662
|
+
const identified = new Set(lease.outstandingToolCallIds ?? []);
|
|
28663
|
+
const currentCount = lease.outstandingToolUses ?? 0;
|
|
28664
|
+
const anonymousCount = Math.max(0, currentCount - identified.size);
|
|
28665
|
+
if (lifecycle === "started") {
|
|
28666
|
+
if (callId && identified.has(callId))
|
|
28667
|
+
return;
|
|
28668
|
+
if (callId)
|
|
28669
|
+
identified.add(callId);
|
|
28670
|
+
} else if (callId) {
|
|
28671
|
+
if (!identified.delete(callId))
|
|
28672
|
+
return;
|
|
28673
|
+
} else if (anonymousCount === 0) {
|
|
28674
|
+
return;
|
|
28675
|
+
}
|
|
28676
|
+
const outstandingToolUses = currentCount + (lifecycle === "started" ? 1 : -1);
|
|
28210
28677
|
if (outstandingToolUses > 0) {
|
|
28211
28678
|
agent2.execution.lease = {
|
|
28212
28679
|
...lease,
|
|
28213
28680
|
lastWorkAt: event.nowMs,
|
|
28214
28681
|
nativeDeadlineAt: event.nowMs + agent2.turnSilence.normalBudgetMs,
|
|
28215
28682
|
recoveryExtensionsUsed: 0,
|
|
28216
|
-
outstandingToolUses
|
|
28683
|
+
outstandingToolUses,
|
|
28684
|
+
...identified.size > 0 ? { outstandingToolCallIds: [...identified] } : {}
|
|
28217
28685
|
};
|
|
28218
28686
|
} else {
|
|
28219
28687
|
const unblockedLease = { ...lease };
|
|
28220
28688
|
delete unblockedLease.outstandingToolUses;
|
|
28689
|
+
delete unblockedLease.outstandingToolCallIds;
|
|
28221
28690
|
agent2.execution.lease = {
|
|
28222
28691
|
...unblockedLease,
|
|
28223
28692
|
lastWorkAt: event.nowMs,
|
|
@@ -28236,6 +28705,7 @@ function onTurnToolLifecycle(state, event, lifecycle) {
|
|
|
28236
28705
|
nativeDeadlineAt: event.nowMs + agent2.turnSilence.normalBudgetMs,
|
|
28237
28706
|
recoveryExtensionsUsed: 0,
|
|
28238
28707
|
outstandingToolUses: 1,
|
|
28708
|
+
...callId ? { outstandingToolCallIds: [callId] } : {},
|
|
28239
28709
|
reason: "work_after_terminal"
|
|
28240
28710
|
};
|
|
28241
28711
|
}
|
|
@@ -28399,6 +28869,10 @@ function identityOf(event) {
|
|
|
28399
28869
|
function sameIdentity(left, right) {
|
|
28400
28870
|
return left.sessionInstanceId === right.sessionInstanceId && left.turnId === right.turnId;
|
|
28401
28871
|
}
|
|
28872
|
+
function normalizedToolCallId(rawCallId) {
|
|
28873
|
+
const callId = rawCallId?.trim();
|
|
28874
|
+
return callId && callId.length <= 1024 ? callId : undefined;
|
|
28875
|
+
}
|
|
28402
28876
|
function leaseIsWorking(lease) {
|
|
28403
28877
|
return lease.state === "active" || lease.state === "suspect_active";
|
|
28404
28878
|
}
|
|
@@ -28620,13 +29094,13 @@ function cliCommandsSection() {
|
|
|
28620
29094
|
"",
|
|
28621
29095
|
"### Messaging",
|
|
28622
29096
|
"",
|
|
28623
|
-
`1. \`${CLI} inbox pull\` — fetch unread messages
|
|
29097
|
+
`1. \`${CLI} inbox pull\` — fetch unread messages and advance their read waterlines.`,
|
|
28624
29098
|
`2. \`${CLI} message send --target <ref> --remind-after <0|Nm|Nh> --stdin\` — send to a ` + `channel, DM, or thread. ` + `The body is required through \`--stdin\` and limited to 1 KiB of UTF-8. ` + `Attach uploaded files with \`--attachment <id>\` (repeatable, order matters). ` + `\`--remind-after\` accepts \`0\`, or a whole-number duration from \`1m\` to \`24h\`.`,
|
|
28625
29099
|
`3. \`${CLI} message attachment upload --target <ref> --file <path>\` — upload a file; ` + `returns an id stable across pending→persisted.`,
|
|
28626
29100
|
`4. \`${CLI} message attachment download --id <id> [--out <path>]\` — download any ` + `attachment you can see (or your own pending uploads).`,
|
|
28627
|
-
`5. \`${CLI} message
|
|
28628
|
-
`6. \`${CLI} message
|
|
28629
|
-
`7. \`${CLI} message
|
|
29101
|
+
`5. \`${CLI} message property set --target <full-message-ref> --json <json>\` — add a supported property value to a message.`,
|
|
29102
|
+
`6. \`${CLI} message property list --target <full-message-ref>\` — list the message's current properties and supported capabilities.`,
|
|
29103
|
+
`7. \`${CLI} message property remove --target <full-message-ref> --json <json>\` — remove a supported property value from a message.`,
|
|
28630
29104
|
`8. \`${CLI} message mark list\` — list every currently visible marked message with its full content.`,
|
|
28631
29105
|
"",
|
|
28632
29106
|
"### Servers",
|
|
@@ -28634,12 +29108,14 @@ function cliCommandsSection() {
|
|
|
28634
29108
|
`1. \`${CLI} server list\` — list your servers.`,
|
|
28635
29109
|
`2. \`${CLI} server member --server <name#discriminator>\` — list a server's members.`,
|
|
28636
29110
|
`3. \`${CLI} server join --invite <link>\` — join via invite link or token.`,
|
|
29111
|
+
`4. \`${CLI} server leave --server <name#NNNN>\` — leave a server you belong to. A server owner cannot leave.`,
|
|
28637
29112
|
"",
|
|
28638
29113
|
"### Channels",
|
|
28639
29114
|
"",
|
|
28640
29115
|
`1. \`${CLI} channel list --server <name#discriminator>\` — list top-level channels, grouped by ` + `category; each is marked \`public\` or \`private\`.`,
|
|
28641
29116
|
`2. \`${CLI} channel history --channel <ref>\` — read a channel's or thread's past messages ` + `(the context you weren't awake for). Page with \`--before N\` / \`--after N\` (seq N as ` + "anchor), `--around N` to center on a message, `--limit N` for page size.",
|
|
28642
29117
|
`3. \`${CLI} channel member --channel <ref>\` — roster of a channel or thread. A private ` + `channel/forum returns its concrete member list; a public one returns a hint pointing at ` + `\`${CLI} server member\` (its audience is the whole server).`,
|
|
29118
|
+
`4. \`${CLI} channel leave --channel <ref>\` — leave a thread or private channel/forum. Public channels require leaving their server; DMs cannot be left.`,
|
|
28643
29119
|
"",
|
|
28644
29120
|
"### Friends",
|
|
28645
29121
|
"",
|
|
@@ -28692,6 +29168,15 @@ function messagingSection() {
|
|
|
28692
29168
|
"Reply where the message came from. Post results in the channel that owns the topic. " + "When uncertain, read history (below) or DM the relevant people.",
|
|
28693
29169
|
"Write every message body in the stdin/heredoc block; never place it directly on the command line.",
|
|
28694
29170
|
"",
|
|
29171
|
+
"### Message properties",
|
|
29172
|
+
"",
|
|
29173
|
+
`Message properties are capabilities determined by the target message's channel type. \`${CLI} ` + "message property list --target <full-message-ref>` returns its current values and supported `capabilities`.",
|
|
29174
|
+
"",
|
|
29175
|
+
`- \`emoji\` works on text-channel, DM, and thread messages. Set or remove your own reaction with ` + `\`{"type":"emoji","value":"\uD83D\uDC4D"}\`; \`list\` shows everyone who reacted. Add: ` + `\`${CLI} message property set --target <full-message-ref> --json '{"type":"emoji","value":"\uD83D\uDC4D"}'\`.`,
|
|
29176
|
+
`- \`tag\` works on forum opener messages. Set or remove named tags with ` + `\`{"type":"tag","value":["bug","ready"]}\`. A forum reply is a thread message, so it ` + `supports \`emoji\`, not \`tag\`. Add: \`${CLI} message property set --target ` + `<full-message-ref> --json '{"type":"tag","value":["bug"]}'\`.`,
|
|
29177
|
+
`- \`mark\` works on every message. Mark outstanding work with \`{"type":"mark","value":true}\`: ` + `\`${CLI} message property set --target <full-message-ref> --json ` + `'{"type":"mark","value":true}'\`. Clear it with the same JSON through ` + `\`message property remove\`. Use \`${CLI} message mark list\` for the one-shot global view ` + `of all currently visible marked messages.`,
|
|
29178
|
+
"- `archived` is a reserved tag meaning the forum post is complete. Setting it hides the " + "post from the normal forum feed; removing it reopens the post.",
|
|
29179
|
+
"",
|
|
28695
29180
|
"### Context refs",
|
|
28696
29181
|
"",
|
|
28697
29182
|
"Path-style refs:",
|
|
@@ -28804,6 +29289,7 @@ function criticalRulesSection() {
|
|
|
28804
29289
|
`- **\`${CLI}\` is the only way to communicate.** Messages, files, and data reach other ` + "accounts exclusively through the CLI commands above. Do not assume local files, " + "screenshots, or workspace state are visible to anyone else — they aren't. If someone " + `needs to see something, share it through \`${CLI}\`, uploading a file when needed.`,
|
|
28805
29290
|
"- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
|
|
28806
29291
|
"- **Match the sender's language.** Reply in the language they wrote in.",
|
|
29292
|
+
`- **Leaving a scope is destructive.** Use \`${CLI} channel leave\` or \`${CLI} server leave\` only after your owner explicitly asks you to leave that exact scope.`,
|
|
28807
29293
|
"- **Channel alignment**: you can't send to a channel with unread messages. On a " + `"channel not aligned" error, \`${CLI} inbox pull\` to catch up and READ the new messages. ` + "Judge if your message is still needed or overlaps with what just landed. Adjust or skip; " + "don't mechanically resend."
|
|
28808
29294
|
].join(`
|
|
28809
29295
|
`);
|
|
@@ -28816,7 +29302,7 @@ function executionModelSection() {
|
|
|
28816
29302
|
"",
|
|
28817
29303
|
"On wake, restore durable context from `memory.md` and the context timeline, then pull your inbox. " + "Follow *Outstanding work marks* below before taking new work.",
|
|
28818
29304
|
"",
|
|
28819
|
-
"`inbox pull` advances your read waterline
|
|
29305
|
+
"`inbox pull` advances your read waterline — pulled messages won't come back in a " + "future pull. A task-bearing message stays durable through its server mark even after the " + "read waterline advances."
|
|
28820
29306
|
].join(`
|
|
28821
29307
|
`);
|
|
28822
29308
|
}
|
|
@@ -28888,9 +29374,9 @@ function workspaceMemorySection(config2) {
|
|
|
28888
29374
|
"",
|
|
28889
29375
|
"### Outstanding work marks",
|
|
28890
29376
|
"",
|
|
28891
|
-
"Marks are the durable work queue. If a message requires work beyond an immediate reply, " + `acknowledge it, then run \`${CLI} message
|
|
29377
|
+
"Marks are the durable work queue. If a message requires work beyond an immediate reply, " + `acknowledge it, then run \`${CLI} message property set --target <full-message-ref> ` + `--json '{"type":"mark","value":true}'\` before ` + "starting or queuing. Do not mark a message you answer immediately.",
|
|
28892
29378
|
"",
|
|
28893
|
-
"Keep it marked while the work is active, queued, or blocked; report blockers where the task " + `came from. Run \`${CLI} message
|
|
29379
|
+
"Keep it marked while the work is active, queued, or blocked; report blockers where the task " + `came from. Run \`${CLI} message property remove --target <full-message-ref> ` + `--json '{"type":"mark","value":true}'\` only after ` + "sending the result, or when the request is cancelled or superseded and nothing remains.",
|
|
28894
29380
|
"",
|
|
28895
29381
|
"If `inbox pull` returns a `markedReminder`, run " + `\`${CLI} message mark list\` before taking new work. Do not copy marked tasks into local files.`
|
|
28896
29382
|
].join(`
|
|
@@ -28943,7 +29429,7 @@ function toLocalISO(iso) {
|
|
|
28943
29429
|
}
|
|
28944
29430
|
|
|
28945
29431
|
// src/manager/managerRuntime.ts
|
|
28946
|
-
import { randomUUID as
|
|
29432
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
28947
29433
|
var SESSION_STOP_GRACE_MS2 = 2000;
|
|
28948
29434
|
function normalizeTerminationCause(value) {
|
|
28949
29435
|
return value === "runtime_error" || value === "killed_stalled" ? value : "other";
|
|
@@ -29180,7 +29666,7 @@ class AgentProcessManager {
|
|
|
29180
29666
|
liveBackendIds = new Map;
|
|
29181
29667
|
activeSpawnState = new Map;
|
|
29182
29668
|
publishedAgentActivity = new Map;
|
|
29183
|
-
traceProcessNonce =
|
|
29669
|
+
traceProcessNonce = randomUUID6();
|
|
29184
29670
|
nextSpawnOrdinal = 1;
|
|
29185
29671
|
nextDaemonTurnOrdinal = 1;
|
|
29186
29672
|
nextDeliveryOrdinal = 1;
|
|
@@ -29456,6 +29942,12 @@ class AgentProcessManager {
|
|
|
29456
29942
|
if (this.sessions.get(agentId) === session2)
|
|
29457
29943
|
this.sessions.delete(agentId);
|
|
29458
29944
|
}
|
|
29945
|
+
async interrupt(agentId) {
|
|
29946
|
+
const session2 = this.sessions.get(agentId);
|
|
29947
|
+
if (!session2)
|
|
29948
|
+
return;
|
|
29949
|
+
await session2.interrupt({ requestId: randomUUID6(), reason: "owner_request" });
|
|
29950
|
+
}
|
|
29459
29951
|
async stopAll() {
|
|
29460
29952
|
if (this.tickTimer) {
|
|
29461
29953
|
clearInterval(this.tickTimer);
|
|
@@ -29953,7 +30445,7 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
29953
30445
|
case "reset_idle_session": {
|
|
29954
30446
|
const spawnState = this.activeSpawnState.get(effect.agentId);
|
|
29955
30447
|
const completion = {
|
|
29956
|
-
eventId: `bae_${
|
|
30448
|
+
eventId: `bae_${randomUUID6()}`,
|
|
29957
30449
|
occurredAt: new Date(this.now()).toISOString()
|
|
29958
30450
|
};
|
|
29959
30451
|
const persisted = this.forgetSession(effect.agentId, "reset_session", effect.sessionId, completion);
|
|
@@ -30348,11 +30840,12 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30348
30840
|
emitErrorAudit(agentId, scope, code, rawMessage) {
|
|
30349
30841
|
if (!this.opts.onBotAuditEvent)
|
|
30350
30842
|
return;
|
|
30843
|
+
const stableCode = /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : "runtime_error";
|
|
30351
30844
|
const message2 = scrubRuntimeErrorDiagnosticText(rawMessage).slice(0, AUDIT_ERROR_MESSAGE_MAX_LEN);
|
|
30352
30845
|
try {
|
|
30353
30846
|
this.opts.onBotAuditEvent(agentId, {
|
|
30354
30847
|
kind: "error",
|
|
30355
|
-
payload: { scope, code, message: message2, model: this.currentModelFor(agentId) }
|
|
30848
|
+
payload: { scope, code: stableCode, message: message2, model: this.currentModelFor(agentId) }
|
|
30356
30849
|
}, {
|
|
30357
30850
|
sessionId: this.liveSessions.get(agentId) ?? null,
|
|
30358
30851
|
launchId: this.launchIds.get(agentId) ?? null
|
|
@@ -30377,18 +30870,18 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30377
30870
|
return;
|
|
30378
30871
|
}
|
|
30379
30872
|
const sessionSuperseded = owner.superseded;
|
|
30380
|
-
const
|
|
30381
|
-
if (
|
|
30382
|
-
this.emitErrorAudit(agentId, "runtime",
|
|
30873
|
+
const runtimeError = event.type === "session_failed" ? event.error : event.type === "turn_completed" && event.result.outcome === "failed" ? event.result.error : undefined;
|
|
30874
|
+
if (runtimeError !== undefined && !sessionSuperseded) {
|
|
30875
|
+
this.emitErrorAudit(agentId, "runtime", runtimeError.code, runtimeError.message);
|
|
30383
30876
|
if (this.nonCleanEndMarker.get(agentId)?.cause !== "killed_stalled") {
|
|
30384
|
-
this.nonCleanEndMarker.set(agentId, { cause: "runtime_error", detail:
|
|
30877
|
+
this.nonCleanEndMarker.set(agentId, { cause: "runtime_error", detail: runtimeError.message });
|
|
30385
30878
|
}
|
|
30386
30879
|
const agent2 = this.state.agents[agentId];
|
|
30387
30880
|
if (agent2?.resetting && agent2.resettingSince !== null && this.now() - agent2.resettingSince >= this.state.resetStuckThresholdMs) {
|
|
30388
30881
|
this.log.warn("runtime error during a stuck reset window", {
|
|
30389
30882
|
agentId,
|
|
30390
30883
|
resettingForMs: this.now() - agent2.resettingSince,
|
|
30391
|
-
message:
|
|
30884
|
+
message: runtimeError.message
|
|
30392
30885
|
});
|
|
30393
30886
|
}
|
|
30394
30887
|
}
|
|
@@ -30483,9 +30976,9 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30483
30976
|
case "assistant_message_completed":
|
|
30484
30977
|
return { type: "turn_work", turnId: event.turnId };
|
|
30485
30978
|
case "tool_started":
|
|
30486
|
-
return { type: "turn_tool_started", turnId: event.turnId };
|
|
30979
|
+
return { type: "turn_tool_started", turnId: event.turnId, callId: event.callId };
|
|
30487
30980
|
case "tool_finished":
|
|
30488
|
-
return { type: "turn_tool_finished", turnId: event.turnId };
|
|
30981
|
+
return { type: "turn_tool_finished", turnId: event.turnId, callId: event.callId };
|
|
30489
30982
|
case "compaction_started":
|
|
30490
30983
|
case "compaction_finished":
|
|
30491
30984
|
case "review_started":
|
|
@@ -30938,6 +31431,10 @@ class AgentRouter {
|
|
|
30938
31431
|
}
|
|
30939
31432
|
break;
|
|
30940
31433
|
}
|
|
31434
|
+
case "agent:interrupt": {
|
|
31435
|
+
await this.opts.manager.interrupt(cmd.agentId);
|
|
31436
|
+
break;
|
|
31437
|
+
}
|
|
30941
31438
|
case "agent:stop":
|
|
30942
31439
|
this.log.info("agent:stop received", { agentId: cmd.agentId });
|
|
30943
31440
|
try {
|
|
@@ -32380,7 +32877,7 @@ class MessageReminderScheduler {
|
|
|
32380
32877
|
}
|
|
32381
32878
|
|
|
32382
32879
|
// src/manager/agentDriverHost.ts
|
|
32383
|
-
import { randomUUID as
|
|
32880
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32384
32881
|
import { homedir as homedir4 } from "node:os";
|
|
32385
32882
|
import { join as join13 } from "node:path";
|
|
32386
32883
|
|
|
@@ -32536,7 +33033,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
32536
33033
|
onRawLine?.(event.text);
|
|
32537
33034
|
},
|
|
32538
33035
|
now: () => Date.now(),
|
|
32539
|
-
createId: () =>
|
|
33036
|
+
createId: () => randomUUID7()
|
|
32540
33037
|
};
|
|
32541
33038
|
}
|
|
32542
33039
|
|
|
@@ -32615,13 +33112,16 @@ class DaemonSelfSleepScheduler {
|
|
|
32615
33112
|
// src/telemetry/dailyTokenUsage.ts
|
|
32616
33113
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32617
33114
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
32618
|
-
import { randomUUID as
|
|
33115
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
33116
|
+
var TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
33117
|
+
var TOKEN_USAGE_RECOVERY_DAYS = 2;
|
|
33118
|
+
var TOKEN_USAGE_RETENTION_DAYS = TOKEN_USAGE_WINDOW_DAYS + TOKEN_USAGE_RECOVERY_DAYS;
|
|
32619
33119
|
function oldestRetainedDay(at, timeZone) {
|
|
32620
33120
|
const today = dayKeyInTimeZone(at, timeZone);
|
|
32621
|
-
return calendarDayKeyDaysAgo(today,
|
|
33121
|
+
return calendarDayKeyDaysAgo(today, TOKEN_USAGE_RETENTION_DAYS - 1);
|
|
32622
33122
|
}
|
|
32623
33123
|
function oldestVisibleDay(today) {
|
|
32624
|
-
return calendarDayKeyDaysAgo(today,
|
|
33124
|
+
return calendarDayKeyDaysAgo(today, TOKEN_USAGE_WINDOW_DAYS - 1);
|
|
32625
33125
|
}
|
|
32626
33126
|
function isMetric(value) {
|
|
32627
33127
|
return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -32783,7 +33283,7 @@ class DailyTokenUsageStore {
|
|
|
32783
33283
|
async persist() {
|
|
32784
33284
|
const directory = dirname6(this.filePath);
|
|
32785
33285
|
await mkdir(directory, { recursive: true, mode: 448 });
|
|
32786
|
-
const temporary = `${this.filePath}.${
|
|
33286
|
+
const temporary = `${this.filePath}.${randomUUID8()}.tmp`;
|
|
32787
33287
|
try {
|
|
32788
33288
|
const file2 = await open(temporary, "wx", 384);
|
|
32789
33289
|
try {
|
|
@@ -32865,15 +33365,17 @@ function createRuntimeRawLineTap(args) {
|
|
|
32865
33365
|
}
|
|
32866
33366
|
function deriveAuditLogSubcommand(pathname, method) {
|
|
32867
33367
|
const canonical = pathname.split("?")[0] ?? pathname;
|
|
32868
|
-
if (/^\/api\/community\/messages\/[^/]+\/
|
|
32869
|
-
|
|
32870
|
-
|
|
33368
|
+
if (/^\/api\/community\/messages\/[^/]+\/properties$/.test(canonical)) {
|
|
33369
|
+
if (method === "GET")
|
|
33370
|
+
return "messagePropertyList";
|
|
32871
33371
|
if (method === "PUT")
|
|
32872
|
-
return "
|
|
33372
|
+
return "messagePropertySet";
|
|
32873
33373
|
if (method === "DELETE")
|
|
32874
|
-
return "
|
|
33374
|
+
return "messagePropertyRemove";
|
|
32875
33375
|
return null;
|
|
32876
33376
|
}
|
|
33377
|
+
if (/^\/api\/community\/messages\/[^/]+\/reactions\//.test(canonical))
|
|
33378
|
+
return "reactAdd";
|
|
32877
33379
|
if (method === "GET" && /^\/api\/community\/users\/me\/marks$/.test(canonical))
|
|
32878
33380
|
return "markList";
|
|
32879
33381
|
if (/^\/api\/community\/channels\/[^/]+\/messages\/seq\//.test(canonical))
|
|
@@ -33039,14 +33541,14 @@ async function createDaemon(opts) {
|
|
|
33039
33541
|
log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
|
|
33040
33542
|
},
|
|
33041
33543
|
onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
|
|
33042
|
-
onProxyRequest: (agentId, method, pathname) => {
|
|
33544
|
+
onProxyRequest: (agentId, method, pathname, metadata) => {
|
|
33043
33545
|
const subcommand = deriveAuditLogSubcommand(pathname, method);
|
|
33044
33546
|
if (!subcommand)
|
|
33045
33547
|
return;
|
|
33046
33548
|
const context = managerRef?.auditContext(agentId);
|
|
33047
33549
|
emitBotAuditEvent(agentId, {
|
|
33048
33550
|
kind: "cli_invocation",
|
|
33049
|
-
payload: { subcommand }
|
|
33551
|
+
payload: { subcommand, ...metadata ? { propertyType: metadata.propertyType } : {} }
|
|
33050
33552
|
}, context);
|
|
33051
33553
|
emitImplicitTypingStopOnSend({
|
|
33052
33554
|
subcommand,
|
|
@@ -33968,10 +34470,17 @@ function projectFsm(row, targetAgentId) {
|
|
|
33968
34470
|
"queueDwellTotalMs",
|
|
33969
34471
|
"sseReconnectCount"
|
|
33970
34472
|
];
|
|
33971
|
-
const
|
|
34473
|
+
const toolMetricKeys = [
|
|
34474
|
+
"outstandingToolUses",
|
|
34475
|
+
"anonymousOutstandingToolUses",
|
|
34476
|
+
"toolLifecycleMismatchCount"
|
|
34477
|
+
];
|
|
34478
|
+
const hasMetrics = metricKeys.some((key) => (key in row) || row[key] !== undefined) || toolMetricKeys.some((key) => (key in row) || row[key] !== undefined) || "resumeOutcome" in row || "terminalOwnerKind" in row;
|
|
33972
34479
|
if (hasMetrics) {
|
|
33973
34480
|
if (!metricKeys.every((key) => copyFiniteNumber(row, output, key)))
|
|
33974
34481
|
return null;
|
|
34482
|
+
if (!toolMetricKeys.every((key) => copyInteger(row, output, key, { optional: true })))
|
|
34483
|
+
return null;
|
|
33975
34484
|
const resumeOutcome = enumValue(row.resumeOutcome, RESUME_OUTCOMES);
|
|
33976
34485
|
const terminalOwnerKind = enumValue(row.terminalOwnerKind, TERMINAL_OWNER_KINDS);
|
|
33977
34486
|
if (!resumeOutcome || !terminalOwnerKind)
|
|
@@ -36683,7 +37192,7 @@ ${MESSAGE_SEND_STDIN_POLICY}`);
|
|
|
36683
37192
|
}
|
|
36684
37193
|
replyToSeq = n;
|
|
36685
37194
|
}
|
|
36686
|
-
const nonce =
|
|
37195
|
+
const nonce = randomUUID11();
|
|
36687
37196
|
const res = await sendWithRetry(api2, {
|
|
36688
37197
|
agentId: agent2,
|
|
36689
37198
|
channel: channel2,
|
|
@@ -36712,22 +37221,43 @@ ${MESSAGE_SEND_STDIN_POLICY}`);
|
|
|
36712
37221
|
return { sent, reminder: { armed: false, reason: "local reminder request failed" } };
|
|
36713
37222
|
}
|
|
36714
37223
|
}
|
|
36715
|
-
|
|
37224
|
+
function parseMessagePropertyJson(command, raw) {
|
|
37225
|
+
if (typeof raw !== "string")
|
|
37226
|
+
throw new CliError(`${command}: --json <json> is required`);
|
|
37227
|
+
try {
|
|
37228
|
+
return JSON.parse(raw);
|
|
37229
|
+
} catch {
|
|
37230
|
+
throw new CliError(`${command}: --json must be valid JSON`);
|
|
37231
|
+
}
|
|
37232
|
+
}
|
|
37233
|
+
async function cmdMessagePropertySet(opts) {
|
|
36716
37234
|
const api2 = getApi();
|
|
36717
37235
|
const target2 = opts.target;
|
|
36718
|
-
const emoji3 = opts.emoji;
|
|
36719
37236
|
if (!target2)
|
|
36720
|
-
throw new CliError("message
|
|
36721
|
-
|
|
36722
|
-
|
|
36723
|
-
const
|
|
36724
|
-
|
|
36725
|
-
|
|
36726
|
-
|
|
36727
|
-
|
|
36728
|
-
|
|
36729
|
-
|
|
36730
|
-
|
|
37237
|
+
throw new CliError("message property set: --target <ref> is required");
|
|
37238
|
+
const request = parseMessageTarget("message property set", target2);
|
|
37239
|
+
const property = parseMessagePropertyJson("message property set", opts.json);
|
|
37240
|
+
const result = await withTransientMutationRetry(() => api2.messagePropertySet({ ...request, property }));
|
|
37241
|
+
return { target: target2, ...result };
|
|
37242
|
+
}
|
|
37243
|
+
async function cmdMessagePropertyList(opts) {
|
|
37244
|
+
const api2 = getApi();
|
|
37245
|
+
const target2 = opts.target;
|
|
37246
|
+
if (!target2)
|
|
37247
|
+
throw new CliError("message property list: --target <ref> is required");
|
|
37248
|
+
const request = parseMessageTarget("message property list", target2);
|
|
37249
|
+
const result = await api2.messagePropertyList(request);
|
|
37250
|
+
return { target: target2, ...result };
|
|
37251
|
+
}
|
|
37252
|
+
async function cmdMessagePropertyRemove(opts) {
|
|
37253
|
+
const api2 = getApi();
|
|
37254
|
+
const target2 = opts.target;
|
|
37255
|
+
if (!target2)
|
|
37256
|
+
throw new CliError("message property remove: --target <ref> is required");
|
|
37257
|
+
const request = parseMessageTarget("message property remove", target2);
|
|
37258
|
+
const property = parseMessagePropertyJson("message property remove", opts.json);
|
|
37259
|
+
const result = await withTransientMutationRetry(() => api2.messagePropertyRemove({ ...request, property }));
|
|
37260
|
+
return { target: target2, ...result };
|
|
36731
37261
|
}
|
|
36732
37262
|
function parseMessageTarget(command, target2) {
|
|
36733
37263
|
let parsed;
|
|
@@ -36744,24 +37274,6 @@ function parseMessageTarget(command, target2) {
|
|
|
36744
37274
|
const channel2 = parsed.threadRootSeq !== undefined ? `/${parsed.server}/${parsed.channel}/#${parsed.threadRootSeq}` : `/${parsed.server}/${parsed.channel}`;
|
|
36745
37275
|
return { channel: channel2, seq: parsed.seq };
|
|
36746
37276
|
}
|
|
36747
|
-
async function cmdMessageMarkSet(opts) {
|
|
36748
|
-
const api2 = getApi();
|
|
36749
|
-
const target2 = opts.target;
|
|
36750
|
-
if (!target2)
|
|
36751
|
-
throw new CliError("message mark set: --target <ref> is required");
|
|
36752
|
-
const request = parseMessageTarget("message mark set", target2);
|
|
36753
|
-
await withTransientMutationRetry(() => api2.markSet(request));
|
|
36754
|
-
return { target: target2, marked: true };
|
|
36755
|
-
}
|
|
36756
|
-
async function cmdMessageMarkRemove(opts) {
|
|
36757
|
-
const api2 = getApi();
|
|
36758
|
-
const target2 = opts.target;
|
|
36759
|
-
if (!target2)
|
|
36760
|
-
throw new CliError("message mark remove: --target <ref> is required");
|
|
36761
|
-
const request = parseMessageTarget("message mark remove", target2);
|
|
36762
|
-
await withTransientMutationRetry(() => api2.markRemove(request));
|
|
36763
|
-
return { target: target2, marked: false };
|
|
36764
|
-
}
|
|
36765
37277
|
async function cmdMessageMarkList(opts) {
|
|
36766
37278
|
const api2 = getApi();
|
|
36767
37279
|
const { marked } = await api2.listMarks({ agentId: agentId(opts) });
|
|
@@ -36891,7 +37403,7 @@ async function cmdInboxPull(opts) {
|
|
|
36891
37403
|
let acked = 0;
|
|
36892
37404
|
let ackError;
|
|
36893
37405
|
let failed;
|
|
36894
|
-
if (
|
|
37406
|
+
if (messages.length > 0) {
|
|
36895
37407
|
const latest = new Map;
|
|
36896
37408
|
for (const m of messages) {
|
|
36897
37409
|
const seqN = Number(m.seq.replace("#", ""));
|
|
@@ -36959,6 +37471,14 @@ async function cmdServerJoin(opts) {
|
|
|
36959
37471
|
const { server } = await api2.joinServer({ agentId: agent2, invite: token });
|
|
36960
37472
|
return { server };
|
|
36961
37473
|
}
|
|
37474
|
+
async function cmdServerLeave(opts) {
|
|
37475
|
+
const api2 = getApi();
|
|
37476
|
+
const agent2 = agentId(opts);
|
|
37477
|
+
const server = opts.server;
|
|
37478
|
+
if (!server)
|
|
37479
|
+
throw new CliError("server leave: --server <name#NNNN> is required");
|
|
37480
|
+
return await api2.leaveServer({ agentId: agent2, server });
|
|
37481
|
+
}
|
|
36962
37482
|
async function cmdChannelList(opts) {
|
|
36963
37483
|
const api2 = getApi();
|
|
36964
37484
|
const agent2 = agentId(opts);
|
|
@@ -36975,6 +37495,26 @@ async function cmdChannelMember(opts) {
|
|
|
36975
37495
|
throw new CliError("channel member: --channel <ref> is required");
|
|
36976
37496
|
return await api2.channelMember({ agentId: agent2, channel: channel2 });
|
|
36977
37497
|
}
|
|
37498
|
+
async function cmdChannelLeave(opts) {
|
|
37499
|
+
const api2 = getApi();
|
|
37500
|
+
const agent2 = agentId(opts);
|
|
37501
|
+
const channel2 = opts.channel;
|
|
37502
|
+
if (!channel2)
|
|
37503
|
+
throw new CliError("channel leave: --channel <ref> is required");
|
|
37504
|
+
let parsed;
|
|
37505
|
+
try {
|
|
37506
|
+
parsed = parseRef(channel2);
|
|
37507
|
+
} catch {
|
|
37508
|
+
throw new CliError("channel leave: malformed channel ref");
|
|
37509
|
+
}
|
|
37510
|
+
if (parsed.server === DM_SERVER) {
|
|
37511
|
+
throw new CliError("channel leave: DMs cannot be left");
|
|
37512
|
+
}
|
|
37513
|
+
if (parsed.seq !== undefined) {
|
|
37514
|
+
throw new CliError("channel leave: message refs cannot be left; use a channel or thread-root ref");
|
|
37515
|
+
}
|
|
37516
|
+
return await api2.leaveChannel({ agentId: agent2, channel: channel2 });
|
|
37517
|
+
}
|
|
36978
37518
|
async function cmdChannelHistory(opts) {
|
|
36979
37519
|
const api2 = getApi();
|
|
36980
37520
|
const agent2 = agentId(opts);
|
|
@@ -37032,22 +37572,22 @@ function buildProgram(stdin) {
|
|
|
37032
37572
|
const result = await cmdMessageSend({ ...globalOpts, ...localOpts }, stdin);
|
|
37033
37573
|
printEnvelope({ success: result });
|
|
37034
37574
|
});
|
|
37035
|
-
message2.command("
|
|
37036
|
-
|
|
37037
|
-
|
|
37038
|
-
const result = await
|
|
37575
|
+
const property = message2.command("property").description("message property operations").exitOverride();
|
|
37576
|
+
property.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37577
|
+
property.command("set").description("add a supported property value to a message").requiredOption("--target <ref>", "full message ref").requiredOption("--json <json>", "property JSON").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37578
|
+
const result = await cmdMessagePropertySet({ ...program.opts(), ...this.opts() });
|
|
37039
37579
|
printEnvelope({ success: result });
|
|
37040
37580
|
});
|
|
37041
|
-
|
|
37042
|
-
|
|
37043
|
-
mark.command("set").description("mark a message as outstanding work").requiredOption("--target <ref>", "full message ref").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37044
|
-
const result = await cmdMessageMarkSet({ ...program.opts(), ...this.opts() });
|
|
37581
|
+
property.command("list").description("list current properties and supported capabilities").requiredOption("--target <ref>", "full message ref").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37582
|
+
const result = await cmdMessagePropertyList({ ...program.opts(), ...this.opts() });
|
|
37045
37583
|
printEnvelope({ success: result });
|
|
37046
37584
|
});
|
|
37047
|
-
|
|
37048
|
-
const result = await
|
|
37585
|
+
property.command("remove").description("remove a supported property value from a message").requiredOption("--target <ref>", "full message ref").requiredOption("--json <json>", "property JSON").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37586
|
+
const result = await cmdMessagePropertyRemove({ ...program.opts(), ...this.opts() });
|
|
37049
37587
|
printEnvelope({ success: result });
|
|
37050
37588
|
});
|
|
37589
|
+
const mark = message2.command("mark").description("global durable-mark queries").exitOverride();
|
|
37590
|
+
mark.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37051
37591
|
mark.command("list").description("list all currently visible marked messages").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37052
37592
|
const result = await cmdMessageMarkList({ ...program.opts(), ...this.opts() });
|
|
37053
37593
|
printEnvelope({ success: result });
|
|
@@ -37068,7 +37608,7 @@ function buildProgram(stdin) {
|
|
|
37068
37608
|
});
|
|
37069
37609
|
const inbox = program.command("inbox").description("inbox operations").exitOverride();
|
|
37070
37610
|
inbox.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37071
|
-
inbox.command("pull").description("fetch unread messages from all channels").option("--max <n>", "max messages to return").
|
|
37611
|
+
inbox.command("pull").description("fetch unread messages from all channels").option("--max <n>", "max messages to return").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37072
37612
|
const localOpts = this.opts();
|
|
37073
37613
|
const globalOpts = program.opts();
|
|
37074
37614
|
const result = await cmdInboxPull({ ...globalOpts, ...localOpts });
|
|
@@ -37094,6 +37634,12 @@ function buildProgram(stdin) {
|
|
|
37094
37634
|
const result = await cmdServerJoin({ ...globalOpts, ...localOpts });
|
|
37095
37635
|
printEnvelope({ success: result });
|
|
37096
37636
|
});
|
|
37637
|
+
server.command("leave").description("leave a server you belong to").option("--server <handle>", "server name#NNNN handle (from `server list`)").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37638
|
+
const localOpts = this.opts();
|
|
37639
|
+
const globalOpts = program.opts();
|
|
37640
|
+
const result = await cmdServerLeave({ ...globalOpts, ...localOpts });
|
|
37641
|
+
printEnvelope({ success: result });
|
|
37642
|
+
});
|
|
37097
37643
|
const channel2 = program.command("channel").description("channel operations").exitOverride();
|
|
37098
37644
|
channel2.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37099
37645
|
channel2.command("list").description("list top-level channels visible to this agent in one server").option("--server <handle>", "server name#discriminator handle (from `server list`)").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
@@ -37114,6 +37660,12 @@ function buildProgram(stdin) {
|
|
|
37114
37660
|
const result = await cmdChannelMember({ ...globalOpts, ...localOpts });
|
|
37115
37661
|
printEnvelope({ success: result });
|
|
37116
37662
|
});
|
|
37663
|
+
channel2.command("leave").description("leave a thread or private channel/forum").option("--channel <ref>", "channel/thread ref (path-style)").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37664
|
+
const localOpts = this.opts();
|
|
37665
|
+
const globalOpts = program.opts();
|
|
37666
|
+
const result = await cmdChannelLeave({ ...globalOpts, ...localOpts });
|
|
37667
|
+
printEnvelope({ success: result });
|
|
37668
|
+
});
|
|
37117
37669
|
const friend = program.command("friend").description("friend operations").exitOverride();
|
|
37118
37670
|
friend.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37119
37671
|
friend.command("request").description("send a friend request to a user by handle (owner-approval required)").option("--username <name#0042>", "the target's global handle, e.g. Alice#0042").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|