@alook/daemon 0.1.29 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +570 -167
- package/dist/index.js +417 -90
- 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;
|
|
@@ -17830,17 +17834,18 @@ var CommunityAgentNapRequestSchema = exports_external.object({
|
|
|
17830
17834
|
message: "handoff is required"
|
|
17831
17835
|
})
|
|
17832
17836
|
});
|
|
17833
|
-
var
|
|
17837
|
+
var CommunityAgentMessagePropertyRequestSchema = exports_external.object({
|
|
17834
17838
|
channel: exports_external.string().min(1),
|
|
17835
17839
|
seq: CommunityAgentPositiveSeqSchema,
|
|
17836
|
-
|
|
17840
|
+
property: exports_external.unknown()
|
|
17837
17841
|
});
|
|
17838
17842
|
var CommunityAgentFriendRequestSchema = exports_external.object({
|
|
17839
17843
|
username: exports_external.string().min(1)
|
|
17840
17844
|
});
|
|
17841
17845
|
var CommunityAgentListFriendsSchema = exports_external.object({});
|
|
17842
17846
|
var AuditLogCliInvocationPayloadSchema = exports_external.object({
|
|
17843
|
-
subcommand: exports_external.string().min(1)
|
|
17847
|
+
subcommand: exports_external.string().min(1),
|
|
17848
|
+
propertyType: exports_external.enum(["emoji", "tag", "mark"]).optional()
|
|
17844
17849
|
});
|
|
17845
17850
|
var AuditLogToolCallPayloadSchema = exports_external.object({
|
|
17846
17851
|
name: exports_external.string().min(1),
|
|
@@ -17851,6 +17856,9 @@ var AuditLogThinkingPayloadSchema = exports_external.object({
|
|
|
17851
17856
|
truncated: exports_external.boolean(),
|
|
17852
17857
|
chars: exports_external.number().int().nonnegative()
|
|
17853
17858
|
});
|
|
17859
|
+
var AuditLogTurnInterruptPayloadSchema = exports_external.object({
|
|
17860
|
+
status: exports_external.literal("accepted")
|
|
17861
|
+
});
|
|
17854
17862
|
var AuditLogWakeTriggerPayloadSchema = exports_external.object({
|
|
17855
17863
|
messageId: exports_external.string().min(1),
|
|
17856
17864
|
channel: exports_external.string().min(1),
|
|
@@ -17883,6 +17891,7 @@ var BotAuditEventSchema = exports_external.discriminatedUnion("kind", [
|
|
|
17883
17891
|
exports_external.object({ kind: exports_external.literal("cli_invocation"), payload: AuditLogCliInvocationPayloadSchema }),
|
|
17884
17892
|
exports_external.object({ kind: exports_external.literal("tool_call"), payload: AuditLogToolCallPayloadSchema }),
|
|
17885
17893
|
exports_external.object({ kind: exports_external.literal("thinking"), payload: AuditLogThinkingPayloadSchema }),
|
|
17894
|
+
exports_external.object({ kind: exports_external.literal("turn_interrupt"), payload: AuditLogTurnInterruptPayloadSchema }),
|
|
17886
17895
|
exports_external.object({ kind: exports_external.literal("wake_trigger"), payload: AuditLogWakeTriggerPayloadSchema }),
|
|
17887
17896
|
exports_external.object({ kind: exports_external.literal("session_reset"), payload: AuditLogSessionResetPayloadSchema }),
|
|
17888
17897
|
exports_external.object({ kind: exports_external.literal("nap"), payload: AuditLogNapPayloadSchema }),
|
|
@@ -17894,6 +17903,7 @@ var BotAuditEventKindSchema = exports_external.enum([
|
|
|
17894
17903
|
"cli_invocation",
|
|
17895
17904
|
"tool_call",
|
|
17896
17905
|
"thinking",
|
|
17906
|
+
"turn_interrupt",
|
|
17897
17907
|
"wake_trigger",
|
|
17898
17908
|
"session_reset",
|
|
17899
17909
|
"nap",
|
|
@@ -18850,7 +18860,7 @@ var communityBotAuditEventSchema = exports_external.strictObject({
|
|
|
18850
18860
|
type: exports_external.literal("community:bot.audit_event"),
|
|
18851
18861
|
botId: string4,
|
|
18852
18862
|
id: string4,
|
|
18853
|
-
kind: exports_external.enum(["cli_invocation", "tool_call", "thinking", "wake_trigger", "session_reset", "nap", "model_changed", "provider_changed", "error"]),
|
|
18863
|
+
kind: exports_external.enum(["cli_invocation", "tool_call", "thinking", "turn_interrupt", "wake_trigger", "session_reset", "nap", "model_changed", "provider_changed", "error"]),
|
|
18854
18864
|
payload: exports_external.unknown(),
|
|
18855
18865
|
sessionId: nullableString.optional(),
|
|
18856
18866
|
launchId: nullableString.optional(),
|
|
@@ -19136,6 +19146,14 @@ function proxyServerApiFromEnv(prefix = "ALOOK", env = process.env) {
|
|
|
19136
19146
|
function createProxyServerApi(config2) {
|
|
19137
19147
|
const fetchImpl = config2.fetchImpl ?? fetch;
|
|
19138
19148
|
const base = config2.proxyUrl.replace(/\/+$/, "");
|
|
19149
|
+
const propertyAuditQuery = (property) => {
|
|
19150
|
+
if (!property || typeof property !== "object" || Array.isArray(property))
|
|
19151
|
+
return "";
|
|
19152
|
+
const type = property.type;
|
|
19153
|
+
if (type !== "emoji" && type !== "tag" && type !== "mark")
|
|
19154
|
+
return "";
|
|
19155
|
+
return `?type=${encodeURIComponent(type)}`;
|
|
19156
|
+
};
|
|
19139
19157
|
async function parseJsonResponse(res, method) {
|
|
19140
19158
|
let text2;
|
|
19141
19159
|
try {
|
|
@@ -19253,17 +19271,37 @@ function createProxyServerApi(config2) {
|
|
|
19253
19271
|
});
|
|
19254
19272
|
return parseJsonResponse(res, "resolve");
|
|
19255
19273
|
}
|
|
19256
|
-
async function
|
|
19257
|
-
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/
|
|
19274
|
+
async function callMessagePropertySet(req) {
|
|
19275
|
+
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/properties${propertyAuditQuery(req.property)}`, {
|
|
19258
19276
|
method: "PUT",
|
|
19259
19277
|
headers: {
|
|
19260
19278
|
"content-type": "application/json",
|
|
19261
19279
|
authorization: `Bearer ${config2.voucher}`
|
|
19262
19280
|
},
|
|
19263
|
-
body: JSON.stringify(
|
|
19281
|
+
body: JSON.stringify(req)
|
|
19282
|
+
});
|
|
19283
|
+
return parseJsonResponse(res, "messagePropertySet");
|
|
19284
|
+
}
|
|
19285
|
+
async function callMessagePropertyList(req) {
|
|
19286
|
+
const q = new URLSearchParams;
|
|
19287
|
+
q.set("ref", req.channel);
|
|
19288
|
+
q.set("seq", String(req.seq));
|
|
19289
|
+
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/properties?${q.toString()}`, {
|
|
19290
|
+
method: "GET",
|
|
19291
|
+
headers: { authorization: `Bearer ${config2.voucher}` }
|
|
19292
|
+
});
|
|
19293
|
+
return parseJsonResponse(res, "messagePropertyList");
|
|
19294
|
+
}
|
|
19295
|
+
async function callMessagePropertyRemove(req) {
|
|
19296
|
+
const res = await fetchImpl(`${base}/api/community/messages/${REF_PLACEHOLDER_ID}/properties${propertyAuditQuery(req.property)}`, {
|
|
19297
|
+
method: "DELETE",
|
|
19298
|
+
headers: {
|
|
19299
|
+
"content-type": "application/json",
|
|
19300
|
+
authorization: `Bearer ${config2.voucher}`
|
|
19301
|
+
},
|
|
19302
|
+
body: JSON.stringify(req)
|
|
19264
19303
|
});
|
|
19265
|
-
|
|
19266
|
-
return body?.duplicate ? { ok: true, duplicate: true } : { ok: true };
|
|
19304
|
+
return parseJsonResponse(res, "messagePropertyRemove");
|
|
19267
19305
|
}
|
|
19268
19306
|
async function callListMembers(req) {
|
|
19269
19307
|
const q = new URLSearchParams;
|
|
@@ -19315,28 +19353,6 @@ function createProxyServerApi(config2) {
|
|
|
19315
19353
|
});
|
|
19316
19354
|
return parseJsonResponse(res, "inboxPull");
|
|
19317
19355
|
}
|
|
19318
|
-
async function callMarkSet(req) {
|
|
19319
|
-
const res = await fetchImpl(`${base}/api/community/messages/resolve/marks`, {
|
|
19320
|
-
method: "PUT",
|
|
19321
|
-
headers: {
|
|
19322
|
-
"content-type": "application/json",
|
|
19323
|
-
authorization: `Bearer ${config2.voucher}`
|
|
19324
|
-
},
|
|
19325
|
-
body: JSON.stringify(req)
|
|
19326
|
-
});
|
|
19327
|
-
await parseJsonResponse(res, "markSet");
|
|
19328
|
-
}
|
|
19329
|
-
async function callMarkRemove(req) {
|
|
19330
|
-
const res = await fetchImpl(`${base}/api/community/messages/resolve/marks`, {
|
|
19331
|
-
method: "DELETE",
|
|
19332
|
-
headers: {
|
|
19333
|
-
"content-type": "application/json",
|
|
19334
|
-
authorization: `Bearer ${config2.voucher}`
|
|
19335
|
-
},
|
|
19336
|
-
body: JSON.stringify(req)
|
|
19337
|
-
});
|
|
19338
|
-
await parseJsonResponse(res, "markRemove");
|
|
19339
|
-
}
|
|
19340
19356
|
async function callListMarks() {
|
|
19341
19357
|
const res = await fetchImpl(`${base}/api/community/users/me/marks`, {
|
|
19342
19358
|
method: "GET",
|
|
@@ -19493,11 +19509,32 @@ function createProxyServerApi(config2) {
|
|
|
19493
19509
|
}
|
|
19494
19510
|
return { server: projectServer(body.server) };
|
|
19495
19511
|
}
|
|
19512
|
+
async function callLeaveChannel(req) {
|
|
19513
|
+
const parsed = parseRef(req.channel);
|
|
19514
|
+
const scope = parsed.threadRootSeq === undefined ? "channel" : "thread";
|
|
19515
|
+
const collection = scope === "thread" ? "participants" : "members";
|
|
19516
|
+
const res = await fetchImpl(`${base}/api/community/channels/${REF_PLACEHOLDER_ID}/${collection}/self?ref=${encodeURIComponent(req.channel)}`, {
|
|
19517
|
+
method: "DELETE",
|
|
19518
|
+
headers: { authorization: `Bearer ${config2.voucher}` }
|
|
19519
|
+
});
|
|
19520
|
+
await parseJsonResponse(res, "leaveChannel");
|
|
19521
|
+
return { left: req.channel, scope };
|
|
19522
|
+
}
|
|
19523
|
+
async function callLeaveServer(req) {
|
|
19524
|
+
const res = await fetchImpl(`${base}/api/community/servers/${REF_PLACEHOLDER_ID}/leave?server=${encodeURIComponent(req.server)}`, {
|
|
19525
|
+
method: "POST",
|
|
19526
|
+
headers: { authorization: `Bearer ${config2.voucher}` }
|
|
19527
|
+
});
|
|
19528
|
+
await parseJsonResponse(res, "leaveServer");
|
|
19529
|
+
return { left: req.server, scope: "server" };
|
|
19530
|
+
}
|
|
19496
19531
|
return {
|
|
19497
19532
|
listServers: (_r) => callListServers(),
|
|
19498
19533
|
joinServer: callJoinServer,
|
|
19534
|
+
leaveServer: callLeaveServer,
|
|
19499
19535
|
listChannels: callListChannels,
|
|
19500
19536
|
channelMember: callChannelMember,
|
|
19537
|
+
leaveChannel: callLeaveChannel,
|
|
19501
19538
|
inboxPull: callInboxPull,
|
|
19502
19539
|
inboxSnapshot: (_r) => callInboxSnapshot(),
|
|
19503
19540
|
ack: callAck,
|
|
@@ -19508,9 +19545,9 @@ function createProxyServerApi(config2) {
|
|
|
19508
19545
|
attachmentUpload: callUpload,
|
|
19509
19546
|
attachmentDownload: callDownload,
|
|
19510
19547
|
updateProfile: callUpdateProfile,
|
|
19511
|
-
|
|
19512
|
-
|
|
19513
|
-
|
|
19548
|
+
messagePropertySet: callMessagePropertySet,
|
|
19549
|
+
messagePropertyList: callMessagePropertyList,
|
|
19550
|
+
messagePropertyRemove: callMessagePropertyRemove,
|
|
19514
19551
|
listMarks: (_r) => callListMarks(),
|
|
19515
19552
|
friendRequest: callFriendRequest,
|
|
19516
19553
|
listFriends: (_r) => callListFriends(),
|
|
@@ -19557,6 +19594,9 @@ function createDefaultAgentDriverHost(options = {}) {
|
|
|
19557
19594
|
};
|
|
19558
19595
|
}
|
|
19559
19596
|
|
|
19597
|
+
// agent-driver/dist/adapters/claude/index.js
|
|
19598
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
19599
|
+
|
|
19560
19600
|
// agent-driver/dist/controller/process-host.js
|
|
19561
19601
|
import { EventEmitter } from "events";
|
|
19562
19602
|
|
|
@@ -20136,6 +20176,7 @@ class ProcessLane {
|
|
|
20136
20176
|
admissionSequence = 0;
|
|
20137
20177
|
activeTerminalReceipt;
|
|
20138
20178
|
stopPromise;
|
|
20179
|
+
pendingInterrupt;
|
|
20139
20180
|
pendingPromptAdmission;
|
|
20140
20181
|
constructor(driver, ctx, opts = {}) {
|
|
20141
20182
|
this.driver = driver;
|
|
@@ -20175,12 +20216,14 @@ class ProcessLane {
|
|
|
20175
20216
|
try {
|
|
20176
20217
|
spawned = await this.driver.spawn(launchCtx);
|
|
20177
20218
|
} catch (error51) {
|
|
20219
|
+
this.settlePendingInterrupt(false);
|
|
20178
20220
|
this.settlePendingPrompt({ ok: false, reason: "runtime_error", error: String(error51) });
|
|
20179
20221
|
throw error51;
|
|
20180
20222
|
}
|
|
20181
20223
|
const { process: proc } = spawned;
|
|
20182
20224
|
this.process = proc;
|
|
20183
20225
|
this.attachProcess(proc);
|
|
20226
|
+
this.dispatchPendingInterrupt(proc);
|
|
20184
20227
|
this.armPendingPromptTimeout();
|
|
20185
20228
|
if (this.driver.execution.lifetime === "session" && !this.writableStdin(proc)) {
|
|
20186
20229
|
const rejection = this.stdinUnavailableAdmission();
|
|
@@ -20279,6 +20322,7 @@ class ProcessLane {
|
|
|
20279
20322
|
pending.resolve(admission);
|
|
20280
20323
|
}
|
|
20281
20324
|
stop(opts = {}) {
|
|
20325
|
+
this.settlePendingInterrupt(false);
|
|
20282
20326
|
this.settlePendingPrompt({ ok: false, reason: "closed", error: "runtime lane stopped before command admission" });
|
|
20283
20327
|
if (!this.process)
|
|
20284
20328
|
return Promise.resolve();
|
|
@@ -20297,11 +20341,39 @@ class ProcessLane {
|
|
|
20297
20341
|
proc.kill(opts?.signal ?? "SIGTERM");
|
|
20298
20342
|
}
|
|
20299
20343
|
}
|
|
20300
|
-
async interrupt() {
|
|
20344
|
+
async interrupt(input) {
|
|
20301
20345
|
const proc = this.process;
|
|
20302
|
-
if (!proc
|
|
20346
|
+
if (!proc) {
|
|
20347
|
+
if (!this.started)
|
|
20348
|
+
return false;
|
|
20349
|
+
if (this.pendingInterrupt)
|
|
20350
|
+
return this.pendingInterrupt.promise;
|
|
20351
|
+
let resolve;
|
|
20352
|
+
let reject;
|
|
20353
|
+
const promise2 = new Promise((res, rej) => {
|
|
20354
|
+
resolve = res;
|
|
20355
|
+
reject = rej;
|
|
20356
|
+
});
|
|
20357
|
+
this.pendingInterrupt = { input, promise: promise2, resolve, reject };
|
|
20358
|
+
return promise2;
|
|
20359
|
+
}
|
|
20360
|
+
if (this.closed)
|
|
20303
20361
|
return false;
|
|
20304
|
-
return
|
|
20362
|
+
return this.driver.interrupt(input, proc);
|
|
20363
|
+
}
|
|
20364
|
+
dispatchPendingInterrupt(proc) {
|
|
20365
|
+
const pending = this.pendingInterrupt;
|
|
20366
|
+
if (!pending)
|
|
20367
|
+
return;
|
|
20368
|
+
this.pendingInterrupt = undefined;
|
|
20369
|
+
this.driver.interrupt(pending.input, proc).then(pending.resolve, pending.reject);
|
|
20370
|
+
}
|
|
20371
|
+
settlePendingInterrupt(accepted) {
|
|
20372
|
+
const pending = this.pendingInterrupt;
|
|
20373
|
+
if (!pending)
|
|
20374
|
+
return;
|
|
20375
|
+
this.pendingInterrupt = undefined;
|
|
20376
|
+
pending.resolve(accepted);
|
|
20305
20377
|
}
|
|
20306
20378
|
updateSettings(input) {
|
|
20307
20379
|
return this.driver.updateSettings?.(input) ?? Promise.resolve({ status: "unsupported" });
|
|
@@ -20638,6 +20710,13 @@ function tryParseJsonLine(line) {
|
|
|
20638
20710
|
|
|
20639
20711
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
20640
20712
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
20713
|
+
var CLAUDE_RESULT_ERROR_CODES = new Map([
|
|
20714
|
+
["error_max_turns", "claude.error_max_turns"],
|
|
20715
|
+
["error_during_execution", "claude.error_during_execution"],
|
|
20716
|
+
["error_max_budget_usd", "claude.error_max_budget_usd"],
|
|
20717
|
+
["error_max_structured_output_retries", "claude.error_max_structured_output_retries"]
|
|
20718
|
+
]);
|
|
20719
|
+
var CLAUDE_INTERRUPT_TERMINAL_REASONS = new Set(["aborted_streaming", "aborted_tools"]);
|
|
20641
20720
|
var CLAUDE_USAGE_COMPONENTS = [
|
|
20642
20721
|
"inputTokens",
|
|
20643
20722
|
"outputTokens",
|
|
@@ -20731,9 +20810,9 @@ class ClaudeEventNormalizer {
|
|
|
20731
20810
|
out.push({ kind: "assistant_reasoning_completed", text: block.thinking ?? "" });
|
|
20732
20811
|
} else if (block?.type === "text") {
|
|
20733
20812
|
const text2 = block.text ?? "";
|
|
20734
|
-
if (API_ERROR_RE.test(text2))
|
|
20735
|
-
out.push({ kind: "error", message: text2 });
|
|
20736
|
-
else
|
|
20813
|
+
if (API_ERROR_RE.test(text2)) {
|
|
20814
|
+
out.push({ kind: "error", code: "claude.api_error", message: text2 });
|
|
20815
|
+
} else
|
|
20737
20816
|
completedText.push(text2);
|
|
20738
20817
|
} else if (block?.type === "tool_use") {
|
|
20739
20818
|
out.push({ kind: "tool_call", name: block.name ?? "unknown_tool", input: block.input });
|
|
@@ -20759,14 +20838,19 @@ class ClaudeEventNormalizer {
|
|
|
20759
20838
|
}
|
|
20760
20839
|
handleResult(event, out) {
|
|
20761
20840
|
const rawOwner = typeof event.user_message_uuid === "string" && event.user_message_uuid.length > 0 ? event.user_message_uuid : null;
|
|
20762
|
-
const
|
|
20841
|
+
const interruptedTerminal = Boolean(this.turnProtocol && !rawOwner && event.subtype === "error_during_execution" && CLAUDE_INTERRUPT_TERMINAL_REASONS.has(event.terminal_reason));
|
|
20842
|
+
const turnOwner = rawOwner ? this.turnProtocol?.claimResult(rawOwner) ?? (this.turnProtocol ? null : `claude:${rawOwner}`) : interruptedTerminal ? this.turnProtocol.claimInterruptedResult() : null;
|
|
20763
20843
|
if (this.turnProtocol && !turnOwner)
|
|
20764
20844
|
return;
|
|
20765
20845
|
const usage = this.buildUsageTelemetry(event, rawOwner);
|
|
20766
20846
|
if (usage)
|
|
20767
20847
|
out.push(usage);
|
|
20768
|
-
if (event.is_error || event.subtype === "error_during_execution") {
|
|
20769
|
-
out.push({
|
|
20848
|
+
if (!interruptedTerminal && (event.is_error || event.subtype === "error_during_execution")) {
|
|
20849
|
+
out.push({
|
|
20850
|
+
kind: "error",
|
|
20851
|
+
code: CLAUDE_RESULT_ERROR_CODES.get(event.subtype) ?? "claude.result_error",
|
|
20852
|
+
message: String(event.result ?? "Claude runtime error")
|
|
20853
|
+
});
|
|
20770
20854
|
}
|
|
20771
20855
|
out.push({
|
|
20772
20856
|
kind: "turn_end",
|
|
@@ -21044,6 +21128,7 @@ class ClaudeTurnProtocol {
|
|
|
21044
21128
|
segmentOwnerUuid = null;
|
|
21045
21129
|
delivered = new Map;
|
|
21046
21130
|
awaitingFollowOn = false;
|
|
21131
|
+
interruptRequested = false;
|
|
21047
21132
|
finalized = false;
|
|
21048
21133
|
beginTurn() {
|
|
21049
21134
|
const uuid3 = randomUUID4();
|
|
@@ -21052,6 +21137,7 @@ class ClaudeTurnProtocol {
|
|
|
21052
21137
|
this.delivered.clear();
|
|
21053
21138
|
this.delivered.set(uuid3, { acknowledged: false, followOn: false });
|
|
21054
21139
|
this.awaitingFollowOn = false;
|
|
21140
|
+
this.interruptRequested = false;
|
|
21055
21141
|
this.finalized = false;
|
|
21056
21142
|
return this.receipt(uuid3);
|
|
21057
21143
|
}
|
|
@@ -21078,6 +21164,13 @@ class ClaudeTurnProtocol {
|
|
|
21078
21164
|
return false;
|
|
21079
21165
|
return this.delivered.get(this.rootUuid)?.acknowledged === true;
|
|
21080
21166
|
}
|
|
21167
|
+
hasActiveTurn() {
|
|
21168
|
+
return this.rootUuid !== null && !this.finalized;
|
|
21169
|
+
}
|
|
21170
|
+
noteInterruptRequested() {
|
|
21171
|
+
if (this.hasActiveTurn())
|
|
21172
|
+
this.interruptRequested = true;
|
|
21173
|
+
}
|
|
21081
21174
|
claimResult(userMessageUuid) {
|
|
21082
21175
|
if (this.finalized || !this.rootUuid || userMessageUuid !== this.segmentOwnerUuid)
|
|
21083
21176
|
return null;
|
|
@@ -21094,6 +21187,19 @@ class ClaudeTurnProtocol {
|
|
|
21094
21187
|
this.finalized = true;
|
|
21095
21188
|
return this.receipt(this.rootUuid);
|
|
21096
21189
|
}
|
|
21190
|
+
claimInterruptedResult() {
|
|
21191
|
+
if (this.finalized || !this.rootUuid || !this.interruptRequested)
|
|
21192
|
+
return null;
|
|
21193
|
+
const unacknowledged = [...this.delivered.values()].filter((input) => !input.acknowledged);
|
|
21194
|
+
if (unacknowledged.length > 0) {
|
|
21195
|
+
this.awaitingFollowOn = true;
|
|
21196
|
+
for (const input of unacknowledged)
|
|
21197
|
+
input.followOn = true;
|
|
21198
|
+
return null;
|
|
21199
|
+
}
|
|
21200
|
+
this.finalized = true;
|
|
21201
|
+
return this.receipt(this.rootUuid);
|
|
21202
|
+
}
|
|
21097
21203
|
receipt(uuid3) {
|
|
21098
21204
|
return `claude:${uuid3}`;
|
|
21099
21205
|
}
|
|
@@ -21119,7 +21225,9 @@ class ClaudeDriver {
|
|
|
21119
21225
|
};
|
|
21120
21226
|
turnProtocol = new ClaudeTurnProtocol;
|
|
21121
21227
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
21228
|
+
pendingInterrupt;
|
|
21122
21229
|
beginTurn() {
|
|
21230
|
+
this.pendingInterrupt = undefined;
|
|
21123
21231
|
const receipt = this.turnProtocol.beginTurn();
|
|
21124
21232
|
this.eventNormalizer.beginTurn();
|
|
21125
21233
|
return receipt;
|
|
@@ -21158,11 +21266,45 @@ class ClaudeDriver {
|
|
|
21158
21266
|
return { process: proc };
|
|
21159
21267
|
}
|
|
21160
21268
|
normalizeLine(line) {
|
|
21161
|
-
|
|
21269
|
+
const events = this.eventNormalizer.normalizeLine(line);
|
|
21270
|
+
this.flushPendingInterrupt();
|
|
21271
|
+
return events;
|
|
21162
21272
|
}
|
|
21163
21273
|
get currentSessionId() {
|
|
21164
21274
|
return this.eventNormalizer.currentSessionId;
|
|
21165
21275
|
}
|
|
21276
|
+
async interrupt(input, process3) {
|
|
21277
|
+
const stdin = process3.stdin;
|
|
21278
|
+
if (!this.turnProtocol.hasActiveTurn() || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
21279
|
+
return false;
|
|
21280
|
+
this.turnProtocol.noteInterruptRequested();
|
|
21281
|
+
if (!this.turnProtocol.acceptsTurnWork()) {
|
|
21282
|
+
this.pendingInterrupt ??= { input, process: process3 };
|
|
21283
|
+
return true;
|
|
21284
|
+
}
|
|
21285
|
+
this.writeInterrupt(input, process3);
|
|
21286
|
+
return true;
|
|
21287
|
+
}
|
|
21288
|
+
writeInterrupt(input, process3) {
|
|
21289
|
+
process3.stdin.write(JSON.stringify({
|
|
21290
|
+
type: "control_request",
|
|
21291
|
+
request_id: input.requestId ?? randomUUID5(),
|
|
21292
|
+
request: { subtype: "interrupt" }
|
|
21293
|
+
}) + `
|
|
21294
|
+
`);
|
|
21295
|
+
}
|
|
21296
|
+
flushPendingInterrupt() {
|
|
21297
|
+
const pending = this.pendingInterrupt;
|
|
21298
|
+
if (!pending || !this.turnProtocol.acceptsTurnWork())
|
|
21299
|
+
return;
|
|
21300
|
+
this.pendingInterrupt = undefined;
|
|
21301
|
+
const stdin = pending.process.stdin;
|
|
21302
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
21303
|
+
return;
|
|
21304
|
+
try {
|
|
21305
|
+
this.writeInterrupt(pending.input, pending.process);
|
|
21306
|
+
} catch {}
|
|
21307
|
+
}
|
|
21166
21308
|
encodeMessage(text2, sessionId, opts) {
|
|
21167
21309
|
const uuid3 = opts?.mode === "idle" ? this.turnProtocol.rootInputUuid() : this.turnProtocol.steeringInputUuid();
|
|
21168
21310
|
return JSON.stringify({
|
|
@@ -21294,6 +21436,35 @@ import { randomBytes } from "node:crypto";
|
|
|
21294
21436
|
var codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
21295
21437
|
var codexQuotaSourceGeneration = 0;
|
|
21296
21438
|
var codexAccountFingerprint = null;
|
|
21439
|
+
var CODEX_ERROR_INFO_CODES = new Set([
|
|
21440
|
+
"contextWindowExceeded",
|
|
21441
|
+
"sessionBudgetExceeded",
|
|
21442
|
+
"usageLimitExceeded",
|
|
21443
|
+
"serverOverloaded",
|
|
21444
|
+
"cyberPolicy",
|
|
21445
|
+
"misalignmentPolicyViolation",
|
|
21446
|
+
"internalServerError",
|
|
21447
|
+
"unauthorized",
|
|
21448
|
+
"badRequest",
|
|
21449
|
+
"threadRollbackFailed",
|
|
21450
|
+
"sandboxError",
|
|
21451
|
+
"other",
|
|
21452
|
+
"httpConnectionFailed",
|
|
21453
|
+
"responseStreamConnectionFailed",
|
|
21454
|
+
"responseStreamDisconnected",
|
|
21455
|
+
"responseTooManyFailedAttempts",
|
|
21456
|
+
"activeTurnNotSteerable"
|
|
21457
|
+
]);
|
|
21458
|
+
function snakeCase(value) {
|
|
21459
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
21460
|
+
}
|
|
21461
|
+
function codexErrorInfoCode(value, fallback) {
|
|
21462
|
+
const label = typeof value === "string" ? value : value && typeof value === "object" && !Array.isArray(value) ? Object.keys(value)[0] : undefined;
|
|
21463
|
+
return label && CODEX_ERROR_INFO_CODES.has(label) ? `codex.${snakeCase(label)}` : fallback;
|
|
21464
|
+
}
|
|
21465
|
+
function codexRpcErrorCode(value) {
|
|
21466
|
+
return typeof value === "number" && Number.isSafeInteger(value) ? `codex.rpc.${value}` : "codex.rpc_error";
|
|
21467
|
+
}
|
|
21297
21468
|
function rotateCodexQuotaSource() {
|
|
21298
21469
|
codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
21299
21470
|
codexQuotaSourceGeneration += 1;
|
|
@@ -21451,7 +21622,11 @@ class CodexEventNormalizer {
|
|
|
21451
21622
|
return this.replaceQuotaSnapshots(msg.result ?? {});
|
|
21452
21623
|
}
|
|
21453
21624
|
if (msg?.error && msg.id !== undefined) {
|
|
21454
|
-
return [{
|
|
21625
|
+
return [{
|
|
21626
|
+
kind: "error",
|
|
21627
|
+
code: codexRpcErrorCode(msg.error?.code),
|
|
21628
|
+
message: msg.error?.message ?? "Codex RPC error"
|
|
21629
|
+
}];
|
|
21455
21630
|
}
|
|
21456
21631
|
if (msg?.result?.thread?.id) {
|
|
21457
21632
|
return this.adoptAndInit(msg.result.thread.id);
|
|
@@ -21520,20 +21695,26 @@ class CodexEventNormalizer {
|
|
|
21520
21695
|
return [];
|
|
21521
21696
|
this.releaseUsageForTurn(params.threadId, params.turn.id);
|
|
21522
21697
|
if (params.turn.status === "failed") {
|
|
21698
|
+
const error51 = params.turn.error;
|
|
21523
21699
|
return [
|
|
21524
|
-
{
|
|
21700
|
+
{
|
|
21701
|
+
kind: "error",
|
|
21702
|
+
code: codexErrorInfoCode(error51?.codexErrorInfo, "codex.turn_failed"),
|
|
21703
|
+
message: error51?.message ?? "Codex turn failed"
|
|
21704
|
+
},
|
|
21525
21705
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
21526
21706
|
];
|
|
21527
21707
|
}
|
|
21528
|
-
if (params.turn.status === "interrupted") {
|
|
21529
|
-
return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21530
|
-
}
|
|
21531
21708
|
return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21532
21709
|
case "error":
|
|
21533
21710
|
if (params?.willRetry === true) {
|
|
21534
21711
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
21535
21712
|
}
|
|
21536
|
-
return [{
|
|
21713
|
+
return [{
|
|
21714
|
+
kind: "error",
|
|
21715
|
+
code: codexErrorInfoCode(params?.error?.codexErrorInfo, "codex.error"),
|
|
21716
|
+
message: params?.error?.message ?? params?.message ?? "Codex error"
|
|
21717
|
+
}];
|
|
21537
21718
|
case "thread/tokenUsage/updated":
|
|
21538
21719
|
return [];
|
|
21539
21720
|
case "account/rateLimits/updated":
|
|
@@ -21630,42 +21811,46 @@ class CodexEventNormalizer {
|
|
|
21630
21811
|
}
|
|
21631
21812
|
handleItemStarted(params) {
|
|
21632
21813
|
const t = params?.item?.type ?? params?.type;
|
|
21814
|
+
const callId = this.itemCallId(params);
|
|
21815
|
+
const identity = callId ? { callId } : {};
|
|
21633
21816
|
switch (t) {
|
|
21634
21817
|
case "commandExecution":
|
|
21635
|
-
return [{ kind: "tool_call", name: "shell", input: params?.item }];
|
|
21818
|
+
return [{ kind: "tool_call", ...identity, name: "shell", input: params?.item }];
|
|
21636
21819
|
case "contextCompaction":
|
|
21637
21820
|
return [{ kind: "compaction_started" }];
|
|
21638
21821
|
case "enteredReviewMode":
|
|
21639
21822
|
return [{ kind: "review_started" }];
|
|
21640
21823
|
case "fileChange":
|
|
21641
|
-
return [{ kind: "tool_call", name: "file_change", input: normalizeFileChangeInput(params?.item) }];
|
|
21824
|
+
return [{ kind: "tool_call", ...identity, name: "file_change", input: normalizeFileChangeInput(params?.item) }];
|
|
21642
21825
|
case "mcpToolCall":
|
|
21643
|
-
return [{ kind: "tool_call", name: `mcp_${params?.item?.name ?? "tool"}`, input: params?.item }];
|
|
21826
|
+
return [{ kind: "tool_call", ...identity, name: `mcp_${params?.item?.tool ?? params?.item?.name ?? "tool"}`, input: params?.item }];
|
|
21644
21827
|
case "webSearch":
|
|
21645
|
-
return [{ kind: "tool_call", name: "web_search", input: params?.item }];
|
|
21828
|
+
return [{ kind: "tool_call", ...identity, name: "web_search", input: params?.item }];
|
|
21646
21829
|
case "collabAgentToolCall":
|
|
21647
|
-
return [{ kind: "tool_call", name: "collab_tool_call", input: params?.item }];
|
|
21830
|
+
return [{ kind: "tool_call", ...identity, name: "collab_tool_call", input: params?.item }];
|
|
21648
21831
|
default:
|
|
21649
21832
|
return [];
|
|
21650
21833
|
}
|
|
21651
21834
|
}
|
|
21652
21835
|
handleItemCompleted(params) {
|
|
21653
21836
|
const t = params?.item?.type ?? params?.type;
|
|
21837
|
+
const callId = this.itemCallId(params);
|
|
21838
|
+
const identity = callId ? { callId } : {};
|
|
21654
21839
|
switch (t) {
|
|
21655
21840
|
case "commandExecution":
|
|
21656
|
-
return [{ kind: "tool_output", name: "shell" }];
|
|
21841
|
+
return [{ kind: "tool_output", ...identity, name: "shell" }];
|
|
21657
21842
|
case "contextCompaction":
|
|
21658
21843
|
return [{ kind: "compaction_finished" }];
|
|
21659
21844
|
case "exitedReviewMode":
|
|
21660
21845
|
return [{ kind: "review_finished" }];
|
|
21661
21846
|
case "fileChange":
|
|
21662
|
-
return [{ kind: "tool_output", name: "file_change" }];
|
|
21847
|
+
return [{ kind: "tool_output", ...identity, name: "file_change" }];
|
|
21663
21848
|
case "mcpToolCall":
|
|
21664
|
-
return [{ kind: "tool_output", name: `mcp_${params?.item?.name ?? "tool"}` }];
|
|
21849
|
+
return [{ kind: "tool_output", ...identity, name: `mcp_${params?.item?.tool ?? params?.item?.name ?? "tool"}` }];
|
|
21665
21850
|
case "webSearch":
|
|
21666
|
-
return [{ kind: "tool_output", name: "web_search" }];
|
|
21851
|
+
return [{ kind: "tool_output", ...identity, name: "web_search" }];
|
|
21667
21852
|
case "collabAgentToolCall":
|
|
21668
|
-
return [{ kind: "tool_output", name: "collab_tool_call" }];
|
|
21853
|
+
return [{ kind: "tool_output", ...identity, name: "collab_tool_call" }];
|
|
21669
21854
|
case "agentMessage":
|
|
21670
21855
|
return [{ kind: "assistant_message_completed", text: params?.item?.text ?? "" }];
|
|
21671
21856
|
case "reasoning":
|
|
@@ -21674,6 +21859,10 @@ class CodexEventNormalizer {
|
|
|
21674
21859
|
return [];
|
|
21675
21860
|
}
|
|
21676
21861
|
}
|
|
21862
|
+
itemCallId(params) {
|
|
21863
|
+
const value = params?.item?.id ?? params?.itemId;
|
|
21864
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
21865
|
+
}
|
|
21677
21866
|
}
|
|
21678
21867
|
|
|
21679
21868
|
// agent-driver/dist/adapters/codex/home.js
|
|
@@ -22144,6 +22333,16 @@ class CodexDriver {
|
|
|
22144
22333
|
get currentSessionId() {
|
|
22145
22334
|
return this.eventNormalizer.currentSessionId;
|
|
22146
22335
|
}
|
|
22336
|
+
async interrupt(_input, process3) {
|
|
22337
|
+
const threadId = this.eventNormalizer.currentSessionId;
|
|
22338
|
+
const turnId = this.eventNormalizer.currentTurnId;
|
|
22339
|
+
const stdin = process3.stdin;
|
|
22340
|
+
if (!threadId || !turnId || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
22341
|
+
return false;
|
|
22342
|
+
stdin.write(jsonRpcRequest("turn/interrupt", { threadId, turnId }, this.nextRequestId()) + `
|
|
22343
|
+
`);
|
|
22344
|
+
return true;
|
|
22345
|
+
}
|
|
22147
22346
|
buildTurnStart(threadId, text2) {
|
|
22148
22347
|
return jsonRpcRequest("turn/start", { threadId, input: [{ type: "text", text: text2 }] }, this.nextRequestId());
|
|
22149
22348
|
}
|
|
@@ -22643,7 +22842,7 @@ class CursorAcpLane {
|
|
|
22643
22842
|
return;
|
|
22644
22843
|
const result = record3(value);
|
|
22645
22844
|
if (!result || typeof result.stopReason !== "string" || !PROMPT_STOP_REASONS.has(result.stopReason)) {
|
|
22646
|
-
this.failPrompt(prompt, new Error("Cursor ACP prompt response did not contain a supported stopReason"));
|
|
22845
|
+
this.failPrompt(prompt, new Error("Cursor ACP prompt response did not contain a supported stopReason"), "cursor.invalid_stop_reason");
|
|
22647
22846
|
return;
|
|
22648
22847
|
}
|
|
22649
22848
|
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
@@ -22656,7 +22855,7 @@ class CursorAcpLane {
|
|
|
22656
22855
|
turnOwner: terminalOwner
|
|
22657
22856
|
});
|
|
22658
22857
|
}
|
|
22659
|
-
failPrompt(prompt, error51) {
|
|
22858
|
+
failPrompt(prompt, error51, code = "cursor.prompt_failed") {
|
|
22660
22859
|
if (this.currentPromptRequestId !== prompt.requestId)
|
|
22661
22860
|
return;
|
|
22662
22861
|
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
@@ -22665,6 +22864,7 @@ class CursorAcpLane {
|
|
|
22665
22864
|
this.openToolCalls.clear();
|
|
22666
22865
|
this.events.emit("runtime_event", {
|
|
22667
22866
|
kind: "error",
|
|
22867
|
+
code,
|
|
22668
22868
|
message: error51 instanceof Error ? error51.message : String(error51)
|
|
22669
22869
|
});
|
|
22670
22870
|
this.events.emit("runtime_event", {
|
|
@@ -22818,9 +23018,10 @@ class CursorAcpLane {
|
|
|
22818
23018
|
this.pending.delete(id);
|
|
22819
23019
|
if (message2.error !== undefined) {
|
|
22820
23020
|
const payload = record3(message2.error);
|
|
22821
|
-
|
|
23021
|
+
const rpcCode = typeof payload?.code === "number" && Number.isSafeInteger(payload.code) ? payload.code : undefined;
|
|
23022
|
+
this.failPrompt(pending.prompt, new CursorAcpRpcError(pending.method, rpcCode, rpcErrorMessage(message2.error)), rpcCode === undefined ? "cursor.rpc_error" : `cursor.rpc.${rpcCode}`);
|
|
22822
23023
|
} else if (!("result" in message2)) {
|
|
22823
|
-
this.failPrompt(pending.prompt, new Error("Cursor ACP response omitted result"));
|
|
23024
|
+
this.failPrompt(pending.prompt, new Error("Cursor ACP response omitted result"), "cursor.invalid_response");
|
|
22824
23025
|
} else {
|
|
22825
23026
|
this.completePrompt(pending.prompt, message2.result);
|
|
22826
23027
|
}
|
|
@@ -23105,7 +23306,11 @@ function parseModelRef(model) {
|
|
|
23105
23306
|
function messageFromError(value) {
|
|
23106
23307
|
const payload = record4(value);
|
|
23107
23308
|
const message2 = typeof payload?.message === "string" && payload.message.trim() ? payload.message : undefined;
|
|
23108
|
-
return message2
|
|
23309
|
+
return message2 ?? "OpenCode reported an inconsistent turn outcome";
|
|
23310
|
+
}
|
|
23311
|
+
function codeFromError(value) {
|
|
23312
|
+
const payload = record4(value);
|
|
23313
|
+
return payload?.type === "unknown" ? "opencode.unknown" : "opencode.step_failed";
|
|
23109
23314
|
}
|
|
23110
23315
|
|
|
23111
23316
|
class OpenCodeServiceLane {
|
|
@@ -23773,7 +23978,10 @@ class OpenCodeServiceLane {
|
|
|
23773
23978
|
root.outcomes.push({
|
|
23774
23979
|
seq,
|
|
23775
23980
|
ok: successful,
|
|
23776
|
-
...!successful ? {
|
|
23981
|
+
...!successful ? {
|
|
23982
|
+
code: "opencode.unsupported_finish",
|
|
23983
|
+
message: "OpenCode reported an unsupported final step outcome"
|
|
23984
|
+
} : {}
|
|
23777
23985
|
});
|
|
23778
23986
|
}
|
|
23779
23987
|
const tokens = record4(data.tokens);
|
|
@@ -23802,7 +24010,12 @@ class OpenCodeServiceLane {
|
|
|
23802
24010
|
break;
|
|
23803
24011
|
}
|
|
23804
24012
|
case "session.next.step.failed":
|
|
23805
|
-
root.outcomes.push({
|
|
24013
|
+
root.outcomes.push({
|
|
24014
|
+
seq,
|
|
24015
|
+
ok: false,
|
|
24016
|
+
code: codeFromError(data.error),
|
|
24017
|
+
message: messageFromError(data.error)
|
|
24018
|
+
});
|
|
23806
24019
|
break;
|
|
23807
24020
|
default:
|
|
23808
24021
|
break;
|
|
@@ -23982,11 +24195,11 @@ class OpenCodeServiceLane {
|
|
|
23982
24195
|
return;
|
|
23983
24196
|
const outcome = root.outcomes.filter((item) => item.seq > maxAdmission).sort((left, right) => left.seq - right.seq).at(-1);
|
|
23984
24197
|
if (!root.interrupted && !outcome) {
|
|
23985
|
-
this.settleRoot(root, false, "OpenCode drain settled without a durable turn outcome");
|
|
24198
|
+
this.settleRoot(root, false, "OpenCode drain settled without a durable turn outcome", "opencode.missing_outcome");
|
|
23986
24199
|
return;
|
|
23987
24200
|
}
|
|
23988
24201
|
if (outcome && !outcome.ok) {
|
|
23989
|
-
this.settleRoot(root, false, outcome.message ?? "OpenCode turn failed");
|
|
24202
|
+
this.settleRoot(root, false, outcome.message ?? "OpenCode turn failed", outcome.code ?? "opencode.turn_failed");
|
|
23990
24203
|
return;
|
|
23991
24204
|
}
|
|
23992
24205
|
this.settleRoot(root, true);
|
|
@@ -24012,7 +24225,7 @@ class OpenCodeServiceLane {
|
|
|
24012
24225
|
barrierStillCurrent(root, identity, generation) {
|
|
24013
24226
|
return this.activeRoot === root && root.generation === generation && root.pendingAdmissions === 0 && !root.interruptPending && this.isIdentity(identity) && this.identityMatches();
|
|
24014
24227
|
}
|
|
24015
|
-
settleRoot(root, success2, message2) {
|
|
24228
|
+
settleRoot(root, success2, message2, code = "opencode.turn_failed") {
|
|
24016
24229
|
if (this.activeRoot !== root)
|
|
24017
24230
|
return;
|
|
24018
24231
|
this.activeRoot = null;
|
|
@@ -24020,6 +24233,7 @@ class OpenCodeServiceLane {
|
|
|
24020
24233
|
if (!success2) {
|
|
24021
24234
|
this.events.emit("runtime_event", {
|
|
24022
24235
|
kind: "error",
|
|
24236
|
+
code,
|
|
24023
24237
|
message: message2 ?? "OpenCode turn failed"
|
|
24024
24238
|
});
|
|
24025
24239
|
}
|
|
@@ -24535,7 +24749,11 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
24535
24749
|
return [{ kind: "assistant_message_completed", text: d.content ?? "" }];
|
|
24536
24750
|
}
|
|
24537
24751
|
case "error":
|
|
24538
|
-
return [{
|
|
24752
|
+
return [{
|
|
24753
|
+
kind: "error",
|
|
24754
|
+
code: "pi.message_error",
|
|
24755
|
+
message: d.error?.errorMessage ?? "Pi error"
|
|
24756
|
+
}];
|
|
24539
24757
|
default:
|
|
24540
24758
|
return [];
|
|
24541
24759
|
}
|
|
@@ -25123,7 +25341,9 @@ class LogicalAgentSession {
|
|
|
25123
25341
|
interruptedTurnId;
|
|
25124
25342
|
processTurnEnded = false;
|
|
25125
25343
|
stopRequestId;
|
|
25126
|
-
|
|
25344
|
+
anonymousOutstandingToolUses = 0;
|
|
25345
|
+
outstandingToolCallIds = new Set;
|
|
25346
|
+
toolLifecycleMismatchCount = 0;
|
|
25127
25347
|
compacting = false;
|
|
25128
25348
|
reviewing = false;
|
|
25129
25349
|
steeringDeliveries = new Set;
|
|
@@ -25313,6 +25533,9 @@ class LogicalAgentSession {
|
|
|
25313
25533
|
queueDwellCount: this.metricValue(this.queueDwellCount),
|
|
25314
25534
|
queueDwellTotalMs: this.metricValue(this.queueDwellTotalMs),
|
|
25315
25535
|
sseReconnectCount: this.metricValue(this.sseReconnectCount),
|
|
25536
|
+
outstandingToolUses: this.outstandingToolUseCount(),
|
|
25537
|
+
anonymousOutstandingToolUses: this.metricValue(this.anonymousOutstandingToolUses),
|
|
25538
|
+
toolLifecycleMismatchCount: this.metricValue(this.toolLifecycleMismatchCount),
|
|
25316
25539
|
resumeOutcome: this.resumeOutcome,
|
|
25317
25540
|
terminalOwnerKind: this.adapter.execution.terminalOwnership
|
|
25318
25541
|
}
|
|
@@ -25632,15 +25855,36 @@ class LogicalAgentSession {
|
|
|
25632
25855
|
}
|
|
25633
25856
|
return;
|
|
25634
25857
|
case "tool_call":
|
|
25635
|
-
|
|
25636
|
-
|
|
25637
|
-
|
|
25858
|
+
if (!turnId) {
|
|
25859
|
+
this.toolLifecycleMismatchCount += 1;
|
|
25860
|
+
return;
|
|
25861
|
+
}
|
|
25862
|
+
if (!this.startToolUse(event.callId))
|
|
25863
|
+
return;
|
|
25864
|
+
const startedCallId = this.toolCallId(event.callId);
|
|
25865
|
+
this.emit({
|
|
25866
|
+
type: "tool_started",
|
|
25867
|
+
turnId,
|
|
25868
|
+
...startedCallId ? { callId: startedCallId } : {},
|
|
25869
|
+
name: event.name,
|
|
25870
|
+
input: jsonValue(event.input)
|
|
25871
|
+
});
|
|
25638
25872
|
return;
|
|
25639
25873
|
case "tool_output":
|
|
25640
|
-
|
|
25641
|
-
|
|
25642
|
-
|
|
25643
|
-
|
|
25874
|
+
if (!turnId) {
|
|
25875
|
+
this.toolLifecycleMismatchCount += 1;
|
|
25876
|
+
return;
|
|
25877
|
+
}
|
|
25878
|
+
if (!this.finishToolUse(event.callId))
|
|
25879
|
+
return;
|
|
25880
|
+
const finishedCallId = this.toolCallId(event.callId);
|
|
25881
|
+
this.emit({
|
|
25882
|
+
type: "tool_finished",
|
|
25883
|
+
turnId,
|
|
25884
|
+
...finishedCallId ? { callId: finishedCallId } : {},
|
|
25885
|
+
name: event.name
|
|
25886
|
+
});
|
|
25887
|
+
if (this.outstandingToolUseCount() === 0 && !this.toolBoundaryFlushDisabled)
|
|
25644
25888
|
this.flushSafeBoundaryQueue();
|
|
25645
25889
|
return;
|
|
25646
25890
|
case "compaction_started":
|
|
@@ -25696,7 +25940,7 @@ class LogicalAgentSession {
|
|
|
25696
25940
|
}
|
|
25697
25941
|
case "error":
|
|
25698
25942
|
this.toolBoundaryFlushDisabled = true;
|
|
25699
|
-
this.turnError = driverError("process", "runtime_error", event.message, true);
|
|
25943
|
+
this.turnError = driverError("process", stableErrorCode(event.code, "runtime_error"), event.message, true);
|
|
25700
25944
|
this.emit({
|
|
25701
25945
|
type: "diagnostic",
|
|
25702
25946
|
turnId,
|
|
@@ -25783,7 +26027,7 @@ class LogicalAgentSession {
|
|
|
25783
26027
|
this.activeTurn = undefined;
|
|
25784
26028
|
this.turnError = undefined;
|
|
25785
26029
|
this.interruptedTurnId = undefined;
|
|
25786
|
-
this.
|
|
26030
|
+
this.clearOutstandingToolUses();
|
|
25787
26031
|
this.compacting = false;
|
|
25788
26032
|
this.reviewing = false;
|
|
25789
26033
|
this.toolBoundaryFlushDisabled = false;
|
|
@@ -25807,7 +26051,7 @@ class LogicalAgentSession {
|
|
|
25807
26051
|
return this.safeBoundaryFlush;
|
|
25808
26052
|
}
|
|
25809
26053
|
canFlushSafeBoundaryQueue() {
|
|
25810
|
-
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.
|
|
26054
|
+
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;
|
|
25811
26055
|
}
|
|
25812
26056
|
async drainSafeBoundaryQueue() {
|
|
25813
26057
|
while (this.canFlushSafeBoundaryQueue()) {
|
|
@@ -25988,7 +26232,7 @@ class LogicalAgentSession {
|
|
|
25988
26232
|
return "compacting";
|
|
25989
26233
|
if (this.reviewing)
|
|
25990
26234
|
return "reviewing";
|
|
25991
|
-
if (this.
|
|
26235
|
+
if (this.outstandingToolUseCount() > 0)
|
|
25992
26236
|
return "tool_wait";
|
|
25993
26237
|
if (this.activeTurn)
|
|
25994
26238
|
return "working";
|
|
@@ -25998,6 +26242,46 @@ class LogicalAgentSession {
|
|
|
25998
26242
|
const now = this.host.now();
|
|
25999
26243
|
return Number.isFinite(now) && now >= 0 ? now : 0;
|
|
26000
26244
|
}
|
|
26245
|
+
outstandingToolUseCount() {
|
|
26246
|
+
return this.anonymousOutstandingToolUses + this.outstandingToolCallIds.size;
|
|
26247
|
+
}
|
|
26248
|
+
startToolUse(rawCallId) {
|
|
26249
|
+
const callId = this.toolCallId(rawCallId);
|
|
26250
|
+
if (!callId) {
|
|
26251
|
+
this.anonymousOutstandingToolUses += 1;
|
|
26252
|
+
return true;
|
|
26253
|
+
}
|
|
26254
|
+
if (this.outstandingToolCallIds.has(callId)) {
|
|
26255
|
+
this.toolLifecycleMismatchCount += 1;
|
|
26256
|
+
return false;
|
|
26257
|
+
}
|
|
26258
|
+
this.outstandingToolCallIds.add(callId);
|
|
26259
|
+
return true;
|
|
26260
|
+
}
|
|
26261
|
+
finishToolUse(rawCallId) {
|
|
26262
|
+
const callId = this.toolCallId(rawCallId);
|
|
26263
|
+
if (!callId) {
|
|
26264
|
+
if (this.anonymousOutstandingToolUses === 0) {
|
|
26265
|
+
this.toolLifecycleMismatchCount += 1;
|
|
26266
|
+
return false;
|
|
26267
|
+
}
|
|
26268
|
+
this.anonymousOutstandingToolUses -= 1;
|
|
26269
|
+
return true;
|
|
26270
|
+
}
|
|
26271
|
+
if (!this.outstandingToolCallIds.delete(callId)) {
|
|
26272
|
+
this.toolLifecycleMismatchCount += 1;
|
|
26273
|
+
return false;
|
|
26274
|
+
}
|
|
26275
|
+
return true;
|
|
26276
|
+
}
|
|
26277
|
+
clearOutstandingToolUses() {
|
|
26278
|
+
this.anonymousOutstandingToolUses = 0;
|
|
26279
|
+
this.outstandingToolCallIds.clear();
|
|
26280
|
+
}
|
|
26281
|
+
toolCallId(rawCallId) {
|
|
26282
|
+
const callId = rawCallId?.trim();
|
|
26283
|
+
return callId && callId.length <= 1024 ? callId : undefined;
|
|
26284
|
+
}
|
|
26001
26285
|
metricValue(value) {
|
|
26002
26286
|
return Number.isFinite(value) && value >= 0 ? value : 0;
|
|
26003
26287
|
}
|
|
@@ -27636,10 +27920,11 @@ var DEFAULT_CAPABILITY_RESOLVER = (method, pathname) => {
|
|
|
27636
27920
|
const isMessagesDoor = /\/channels\/[^/]+\/messages(\/|$|\?)/.test(pathname);
|
|
27637
27921
|
if (isMessagesDoor)
|
|
27638
27922
|
return method === "GET" ? "read" : "send";
|
|
27923
|
+
if (/\/messages\/[^/]+\/properties(\/|$|\?)/.test(pathname)) {
|
|
27924
|
+
return method === "GET" ? "read" : "send";
|
|
27925
|
+
}
|
|
27639
27926
|
if (/\/messages\/[^/]+\/reactions\//.test(pathname))
|
|
27640
27927
|
return "send";
|
|
27641
|
-
if ((method === "PUT" || method === "DELETE") && /\/messages\/[^/]+\/marks(\/|$|\?)/.test(pathname))
|
|
27642
|
-
return "send";
|
|
27643
27928
|
if (method === "GET" && /\/users\/me\/marks(\/|$|\?)/.test(pathname))
|
|
27644
27929
|
return "read";
|
|
27645
27930
|
if (method === "GET" && /\/messages\/[^/]+(\?|$)/.test(pathname))
|
|
@@ -27680,6 +27965,12 @@ function isCanonicalChannelScope(channel2) {
|
|
|
27680
27965
|
return false;
|
|
27681
27966
|
}
|
|
27682
27967
|
}
|
|
27968
|
+
function propertyAuditMetadata(method, pathname, requestUrl) {
|
|
27969
|
+
if (method !== "PUT" && method !== "DELETE" || !/^\/api\/community\/messages\/[^/]+\/properties$/.test(pathname))
|
|
27970
|
+
return;
|
|
27971
|
+
const type = new URL2(requestUrl, "http://placeholder").searchParams.get("type");
|
|
27972
|
+
return type === "emoji" || type === "tag" || type === "mark" ? { propertyType: type } : undefined;
|
|
27973
|
+
}
|
|
27683
27974
|
function parseLocalMessageReminderBody(body, agentId) {
|
|
27684
27975
|
let value;
|
|
27685
27976
|
try {
|
|
@@ -27818,7 +28109,12 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
27818
28109
|
}
|
|
27819
28110
|
if (onProxyRequest) {
|
|
27820
28111
|
try {
|
|
27821
|
-
|
|
28112
|
+
const method = req.method ?? "GET";
|
|
28113
|
+
const metadata = propertyAuditMetadata(method, pathname, req.url ?? pathname);
|
|
28114
|
+
if (metadata)
|
|
28115
|
+
onProxyRequest(reg.agentId, method, pathname, metadata);
|
|
28116
|
+
else
|
|
28117
|
+
onProxyRequest(reg.agentId, method, pathname);
|
|
27822
28118
|
} catch {}
|
|
27823
28119
|
}
|
|
27824
28120
|
const outHeaders = { ...req.headers };
|
|
@@ -28101,6 +28397,7 @@ function reduceManager(state, event) {
|
|
|
28101
28397
|
if ((lease.state === "active" || lease.state === "suspect_active") && lease.outstandingToolUses !== undefined) {
|
|
28102
28398
|
const unblockedLease = { ...lease };
|
|
28103
28399
|
delete unblockedLease.outstandingToolUses;
|
|
28400
|
+
delete unblockedLease.outstandingToolCallIds;
|
|
28104
28401
|
a.execution.lease = unblockedLease;
|
|
28105
28402
|
}
|
|
28106
28403
|
});
|
|
@@ -28361,26 +28658,40 @@ function onTurnToolLifecycle(state, event, lifecycle) {
|
|
|
28361
28658
|
const matchesTerminal = lifecycle === "started" && current.state === "none" && current.lastTerminal !== null && sameIdentity(current.lastTerminal.identity, identity);
|
|
28362
28659
|
if (!matchesActive && !matchesTerminal)
|
|
28363
28660
|
return { state, effects: [] };
|
|
28364
|
-
if (lifecycle === "finished" && matchesActive && (current.outstandingToolUses ?? 0) === 0) {
|
|
28365
|
-
return { state, effects: [] };
|
|
28366
|
-
}
|
|
28367
28661
|
return mutate(state, event.agentId, (agent2) => {
|
|
28368
28662
|
if (!matchesSession(agent2, event.sessionInstanceId))
|
|
28369
28663
|
return;
|
|
28370
28664
|
const lease = agent2.execution.lease;
|
|
28665
|
+
const callId = normalizedToolCallId(event.callId);
|
|
28371
28666
|
if ((lease.state === "active" || lease.state === "suspect_active") && sameIdentity(lease.identity, identity)) {
|
|
28372
|
-
const
|
|
28667
|
+
const identified = new Set(lease.outstandingToolCallIds ?? []);
|
|
28668
|
+
const currentCount = lease.outstandingToolUses ?? 0;
|
|
28669
|
+
const anonymousCount = Math.max(0, currentCount - identified.size);
|
|
28670
|
+
if (lifecycle === "started") {
|
|
28671
|
+
if (callId && identified.has(callId))
|
|
28672
|
+
return;
|
|
28673
|
+
if (callId)
|
|
28674
|
+
identified.add(callId);
|
|
28675
|
+
} else if (callId) {
|
|
28676
|
+
if (!identified.delete(callId))
|
|
28677
|
+
return;
|
|
28678
|
+
} else if (anonymousCount === 0) {
|
|
28679
|
+
return;
|
|
28680
|
+
}
|
|
28681
|
+
const outstandingToolUses = currentCount + (lifecycle === "started" ? 1 : -1);
|
|
28373
28682
|
if (outstandingToolUses > 0) {
|
|
28374
28683
|
agent2.execution.lease = {
|
|
28375
28684
|
...lease,
|
|
28376
28685
|
lastWorkAt: event.nowMs,
|
|
28377
28686
|
nativeDeadlineAt: event.nowMs + agent2.turnSilence.normalBudgetMs,
|
|
28378
28687
|
recoveryExtensionsUsed: 0,
|
|
28379
|
-
outstandingToolUses
|
|
28688
|
+
outstandingToolUses,
|
|
28689
|
+
...identified.size > 0 ? { outstandingToolCallIds: [...identified] } : {}
|
|
28380
28690
|
};
|
|
28381
28691
|
} else {
|
|
28382
28692
|
const unblockedLease = { ...lease };
|
|
28383
28693
|
delete unblockedLease.outstandingToolUses;
|
|
28694
|
+
delete unblockedLease.outstandingToolCallIds;
|
|
28384
28695
|
agent2.execution.lease = {
|
|
28385
28696
|
...unblockedLease,
|
|
28386
28697
|
lastWorkAt: event.nowMs,
|
|
@@ -28399,6 +28710,7 @@ function onTurnToolLifecycle(state, event, lifecycle) {
|
|
|
28399
28710
|
nativeDeadlineAt: event.nowMs + agent2.turnSilence.normalBudgetMs,
|
|
28400
28711
|
recoveryExtensionsUsed: 0,
|
|
28401
28712
|
outstandingToolUses: 1,
|
|
28713
|
+
...callId ? { outstandingToolCallIds: [callId] } : {},
|
|
28402
28714
|
reason: "work_after_terminal"
|
|
28403
28715
|
};
|
|
28404
28716
|
}
|
|
@@ -28562,6 +28874,10 @@ function identityOf(event) {
|
|
|
28562
28874
|
function sameIdentity(left, right) {
|
|
28563
28875
|
return left.sessionInstanceId === right.sessionInstanceId && left.turnId === right.turnId;
|
|
28564
28876
|
}
|
|
28877
|
+
function normalizedToolCallId(rawCallId) {
|
|
28878
|
+
const callId = rawCallId?.trim();
|
|
28879
|
+
return callId && callId.length <= 1024 ? callId : undefined;
|
|
28880
|
+
}
|
|
28565
28881
|
function leaseIsWorking(lease) {
|
|
28566
28882
|
return lease.state === "active" || lease.state === "suspect_active";
|
|
28567
28883
|
}
|
|
@@ -28783,13 +29099,13 @@ function cliCommandsSection() {
|
|
|
28783
29099
|
"",
|
|
28784
29100
|
"### Messaging",
|
|
28785
29101
|
"",
|
|
28786
|
-
`1. \`${CLI} inbox pull\` — fetch unread messages
|
|
29102
|
+
`1. \`${CLI} inbox pull\` — fetch unread messages and advance their read waterlines.`,
|
|
28787
29103
|
`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\`.`,
|
|
28788
29104
|
`3. \`${CLI} message attachment upload --target <ref> --file <path>\` — upload a file; ` + `returns an id stable across pending→persisted.`,
|
|
28789
29105
|
`4. \`${CLI} message attachment download --id <id> [--out <path>]\` — download any ` + `attachment you can see (or your own pending uploads).`,
|
|
28790
|
-
`5. \`${CLI} message
|
|
28791
|
-
`6. \`${CLI} message
|
|
28792
|
-
`7. \`${CLI} message
|
|
29106
|
+
`5. \`${CLI} message property set --target <full-message-ref> --json <json>\` — add a supported property value to a message.`,
|
|
29107
|
+
`6. \`${CLI} message property list --target <full-message-ref>\` — list the message's current properties and supported capabilities.`,
|
|
29108
|
+
`7. \`${CLI} message property remove --target <full-message-ref> --json <json>\` — remove a supported property value from a message.`,
|
|
28793
29109
|
`8. \`${CLI} message mark list\` — list every currently visible marked message with its full content.`,
|
|
28794
29110
|
"",
|
|
28795
29111
|
"### Servers",
|
|
@@ -28797,12 +29113,14 @@ function cliCommandsSection() {
|
|
|
28797
29113
|
`1. \`${CLI} server list\` — list your servers.`,
|
|
28798
29114
|
`2. \`${CLI} server member --server <name#discriminator>\` — list a server's members.`,
|
|
28799
29115
|
`3. \`${CLI} server join --invite <link>\` — join via invite link or token.`,
|
|
29116
|
+
`4. \`${CLI} server leave --server <name#NNNN>\` — leave a server you belong to. A server owner cannot leave.`,
|
|
28800
29117
|
"",
|
|
28801
29118
|
"### Channels",
|
|
28802
29119
|
"",
|
|
28803
29120
|
`1. \`${CLI} channel list --server <name#discriminator>\` — list top-level channels, grouped by ` + `category; each is marked \`public\` or \`private\`.`,
|
|
28804
29121
|
`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.",
|
|
28805
29122
|
`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).`,
|
|
29123
|
+
`4. \`${CLI} channel leave --channel <ref>\` — leave a thread or private channel/forum. Public channels require leaving their server; DMs cannot be left.`,
|
|
28806
29124
|
"",
|
|
28807
29125
|
"### Friends",
|
|
28808
29126
|
"",
|
|
@@ -28855,6 +29173,15 @@ function messagingSection() {
|
|
|
28855
29173
|
"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.",
|
|
28856
29174
|
"Write every message body in the stdin/heredoc block; never place it directly on the command line.",
|
|
28857
29175
|
"",
|
|
29176
|
+
"### Message properties",
|
|
29177
|
+
"",
|
|
29178
|
+
`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`.",
|
|
29179
|
+
"",
|
|
29180
|
+
`- \`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"}'\`.`,
|
|
29181
|
+
`- \`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"]}'\`.`,
|
|
29182
|
+
`- \`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.`,
|
|
29183
|
+
"- `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.",
|
|
29184
|
+
"",
|
|
28858
29185
|
"### Context refs",
|
|
28859
29186
|
"",
|
|
28860
29187
|
"Path-style refs:",
|
|
@@ -28967,6 +29294,7 @@ function criticalRulesSection() {
|
|
|
28967
29294
|
`- **\`${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.`,
|
|
28968
29295
|
"- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
|
|
28969
29296
|
"- **Match the sender's language.** Reply in the language they wrote in.",
|
|
29297
|
+
`- **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.`,
|
|
28970
29298
|
"- **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."
|
|
28971
29299
|
].join(`
|
|
28972
29300
|
`);
|
|
@@ -28979,7 +29307,7 @@ function executionModelSection() {
|
|
|
28979
29307
|
"",
|
|
28980
29308
|
"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.",
|
|
28981
29309
|
"",
|
|
28982
|
-
"`inbox pull` advances your read waterline
|
|
29310
|
+
"`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."
|
|
28983
29311
|
].join(`
|
|
28984
29312
|
`);
|
|
28985
29313
|
}
|
|
@@ -29051,9 +29379,9 @@ function workspaceMemorySection(config2) {
|
|
|
29051
29379
|
"",
|
|
29052
29380
|
"### Outstanding work marks",
|
|
29053
29381
|
"",
|
|
29054
|
-
"Marks are the durable work queue. If a message requires work beyond an immediate reply, " + `acknowledge it, then run \`${CLI} message
|
|
29382
|
+
"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.",
|
|
29055
29383
|
"",
|
|
29056
|
-
"Keep it marked while the work is active, queued, or blocked; report blockers where the task " + `came from. Run \`${CLI} message
|
|
29384
|
+
"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.",
|
|
29057
29385
|
"",
|
|
29058
29386
|
"If `inbox pull` returns a `markedReminder`, run " + `\`${CLI} message mark list\` before taking new work. Do not copy marked tasks into local files.`
|
|
29059
29387
|
].join(`
|
|
@@ -29106,7 +29434,7 @@ function toLocalISO(iso) {
|
|
|
29106
29434
|
}
|
|
29107
29435
|
|
|
29108
29436
|
// src/manager/managerRuntime.ts
|
|
29109
|
-
import { randomUUID as
|
|
29437
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
29110
29438
|
var SESSION_STOP_GRACE_MS2 = 2000;
|
|
29111
29439
|
function normalizeTerminationCause(value) {
|
|
29112
29440
|
return value === "runtime_error" || value === "killed_stalled" ? value : "other";
|
|
@@ -29343,7 +29671,7 @@ class AgentProcessManager {
|
|
|
29343
29671
|
liveBackendIds = new Map;
|
|
29344
29672
|
activeSpawnState = new Map;
|
|
29345
29673
|
publishedAgentActivity = new Map;
|
|
29346
|
-
traceProcessNonce =
|
|
29674
|
+
traceProcessNonce = randomUUID6();
|
|
29347
29675
|
nextSpawnOrdinal = 1;
|
|
29348
29676
|
nextDaemonTurnOrdinal = 1;
|
|
29349
29677
|
nextDeliveryOrdinal = 1;
|
|
@@ -29619,6 +29947,24 @@ class AgentProcessManager {
|
|
|
29619
29947
|
if (this.sessions.get(agentId) === session2)
|
|
29620
29948
|
this.sessions.delete(agentId);
|
|
29621
29949
|
}
|
|
29950
|
+
async interrupt(agentId) {
|
|
29951
|
+
const session2 = this.sessions.get(agentId);
|
|
29952
|
+
if (!session2)
|
|
29953
|
+
return;
|
|
29954
|
+
const result = await session2.interrupt({ requestId: randomUUID6(), reason: "owner_request" });
|
|
29955
|
+
if (result.status !== "accepted")
|
|
29956
|
+
return;
|
|
29957
|
+
this.log.info("agent turn interrupt accepted", {
|
|
29958
|
+
agentId,
|
|
29959
|
+
sessionInstanceId: session2.sessionInstanceId,
|
|
29960
|
+
turnId: result.turnId
|
|
29961
|
+
});
|
|
29962
|
+
try {
|
|
29963
|
+
this.opts.onBotAuditEvent?.(agentId, { kind: "turn_interrupt", payload: { status: "accepted" } }, this.auditContext(agentId));
|
|
29964
|
+
} catch (err) {
|
|
29965
|
+
this.log.debug("audit emit failed (turn interrupt)", { agentId, err: String(err) });
|
|
29966
|
+
}
|
|
29967
|
+
}
|
|
29622
29968
|
async stopAll() {
|
|
29623
29969
|
if (this.tickTimer) {
|
|
29624
29970
|
clearInterval(this.tickTimer);
|
|
@@ -30116,7 +30462,7 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30116
30462
|
case "reset_idle_session": {
|
|
30117
30463
|
const spawnState = this.activeSpawnState.get(effect.agentId);
|
|
30118
30464
|
const completion = {
|
|
30119
|
-
eventId: `bae_${
|
|
30465
|
+
eventId: `bae_${randomUUID6()}`,
|
|
30120
30466
|
occurredAt: new Date(this.now()).toISOString()
|
|
30121
30467
|
};
|
|
30122
30468
|
const persisted = this.forgetSession(effect.agentId, "reset_session", effect.sessionId, completion);
|
|
@@ -30511,11 +30857,12 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30511
30857
|
emitErrorAudit(agentId, scope, code, rawMessage) {
|
|
30512
30858
|
if (!this.opts.onBotAuditEvent)
|
|
30513
30859
|
return;
|
|
30860
|
+
const stableCode = /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : "runtime_error";
|
|
30514
30861
|
const message2 = scrubRuntimeErrorDiagnosticText(rawMessage).slice(0, AUDIT_ERROR_MESSAGE_MAX_LEN);
|
|
30515
30862
|
try {
|
|
30516
30863
|
this.opts.onBotAuditEvent(agentId, {
|
|
30517
30864
|
kind: "error",
|
|
30518
|
-
payload: { scope, code, message: message2, model: this.currentModelFor(agentId) }
|
|
30865
|
+
payload: { scope, code: stableCode, message: message2, model: this.currentModelFor(agentId) }
|
|
30519
30866
|
}, {
|
|
30520
30867
|
sessionId: this.liveSessions.get(agentId) ?? null,
|
|
30521
30868
|
launchId: this.launchIds.get(agentId) ?? null
|
|
@@ -30540,18 +30887,18 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30540
30887
|
return;
|
|
30541
30888
|
}
|
|
30542
30889
|
const sessionSuperseded = owner.superseded;
|
|
30543
|
-
const
|
|
30544
|
-
if (
|
|
30545
|
-
this.emitErrorAudit(agentId, "runtime",
|
|
30890
|
+
const runtimeError = event.type === "session_failed" ? event.error : event.type === "turn_completed" && event.result.outcome === "failed" ? event.result.error : undefined;
|
|
30891
|
+
if (runtimeError !== undefined && !sessionSuperseded) {
|
|
30892
|
+
this.emitErrorAudit(agentId, "runtime", runtimeError.code, runtimeError.message);
|
|
30546
30893
|
if (this.nonCleanEndMarker.get(agentId)?.cause !== "killed_stalled") {
|
|
30547
|
-
this.nonCleanEndMarker.set(agentId, { cause: "runtime_error", detail:
|
|
30894
|
+
this.nonCleanEndMarker.set(agentId, { cause: "runtime_error", detail: runtimeError.message });
|
|
30548
30895
|
}
|
|
30549
30896
|
const agent2 = this.state.agents[agentId];
|
|
30550
30897
|
if (agent2?.resetting && agent2.resettingSince !== null && this.now() - agent2.resettingSince >= this.state.resetStuckThresholdMs) {
|
|
30551
30898
|
this.log.warn("runtime error during a stuck reset window", {
|
|
30552
30899
|
agentId,
|
|
30553
30900
|
resettingForMs: this.now() - agent2.resettingSince,
|
|
30554
|
-
message:
|
|
30901
|
+
message: runtimeError.message
|
|
30555
30902
|
});
|
|
30556
30903
|
}
|
|
30557
30904
|
}
|
|
@@ -30646,9 +30993,9 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30646
30993
|
case "assistant_message_completed":
|
|
30647
30994
|
return { type: "turn_work", turnId: event.turnId };
|
|
30648
30995
|
case "tool_started":
|
|
30649
|
-
return { type: "turn_tool_started", turnId: event.turnId };
|
|
30996
|
+
return { type: "turn_tool_started", turnId: event.turnId, callId: event.callId };
|
|
30650
30997
|
case "tool_finished":
|
|
30651
|
-
return { type: "turn_tool_finished", turnId: event.turnId };
|
|
30998
|
+
return { type: "turn_tool_finished", turnId: event.turnId, callId: event.callId };
|
|
30652
30999
|
case "compaction_started":
|
|
30653
31000
|
case "compaction_finished":
|
|
30654
31001
|
case "review_started":
|
|
@@ -31101,6 +31448,10 @@ class AgentRouter {
|
|
|
31101
31448
|
}
|
|
31102
31449
|
break;
|
|
31103
31450
|
}
|
|
31451
|
+
case "agent:interrupt": {
|
|
31452
|
+
await this.opts.manager.interrupt(cmd.agentId);
|
|
31453
|
+
break;
|
|
31454
|
+
}
|
|
31104
31455
|
case "agent:stop":
|
|
31105
31456
|
this.log.info("agent:stop received", { agentId: cmd.agentId });
|
|
31106
31457
|
try {
|
|
@@ -32543,7 +32894,7 @@ class MessageReminderScheduler {
|
|
|
32543
32894
|
}
|
|
32544
32895
|
|
|
32545
32896
|
// src/manager/agentDriverHost.ts
|
|
32546
|
-
import { randomUUID as
|
|
32897
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32547
32898
|
import { homedir as homedir4 } from "node:os";
|
|
32548
32899
|
import { join as join13 } from "node:path";
|
|
32549
32900
|
|
|
@@ -32699,7 +33050,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
32699
33050
|
onRawLine?.(event.text);
|
|
32700
33051
|
},
|
|
32701
33052
|
now: () => Date.now(),
|
|
32702
|
-
createId: () =>
|
|
33053
|
+
createId: () => randomUUID7()
|
|
32703
33054
|
};
|
|
32704
33055
|
}
|
|
32705
33056
|
|
|
@@ -32778,7 +33129,7 @@ class DaemonSelfSleepScheduler {
|
|
|
32778
33129
|
// src/telemetry/dailyTokenUsage.ts
|
|
32779
33130
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32780
33131
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
32781
|
-
import { randomUUID as
|
|
33132
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
32782
33133
|
var TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
32783
33134
|
var TOKEN_USAGE_RECOVERY_DAYS = 2;
|
|
32784
33135
|
var TOKEN_USAGE_RETENTION_DAYS = TOKEN_USAGE_WINDOW_DAYS + TOKEN_USAGE_RECOVERY_DAYS;
|
|
@@ -32949,7 +33300,7 @@ class DailyTokenUsageStore {
|
|
|
32949
33300
|
async persist() {
|
|
32950
33301
|
const directory = dirname6(this.filePath);
|
|
32951
33302
|
await mkdir(directory, { recursive: true, mode: 448 });
|
|
32952
|
-
const temporary = `${this.filePath}.${
|
|
33303
|
+
const temporary = `${this.filePath}.${randomUUID8()}.tmp`;
|
|
32953
33304
|
try {
|
|
32954
33305
|
const file2 = await open(temporary, "wx", 384);
|
|
32955
33306
|
try {
|
|
@@ -33031,15 +33382,17 @@ function createRuntimeRawLineTap(args) {
|
|
|
33031
33382
|
}
|
|
33032
33383
|
function deriveAuditLogSubcommand(pathname, method) {
|
|
33033
33384
|
const canonical = pathname.split("?")[0] ?? pathname;
|
|
33034
|
-
if (/^\/api\/community\/messages\/[^/]+\/
|
|
33035
|
-
|
|
33036
|
-
|
|
33385
|
+
if (/^\/api\/community\/messages\/[^/]+\/properties$/.test(canonical)) {
|
|
33386
|
+
if (method === "GET")
|
|
33387
|
+
return "messagePropertyList";
|
|
33037
33388
|
if (method === "PUT")
|
|
33038
|
-
return "
|
|
33389
|
+
return "messagePropertySet";
|
|
33039
33390
|
if (method === "DELETE")
|
|
33040
|
-
return "
|
|
33391
|
+
return "messagePropertyRemove";
|
|
33041
33392
|
return null;
|
|
33042
33393
|
}
|
|
33394
|
+
if (/^\/api\/community\/messages\/[^/]+\/reactions\//.test(canonical))
|
|
33395
|
+
return "reactAdd";
|
|
33043
33396
|
if (method === "GET" && /^\/api\/community\/users\/me\/marks$/.test(canonical))
|
|
33044
33397
|
return "markList";
|
|
33045
33398
|
if (/^\/api\/community\/channels\/[^/]+\/messages\/seq\//.test(canonical))
|
|
@@ -33205,14 +33558,14 @@ async function createDaemon(opts) {
|
|
|
33205
33558
|
log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
|
|
33206
33559
|
},
|
|
33207
33560
|
onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
|
|
33208
|
-
onProxyRequest: (agentId, method, pathname) => {
|
|
33561
|
+
onProxyRequest: (agentId, method, pathname, metadata) => {
|
|
33209
33562
|
const subcommand = deriveAuditLogSubcommand(pathname, method);
|
|
33210
33563
|
if (!subcommand)
|
|
33211
33564
|
return;
|
|
33212
33565
|
const context = managerRef?.auditContext(agentId);
|
|
33213
33566
|
emitBotAuditEvent(agentId, {
|
|
33214
33567
|
kind: "cli_invocation",
|
|
33215
|
-
payload: { subcommand }
|
|
33568
|
+
payload: { subcommand, ...metadata ? { propertyType: metadata.propertyType } : {} }
|
|
33216
33569
|
}, context);
|
|
33217
33570
|
emitImplicitTypingStopOnSend({
|
|
33218
33571
|
subcommand,
|
|
@@ -34134,10 +34487,17 @@ function projectFsm(row, targetAgentId) {
|
|
|
34134
34487
|
"queueDwellTotalMs",
|
|
34135
34488
|
"sseReconnectCount"
|
|
34136
34489
|
];
|
|
34137
|
-
const
|
|
34490
|
+
const toolMetricKeys = [
|
|
34491
|
+
"outstandingToolUses",
|
|
34492
|
+
"anonymousOutstandingToolUses",
|
|
34493
|
+
"toolLifecycleMismatchCount"
|
|
34494
|
+
];
|
|
34495
|
+
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;
|
|
34138
34496
|
if (hasMetrics) {
|
|
34139
34497
|
if (!metricKeys.every((key) => copyFiniteNumber(row, output, key)))
|
|
34140
34498
|
return null;
|
|
34499
|
+
if (!toolMetricKeys.every((key) => copyInteger(row, output, key, { optional: true })))
|
|
34500
|
+
return null;
|
|
34141
34501
|
const resumeOutcome = enumValue(row.resumeOutcome, RESUME_OUTCOMES);
|
|
34142
34502
|
const terminalOwnerKind = enumValue(row.terminalOwnerKind, TERMINAL_OWNER_KINDS);
|
|
34143
34503
|
if (!resumeOutcome || !terminalOwnerKind)
|
|
@@ -36849,7 +37209,7 @@ ${MESSAGE_SEND_STDIN_POLICY}`);
|
|
|
36849
37209
|
}
|
|
36850
37210
|
replyToSeq = n;
|
|
36851
37211
|
}
|
|
36852
|
-
const nonce =
|
|
37212
|
+
const nonce = randomUUID11();
|
|
36853
37213
|
const res = await sendWithRetry(api2, {
|
|
36854
37214
|
agentId: agent2,
|
|
36855
37215
|
channel: channel2,
|
|
@@ -36878,22 +37238,43 @@ ${MESSAGE_SEND_STDIN_POLICY}`);
|
|
|
36878
37238
|
return { sent, reminder: { armed: false, reason: "local reminder request failed" } };
|
|
36879
37239
|
}
|
|
36880
37240
|
}
|
|
36881
|
-
|
|
37241
|
+
function parseMessagePropertyJson(command, raw) {
|
|
37242
|
+
if (typeof raw !== "string")
|
|
37243
|
+
throw new CliError(`${command}: --json <json> is required`);
|
|
37244
|
+
try {
|
|
37245
|
+
return JSON.parse(raw);
|
|
37246
|
+
} catch {
|
|
37247
|
+
throw new CliError(`${command}: --json must be valid JSON`);
|
|
37248
|
+
}
|
|
37249
|
+
}
|
|
37250
|
+
async function cmdMessagePropertySet(opts) {
|
|
36882
37251
|
const api2 = getApi();
|
|
36883
37252
|
const target2 = opts.target;
|
|
36884
|
-
const emoji3 = opts.emoji;
|
|
36885
37253
|
if (!target2)
|
|
36886
|
-
throw new CliError("message
|
|
36887
|
-
|
|
36888
|
-
|
|
36889
|
-
const
|
|
36890
|
-
|
|
36891
|
-
|
|
36892
|
-
|
|
36893
|
-
|
|
36894
|
-
|
|
36895
|
-
|
|
36896
|
-
|
|
37254
|
+
throw new CliError("message property set: --target <ref> is required");
|
|
37255
|
+
const request = parseMessageTarget("message property set", target2);
|
|
37256
|
+
const property = parseMessagePropertyJson("message property set", opts.json);
|
|
37257
|
+
const result = await withTransientMutationRetry(() => api2.messagePropertySet({ ...request, property }));
|
|
37258
|
+
return { target: target2, ...result };
|
|
37259
|
+
}
|
|
37260
|
+
async function cmdMessagePropertyList(opts) {
|
|
37261
|
+
const api2 = getApi();
|
|
37262
|
+
const target2 = opts.target;
|
|
37263
|
+
if (!target2)
|
|
37264
|
+
throw new CliError("message property list: --target <ref> is required");
|
|
37265
|
+
const request = parseMessageTarget("message property list", target2);
|
|
37266
|
+
const result = await api2.messagePropertyList(request);
|
|
37267
|
+
return { target: target2, ...result };
|
|
37268
|
+
}
|
|
37269
|
+
async function cmdMessagePropertyRemove(opts) {
|
|
37270
|
+
const api2 = getApi();
|
|
37271
|
+
const target2 = opts.target;
|
|
37272
|
+
if (!target2)
|
|
37273
|
+
throw new CliError("message property remove: --target <ref> is required");
|
|
37274
|
+
const request = parseMessageTarget("message property remove", target2);
|
|
37275
|
+
const property = parseMessagePropertyJson("message property remove", opts.json);
|
|
37276
|
+
const result = await withTransientMutationRetry(() => api2.messagePropertyRemove({ ...request, property }));
|
|
37277
|
+
return { target: target2, ...result };
|
|
36897
37278
|
}
|
|
36898
37279
|
function parseMessageTarget(command, target2) {
|
|
36899
37280
|
let parsed;
|
|
@@ -36910,24 +37291,6 @@ function parseMessageTarget(command, target2) {
|
|
|
36910
37291
|
const channel2 = parsed.threadRootSeq !== undefined ? `/${parsed.server}/${parsed.channel}/#${parsed.threadRootSeq}` : `/${parsed.server}/${parsed.channel}`;
|
|
36911
37292
|
return { channel: channel2, seq: parsed.seq };
|
|
36912
37293
|
}
|
|
36913
|
-
async function cmdMessageMarkSet(opts) {
|
|
36914
|
-
const api2 = getApi();
|
|
36915
|
-
const target2 = opts.target;
|
|
36916
|
-
if (!target2)
|
|
36917
|
-
throw new CliError("message mark set: --target <ref> is required");
|
|
36918
|
-
const request = parseMessageTarget("message mark set", target2);
|
|
36919
|
-
await withTransientMutationRetry(() => api2.markSet(request));
|
|
36920
|
-
return { target: target2, marked: true };
|
|
36921
|
-
}
|
|
36922
|
-
async function cmdMessageMarkRemove(opts) {
|
|
36923
|
-
const api2 = getApi();
|
|
36924
|
-
const target2 = opts.target;
|
|
36925
|
-
if (!target2)
|
|
36926
|
-
throw new CliError("message mark remove: --target <ref> is required");
|
|
36927
|
-
const request = parseMessageTarget("message mark remove", target2);
|
|
36928
|
-
await withTransientMutationRetry(() => api2.markRemove(request));
|
|
36929
|
-
return { target: target2, marked: false };
|
|
36930
|
-
}
|
|
36931
37294
|
async function cmdMessageMarkList(opts) {
|
|
36932
37295
|
const api2 = getApi();
|
|
36933
37296
|
const { marked } = await api2.listMarks({ agentId: agentId(opts) });
|
|
@@ -37057,7 +37420,7 @@ async function cmdInboxPull(opts) {
|
|
|
37057
37420
|
let acked = 0;
|
|
37058
37421
|
let ackError;
|
|
37059
37422
|
let failed;
|
|
37060
|
-
if (
|
|
37423
|
+
if (messages.length > 0) {
|
|
37061
37424
|
const latest = new Map;
|
|
37062
37425
|
for (const m of messages) {
|
|
37063
37426
|
const seqN = Number(m.seq.replace("#", ""));
|
|
@@ -37125,6 +37488,14 @@ async function cmdServerJoin(opts) {
|
|
|
37125
37488
|
const { server } = await api2.joinServer({ agentId: agent2, invite: token });
|
|
37126
37489
|
return { server };
|
|
37127
37490
|
}
|
|
37491
|
+
async function cmdServerLeave(opts) {
|
|
37492
|
+
const api2 = getApi();
|
|
37493
|
+
const agent2 = agentId(opts);
|
|
37494
|
+
const server = opts.server;
|
|
37495
|
+
if (!server)
|
|
37496
|
+
throw new CliError("server leave: --server <name#NNNN> is required");
|
|
37497
|
+
return await api2.leaveServer({ agentId: agent2, server });
|
|
37498
|
+
}
|
|
37128
37499
|
async function cmdChannelList(opts) {
|
|
37129
37500
|
const api2 = getApi();
|
|
37130
37501
|
const agent2 = agentId(opts);
|
|
@@ -37141,6 +37512,26 @@ async function cmdChannelMember(opts) {
|
|
|
37141
37512
|
throw new CliError("channel member: --channel <ref> is required");
|
|
37142
37513
|
return await api2.channelMember({ agentId: agent2, channel: channel2 });
|
|
37143
37514
|
}
|
|
37515
|
+
async function cmdChannelLeave(opts) {
|
|
37516
|
+
const api2 = getApi();
|
|
37517
|
+
const agent2 = agentId(opts);
|
|
37518
|
+
const channel2 = opts.channel;
|
|
37519
|
+
if (!channel2)
|
|
37520
|
+
throw new CliError("channel leave: --channel <ref> is required");
|
|
37521
|
+
let parsed;
|
|
37522
|
+
try {
|
|
37523
|
+
parsed = parseRef(channel2);
|
|
37524
|
+
} catch {
|
|
37525
|
+
throw new CliError("channel leave: malformed channel ref");
|
|
37526
|
+
}
|
|
37527
|
+
if (parsed.server === DM_SERVER) {
|
|
37528
|
+
throw new CliError("channel leave: DMs cannot be left");
|
|
37529
|
+
}
|
|
37530
|
+
if (parsed.seq !== undefined) {
|
|
37531
|
+
throw new CliError("channel leave: message refs cannot be left; use a channel or thread-root ref");
|
|
37532
|
+
}
|
|
37533
|
+
return await api2.leaveChannel({ agentId: agent2, channel: channel2 });
|
|
37534
|
+
}
|
|
37144
37535
|
async function cmdChannelHistory(opts) {
|
|
37145
37536
|
const api2 = getApi();
|
|
37146
37537
|
const agent2 = agentId(opts);
|
|
@@ -37198,22 +37589,22 @@ function buildProgram(stdin) {
|
|
|
37198
37589
|
const result = await cmdMessageSend({ ...globalOpts, ...localOpts }, stdin);
|
|
37199
37590
|
printEnvelope({ success: result });
|
|
37200
37591
|
});
|
|
37201
|
-
message2.command("
|
|
37202
|
-
|
|
37203
|
-
|
|
37204
|
-
const result = await
|
|
37592
|
+
const property = message2.command("property").description("message property operations").exitOverride();
|
|
37593
|
+
property.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37594
|
+
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() {
|
|
37595
|
+
const result = await cmdMessagePropertySet({ ...program.opts(), ...this.opts() });
|
|
37205
37596
|
printEnvelope({ success: result });
|
|
37206
37597
|
});
|
|
37207
|
-
|
|
37208
|
-
|
|
37209
|
-
mark.command("set").description("mark a message as outstanding work").requiredOption("--target <ref>", "full message ref").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37210
|
-
const result = await cmdMessageMarkSet({ ...program.opts(), ...this.opts() });
|
|
37598
|
+
property.command("list").description("list current properties and supported capabilities").requiredOption("--target <ref>", "full message ref").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37599
|
+
const result = await cmdMessagePropertyList({ ...program.opts(), ...this.opts() });
|
|
37211
37600
|
printEnvelope({ success: result });
|
|
37212
37601
|
});
|
|
37213
|
-
|
|
37214
|
-
const result = await
|
|
37602
|
+
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() {
|
|
37603
|
+
const result = await cmdMessagePropertyRemove({ ...program.opts(), ...this.opts() });
|
|
37215
37604
|
printEnvelope({ success: result });
|
|
37216
37605
|
});
|
|
37606
|
+
const mark = message2.command("mark").description("global durable-mark queries").exitOverride();
|
|
37607
|
+
mark.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37217
37608
|
mark.command("list").description("list all currently visible marked messages").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37218
37609
|
const result = await cmdMessageMarkList({ ...program.opts(), ...this.opts() });
|
|
37219
37610
|
printEnvelope({ success: result });
|
|
@@ -37234,7 +37625,7 @@ function buildProgram(stdin) {
|
|
|
37234
37625
|
});
|
|
37235
37626
|
const inbox = program.command("inbox").description("inbox operations").exitOverride();
|
|
37236
37627
|
inbox.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37237
|
-
inbox.command("pull").description("fetch unread messages from all channels").option("--max <n>", "max messages to return").
|
|
37628
|
+
inbox.command("pull").description("fetch unread messages from all channels").option("--max <n>", "max messages to return").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
37238
37629
|
const localOpts = this.opts();
|
|
37239
37630
|
const globalOpts = program.opts();
|
|
37240
37631
|
const result = await cmdInboxPull({ ...globalOpts, ...localOpts });
|
|
@@ -37260,6 +37651,12 @@ function buildProgram(stdin) {
|
|
|
37260
37651
|
const result = await cmdServerJoin({ ...globalOpts, ...localOpts });
|
|
37261
37652
|
printEnvelope({ success: result });
|
|
37262
37653
|
});
|
|
37654
|
+
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() {
|
|
37655
|
+
const localOpts = this.opts();
|
|
37656
|
+
const globalOpts = program.opts();
|
|
37657
|
+
const result = await cmdServerLeave({ ...globalOpts, ...localOpts });
|
|
37658
|
+
printEnvelope({ success: result });
|
|
37659
|
+
});
|
|
37263
37660
|
const channel2 = program.command("channel").description("channel operations").exitOverride();
|
|
37264
37661
|
channel2.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37265
37662
|
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() {
|
|
@@ -37280,6 +37677,12 @@ function buildProgram(stdin) {
|
|
|
37280
37677
|
const result = await cmdChannelMember({ ...globalOpts, ...localOpts });
|
|
37281
37678
|
printEnvelope({ success: result });
|
|
37282
37679
|
});
|
|
37680
|
+
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() {
|
|
37681
|
+
const localOpts = this.opts();
|
|
37682
|
+
const globalOpts = program.opts();
|
|
37683
|
+
const result = await cmdChannelLeave({ ...globalOpts, ...localOpts });
|
|
37684
|
+
printEnvelope({ success: result });
|
|
37685
|
+
});
|
|
37283
37686
|
const friend = program.command("friend").description("friend operations").exitOverride();
|
|
37284
37687
|
friend.configureOutput({ writeOut: () => {}, writeErr: () => {} });
|
|
37285
37688
|
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() {
|