larkway 0.3.24 → 0.3.26
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 +1 -1
- package/README.zh.md +1 -1
- package/dist/main.js +270 -67
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
You @ the bot in a Feishu thread. It runs on your machine — reading your real codebase, executing commands, opening MRs — and posts the result back. You define what the agent knows and what it can do. Larkway just carries the messages.
|
|
10
10
|
|
|
11
|
-
**Current release: v0.3.
|
|
11
|
+
**Current release: v0.3.26**
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
package/README.zh.md
CHANGED
package/dist/main.js
CHANGED
|
@@ -117684,12 +117684,14 @@ var AnswerChannelExtractor = class {
|
|
|
117684
117684
|
mode = "waiting";
|
|
117685
117685
|
buffer = "";
|
|
117686
117686
|
visibleText = "";
|
|
117687
|
+
lastSnapshotText = "";
|
|
117687
117688
|
ingestDelta(text, raw) {
|
|
117688
117689
|
if (!text || this.mode === "closed") return [];
|
|
117689
117690
|
this.buffer += text;
|
|
117690
117691
|
return this.drain(raw);
|
|
117691
117692
|
}
|
|
117692
117693
|
ingestSnapshot(text, raw) {
|
|
117694
|
+
this.lastSnapshotText = text;
|
|
117693
117695
|
const events = splitAnswerChannelText(text, raw);
|
|
117694
117696
|
const out = [];
|
|
117695
117697
|
for (const event of events) {
|
|
@@ -117697,13 +117699,30 @@ var AnswerChannelExtractor = class {
|
|
|
117697
117699
|
out.push(event);
|
|
117698
117700
|
continue;
|
|
117699
117701
|
}
|
|
117700
|
-
if (event.text === this.visibleText)
|
|
117702
|
+
if (event.text === this.visibleText) {
|
|
117703
|
+
if (text.includes(ANSWER_END_MARKER)) this.mode = "closed";
|
|
117704
|
+
continue;
|
|
117705
|
+
}
|
|
117701
117706
|
this.visibleText = event.text;
|
|
117702
117707
|
out.push(event);
|
|
117703
117708
|
if (text.includes(ANSWER_END_MARKER)) this.mode = "closed";
|
|
117704
117709
|
}
|
|
117705
117710
|
return out;
|
|
117706
117711
|
}
|
|
117712
|
+
ingestGrowingSnapshot(text, raw) {
|
|
117713
|
+
if (!text || this.mode === "closed") return [];
|
|
117714
|
+
if (this.lastSnapshotText && text.startsWith(this.lastSnapshotText)) {
|
|
117715
|
+
const delta = text.slice(this.lastSnapshotText.length);
|
|
117716
|
+
this.lastSnapshotText = text;
|
|
117717
|
+
return delta ? this.ingestDelta(delta, raw) : [];
|
|
117718
|
+
}
|
|
117719
|
+
if (this.lastSnapshotText === "") {
|
|
117720
|
+
this.lastSnapshotText = text;
|
|
117721
|
+
return this.ingestDelta(text, raw);
|
|
117722
|
+
}
|
|
117723
|
+
this.lastSnapshotText = text;
|
|
117724
|
+
return this.ingestSnapshot(text, raw);
|
|
117725
|
+
}
|
|
117707
117726
|
drain(raw) {
|
|
117708
117727
|
const events = [];
|
|
117709
117728
|
if (this.mode === "waiting") {
|
|
@@ -119111,6 +119130,20 @@ async function deleteCardFile(worktreePath) {
|
|
|
119111
119130
|
// src/bridge/cardkitFile.ts
|
|
119112
119131
|
import fs5 from "node:fs/promises";
|
|
119113
119132
|
import path8 from "node:path";
|
|
119133
|
+
var defaultCardKitLiveMetrics = () => ({
|
|
119134
|
+
answerDeltaCount: 0,
|
|
119135
|
+
answerSnapshotCount: 0,
|
|
119136
|
+
firstAnswerAt: null,
|
|
119137
|
+
lastAnswerAt: null,
|
|
119138
|
+
visibleAnswerLength: 0,
|
|
119139
|
+
toolUseCount: 0,
|
|
119140
|
+
lastToolUseAt: null,
|
|
119141
|
+
statusPatchCount: 0,
|
|
119142
|
+
lastStatusPatchAt: null,
|
|
119143
|
+
progressUpdateCount: 0,
|
|
119144
|
+
lastProgressPatchAt: null,
|
|
119145
|
+
lastPatchError: null
|
|
119146
|
+
});
|
|
119114
119147
|
var CardKitFileSchema = external_exports.object({
|
|
119115
119148
|
surface: external_exports.literal("cardkit_stream"),
|
|
119116
119149
|
status: external_exports.enum(["planned", "message_sent", "streaming", "finalized", "fallback_visible", "failed"]).default("planned"),
|
|
@@ -119124,6 +119157,20 @@ var CardKitFileSchema = external_exports.object({
|
|
|
119124
119157
|
replyInThread: external_exports.boolean().default(true),
|
|
119125
119158
|
idempotencyKey: external_exports.string().min(1),
|
|
119126
119159
|
sequence: external_exports.number().int().nonnegative().default(0),
|
|
119160
|
+
live: external_exports.object({
|
|
119161
|
+
answerDeltaCount: external_exports.number().int().nonnegative().default(0),
|
|
119162
|
+
answerSnapshotCount: external_exports.number().int().nonnegative().default(0),
|
|
119163
|
+
firstAnswerAt: external_exports.string().min(1).nullable().default(null),
|
|
119164
|
+
lastAnswerAt: external_exports.string().min(1).nullable().default(null),
|
|
119165
|
+
visibleAnswerLength: external_exports.number().int().nonnegative().default(0),
|
|
119166
|
+
toolUseCount: external_exports.number().int().nonnegative().default(0),
|
|
119167
|
+
lastToolUseAt: external_exports.string().min(1).nullable().default(null),
|
|
119168
|
+
statusPatchCount: external_exports.number().int().nonnegative().default(0),
|
|
119169
|
+
lastStatusPatchAt: external_exports.string().min(1).nullable().default(null),
|
|
119170
|
+
progressUpdateCount: external_exports.number().int().nonnegative().default(0),
|
|
119171
|
+
lastProgressPatchAt: external_exports.string().min(1).nullable().default(null),
|
|
119172
|
+
lastPatchError: external_exports.string().min(1).nullable().default(null)
|
|
119173
|
+
}).default(defaultCardKitLiveMetrics),
|
|
119127
119174
|
elements: external_exports.object({
|
|
119128
119175
|
status: external_exports.object({ elementId: external_exports.string().min(1) }).optional(),
|
|
119129
119176
|
thinking: external_exports.object({ elementId: external_exports.string().min(1) }).optional(),
|
|
@@ -119354,6 +119401,29 @@ function isMissingCardKitElementError(err) {
|
|
|
119354
119401
|
const message = err.message.toLowerCase();
|
|
119355
119402
|
return message.includes("element") && (message.includes("not found") || message.includes("not exist") || message.includes("\u4E0D\u5B58\u5728"));
|
|
119356
119403
|
}
|
|
119404
|
+
function initialLiveMetrics() {
|
|
119405
|
+
return {
|
|
119406
|
+
answerDeltaCount: 0,
|
|
119407
|
+
answerSnapshotCount: 0,
|
|
119408
|
+
firstAnswerAt: null,
|
|
119409
|
+
lastAnswerAt: null,
|
|
119410
|
+
visibleAnswerLength: 0,
|
|
119411
|
+
toolUseCount: 0,
|
|
119412
|
+
lastToolUseAt: null,
|
|
119413
|
+
statusPatchCount: 0,
|
|
119414
|
+
lastStatusPatchAt: null,
|
|
119415
|
+
progressUpdateCount: 0,
|
|
119416
|
+
lastProgressPatchAt: null,
|
|
119417
|
+
lastPatchError: null
|
|
119418
|
+
};
|
|
119419
|
+
}
|
|
119420
|
+
function summarizeError(err) {
|
|
119421
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
119422
|
+
return message.replace(/\s+/g, " ").trim().slice(0, 240) || "unknown error";
|
|
119423
|
+
}
|
|
119424
|
+
function toolStatusText(toolUseCount) {
|
|
119425
|
+
return toolUseCount > 0 ? `\u52AA\u529B\u56DE\u7B54\u4E2D... \xB7 \u5DF2\u7528 ${toolUseCount} \u4E2A\u5DE5\u5177` : "\u52AA\u529B\u56DE\u7B54\u4E2D...";
|
|
119426
|
+
}
|
|
119357
119427
|
var LiveCardKitProgressHandle = class {
|
|
119358
119428
|
cardId;
|
|
119359
119429
|
messageId;
|
|
@@ -119362,12 +119432,14 @@ var LiveCardKitProgressHandle = class {
|
|
|
119362
119432
|
patchIntervalMs;
|
|
119363
119433
|
maxProgressUpdates;
|
|
119364
119434
|
onSequenceCommitted;
|
|
119435
|
+
onLiveMetricsChanged;
|
|
119365
119436
|
answerBuffer = "";
|
|
119366
119437
|
pendingPatch = null;
|
|
119367
119438
|
inFlight = Promise.resolve();
|
|
119368
119439
|
closed = false;
|
|
119369
|
-
progressUpdates = 0;
|
|
119370
119440
|
answerElementCreated = false;
|
|
119441
|
+
immediatePatchStarted = false;
|
|
119442
|
+
metrics = initialLiveMetrics();
|
|
119371
119443
|
sequence = 0;
|
|
119372
119444
|
constructor(opts) {
|
|
119373
119445
|
this.cardKitClient = opts.cardKitClient;
|
|
@@ -119377,20 +119449,31 @@ var LiveCardKitProgressHandle = class {
|
|
|
119377
119449
|
this.patchIntervalMs = opts.patchIntervalMs;
|
|
119378
119450
|
this.maxProgressUpdates = opts.maxProgressUpdates;
|
|
119379
119451
|
this.onSequenceCommitted = opts.onSequenceCommitted;
|
|
119452
|
+
this.onLiveMetricsChanged = opts.onLiveMetricsChanged;
|
|
119380
119453
|
}
|
|
119381
119454
|
get answerText() {
|
|
119382
119455
|
return this.answerBuffer;
|
|
119383
119456
|
}
|
|
119457
|
+
get liveMetrics() {
|
|
119458
|
+
return { ...this.metrics };
|
|
119459
|
+
}
|
|
119384
119460
|
handle(event) {
|
|
119385
119461
|
if (this.closed) return;
|
|
119462
|
+
if (event.type === "tool_use") {
|
|
119463
|
+
this.recordToolUse();
|
|
119464
|
+
this.patchStatus(toolStatusText(this.metrics.toolUseCount));
|
|
119465
|
+
return;
|
|
119466
|
+
}
|
|
119386
119467
|
if (event.type === "answer_delta") {
|
|
119387
119468
|
this.answerBuffer += event.text;
|
|
119388
|
-
this.
|
|
119469
|
+
this.recordAnswerEvent("answer_delta");
|
|
119470
|
+
this.schedulePatch({ immediate: !this.immediatePatchStarted });
|
|
119389
119471
|
return;
|
|
119390
119472
|
}
|
|
119391
119473
|
if (event.type === "answer_snapshot") {
|
|
119392
119474
|
this.answerBuffer = event.text;
|
|
119393
|
-
this.
|
|
119475
|
+
this.recordAnswerEvent("answer_snapshot");
|
|
119476
|
+
this.schedulePatch({ immediate: !this.immediatePatchStarted });
|
|
119394
119477
|
}
|
|
119395
119478
|
}
|
|
119396
119479
|
async drain() {
|
|
@@ -119449,8 +119532,71 @@ var LiveCardKitProgressHandle = class {
|
|
|
119449
119532
|
this.pendingPatch = null;
|
|
119450
119533
|
}
|
|
119451
119534
|
}
|
|
119452
|
-
|
|
119453
|
-
|
|
119535
|
+
recordAnswerEvent(type2) {
|
|
119536
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
119537
|
+
if (type2 === "answer_delta") {
|
|
119538
|
+
this.metrics.answerDeltaCount += 1;
|
|
119539
|
+
} else {
|
|
119540
|
+
this.metrics.answerSnapshotCount += 1;
|
|
119541
|
+
}
|
|
119542
|
+
this.metrics.firstAnswerAt ??= now;
|
|
119543
|
+
this.metrics.lastAnswerAt = now;
|
|
119544
|
+
this.metrics.visibleAnswerLength = this.answerBuffer.length;
|
|
119545
|
+
this.emitLiveMetrics();
|
|
119546
|
+
console.info(
|
|
119547
|
+
"[cardkit_progress] answer event",
|
|
119548
|
+
`type=${type2}`,
|
|
119549
|
+
`delta_count=${this.metrics.answerDeltaCount}`,
|
|
119550
|
+
`snapshot_count=${this.metrics.answerSnapshotCount}`,
|
|
119551
|
+
`visible_length=${this.metrics.visibleAnswerLength}`,
|
|
119552
|
+
`sequence=${this.sequence}`
|
|
119553
|
+
);
|
|
119554
|
+
}
|
|
119555
|
+
recordToolUse() {
|
|
119556
|
+
this.metrics.toolUseCount += 1;
|
|
119557
|
+
this.metrics.lastToolUseAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
119558
|
+
this.emitLiveMetrics();
|
|
119559
|
+
console.info(
|
|
119560
|
+
"[cardkit_progress] tool event",
|
|
119561
|
+
`tool_use_count=${this.metrics.toolUseCount}`,
|
|
119562
|
+
`sequence=${this.sequence}`
|
|
119563
|
+
);
|
|
119564
|
+
}
|
|
119565
|
+
patchStatus(content) {
|
|
119566
|
+
this.inFlight = this.inFlight.then(
|
|
119567
|
+
() => this.next(
|
|
119568
|
+
(sequence) => this.cardKitClient.updateElement(
|
|
119569
|
+
this.cardId,
|
|
119570
|
+
CARDKIT_FOOTER_ELEMENT_ID,
|
|
119571
|
+
{
|
|
119572
|
+
tag: "markdown",
|
|
119573
|
+
content,
|
|
119574
|
+
element_id: CARDKIT_FOOTER_ELEMENT_ID
|
|
119575
|
+
},
|
|
119576
|
+
{
|
|
119577
|
+
sequence,
|
|
119578
|
+
uuid: sequenceUuid(this.cardId, "status", sequence)
|
|
119579
|
+
}
|
|
119580
|
+
)
|
|
119581
|
+
)
|
|
119582
|
+
).then(() => {
|
|
119583
|
+
this.metrics.statusPatchCount += 1;
|
|
119584
|
+
this.metrics.lastStatusPatchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
119585
|
+
this.metrics.lastPatchError = null;
|
|
119586
|
+
this.emitLiveMetrics();
|
|
119587
|
+
}).catch((err) => {
|
|
119588
|
+
this.metrics.lastPatchError = summarizeError(err);
|
|
119589
|
+
this.emitLiveMetrics();
|
|
119590
|
+
console.warn("[cardkit_progress] status update failed (continuing):", err);
|
|
119591
|
+
});
|
|
119592
|
+
}
|
|
119593
|
+
schedulePatch(opts = {}) {
|
|
119594
|
+
if (this.pendingPatch || this.metrics.progressUpdateCount >= this.maxProgressUpdates) return;
|
|
119595
|
+
if (opts.immediate) {
|
|
119596
|
+
this.immediatePatchStarted = true;
|
|
119597
|
+
void this.patchProgress();
|
|
119598
|
+
return;
|
|
119599
|
+
}
|
|
119454
119600
|
this.pendingPatch = setTimeout(() => {
|
|
119455
119601
|
this.pendingPatch = null;
|
|
119456
119602
|
void this.patchProgress();
|
|
@@ -119458,9 +119604,8 @@ var LiveCardKitProgressHandle = class {
|
|
|
119458
119604
|
this.pendingPatch.unref?.();
|
|
119459
119605
|
}
|
|
119460
119606
|
async patchProgress() {
|
|
119461
|
-
if (this.closed || this.
|
|
119607
|
+
if (this.closed || this.metrics.progressUpdateCount >= this.maxProgressUpdates) return;
|
|
119462
119608
|
if (!this.answerBuffer) return;
|
|
119463
|
-
this.progressUpdates += 1;
|
|
119464
119609
|
this.inFlight = this.inFlight.then(
|
|
119465
119610
|
() => this.withAnswerElement(this.answerBuffer).then(
|
|
119466
119611
|
() => this.next(
|
|
@@ -119470,7 +119615,21 @@ var LiveCardKitProgressHandle = class {
|
|
|
119470
119615
|
})
|
|
119471
119616
|
)
|
|
119472
119617
|
)
|
|
119473
|
-
).
|
|
119618
|
+
).then(() => {
|
|
119619
|
+
this.metrics.progressUpdateCount += 1;
|
|
119620
|
+
this.metrics.visibleAnswerLength = this.answerBuffer.length;
|
|
119621
|
+
this.metrics.lastProgressPatchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
119622
|
+
this.metrics.lastPatchError = null;
|
|
119623
|
+
this.emitLiveMetrics();
|
|
119624
|
+
console.info(
|
|
119625
|
+
"[cardkit_progress] progress committed",
|
|
119626
|
+
`progress_update_count=${this.metrics.progressUpdateCount}`,
|
|
119627
|
+
`visible_length=${this.metrics.visibleAnswerLength}`,
|
|
119628
|
+
`sequence=${this.sequence}`
|
|
119629
|
+
);
|
|
119630
|
+
}).catch((err) => {
|
|
119631
|
+
this.metrics.lastPatchError = summarizeError(err);
|
|
119632
|
+
this.emitLiveMetrics();
|
|
119474
119633
|
console.warn("[cardkit_progress] progress update failed (continuing):", err);
|
|
119475
119634
|
});
|
|
119476
119635
|
await this.inFlight;
|
|
@@ -119496,6 +119655,9 @@ var LiveCardKitProgressHandle = class {
|
|
|
119496
119655
|
await fn(this.sequence);
|
|
119497
119656
|
await this.onSequenceCommitted?.(this.sequence);
|
|
119498
119657
|
}
|
|
119658
|
+
emitLiveMetrics() {
|
|
119659
|
+
this.onLiveMetricsChanged?.({ ...this.metrics, sequence: this.sequence });
|
|
119660
|
+
}
|
|
119499
119661
|
};
|
|
119500
119662
|
async function createCardKitProgressHandle(opts) {
|
|
119501
119663
|
const key = idempotencyKey(opts.facts);
|
|
@@ -119529,7 +119691,8 @@ async function createCardKitProgressHandle(opts) {
|
|
|
119529
119691
|
idempotencyKey: key,
|
|
119530
119692
|
patchIntervalMs: opts.patchIntervalMs ?? DEFAULT_PATCH_INTERVAL_MS,
|
|
119531
119693
|
maxProgressUpdates: opts.maxProgressUpdates ?? DEFAULT_MAX_PROGRESS_UPDATES,
|
|
119532
|
-
onSequenceCommitted: opts.onSequenceCommitted
|
|
119694
|
+
onSequenceCommitted: opts.onSequenceCommitted,
|
|
119695
|
+
onLiveMetricsChanged: opts.onLiveMetricsChanged
|
|
119533
119696
|
});
|
|
119534
119697
|
}
|
|
119535
119698
|
async function finalizeExistingCardKitCard(opts) {
|
|
@@ -120603,6 +120766,7 @@ var ResponseSurfacePostBudget = class {
|
|
|
120603
120766
|
};
|
|
120604
120767
|
|
|
120605
120768
|
// src/bridge/handler.ts
|
|
120769
|
+
var DEFAULT_CARDKIT_RESPONSE_SURFACE_TIMEOUT_MS = 20 * 60 * 1e3;
|
|
120606
120770
|
function execGit(cwd, args) {
|
|
120607
120771
|
return new Promise((resolve2, reject) => {
|
|
120608
120772
|
const child = child_process.spawn("git", args, {
|
|
@@ -121157,6 +121321,7 @@ var BridgeHandler = class {
|
|
|
121157
121321
|
} catch (err) {
|
|
121158
121322
|
console.warn("[bridge.handler] ensureStateFile failed (continuing):", err);
|
|
121159
121323
|
}
|
|
121324
|
+
let cardKitRecordWrite = Promise.resolve();
|
|
121160
121325
|
const updateCardKitRecord = async (patch) => {
|
|
121161
121326
|
if (!cardKitRecord) return;
|
|
121162
121327
|
cardKitRecord = {
|
|
@@ -121164,7 +121329,16 @@ var BridgeHandler = class {
|
|
|
121164
121329
|
...patch,
|
|
121165
121330
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
121166
121331
|
};
|
|
121167
|
-
|
|
121332
|
+
const record = cardKitRecord;
|
|
121333
|
+
cardKitRecordWrite = cardKitRecordWrite.catch(() => {
|
|
121334
|
+
}).then(() => writeCardKitFile(worktreePath, record));
|
|
121335
|
+
await cardKitRecordWrite;
|
|
121336
|
+
};
|
|
121337
|
+
const updateCardKitLiveMetrics = (metrics) => {
|
|
121338
|
+
const { sequence, ...live } = metrics;
|
|
121339
|
+
void updateCardKitRecord({ sequence, live }).catch((err) => {
|
|
121340
|
+
console.warn("[bridge.handler] write CardKit live metrics failed:", err);
|
|
121341
|
+
});
|
|
121168
121342
|
};
|
|
121169
121343
|
if (!card && cardKitAvailable && this.deps.cardKitClient) {
|
|
121170
121344
|
try {
|
|
@@ -121180,7 +121354,8 @@ var BridgeHandler = class {
|
|
|
121180
121354
|
initialStatusText: "\u52AA\u529B\u56DE\u7B54\u4E2D...",
|
|
121181
121355
|
onSequenceCommitted: async (sequence) => {
|
|
121182
121356
|
await updateCardKitRecord({ status: "streaming", sequence });
|
|
121183
|
-
}
|
|
121357
|
+
},
|
|
121358
|
+
onLiveMetricsChanged: updateCardKitLiveMetrics
|
|
121184
121359
|
});
|
|
121185
121360
|
cardKitRecord = {
|
|
121186
121361
|
surface: "cardkit_stream",
|
|
@@ -121195,6 +121370,7 @@ var BridgeHandler = class {
|
|
|
121195
121370
|
replyInThread,
|
|
121196
121371
|
idempotencyKey: cardKitProgress.idempotencyKey,
|
|
121197
121372
|
sequence: cardKitProgress.sequence,
|
|
121373
|
+
live: cardKitProgress.liveMetrics,
|
|
121198
121374
|
elements: {
|
|
121199
121375
|
footer: { elementId: "footer_md" },
|
|
121200
121376
|
final: { elementId: "final_md" }
|
|
@@ -121362,7 +121538,12 @@ var BridgeHandler = class {
|
|
|
121362
121538
|
});
|
|
121363
121539
|
const backend = this.deps.botConfig?.backend ?? "claude";
|
|
121364
121540
|
const permissionMode = this.deps.permissionMode ?? "bypassPermissions";
|
|
121365
|
-
const
|
|
121541
|
+
const baseTimeoutMs = this.deps.subprocessTimeoutMs ?? 60 * 60 * 1e3;
|
|
121542
|
+
const timeoutMs = cardKitProgress ? Math.min(
|
|
121543
|
+
baseTimeoutMs,
|
|
121544
|
+
this.deps.responseSurfaceTimeoutMs ?? DEFAULT_CARDKIT_RESPONSE_SURFACE_TIMEOUT_MS
|
|
121545
|
+
) : baseTimeoutMs;
|
|
121546
|
+
const runnerStartedAt = Date.now();
|
|
121366
121547
|
const handle = createRunner(backend).run({
|
|
121367
121548
|
prompt,
|
|
121368
121549
|
resumeSessionId: currentExisting?.sessionId,
|
|
@@ -121390,6 +121571,7 @@ var BridgeHandler = class {
|
|
|
121390
121571
|
}
|
|
121391
121572
|
}
|
|
121392
121573
|
const result = await handle.done;
|
|
121574
|
+
const cardKitTurnTimedOut = cardKitProgress != null && result.exitCode !== 0 && Date.now() - runnerStartedAt >= timeoutMs;
|
|
121393
121575
|
const rawReportedState = await readStateFile(worktreePath);
|
|
121394
121576
|
const reportedState = rawReportedState?.updated_at != null && rawReportedState.updated_at !== preRunUpdatedAt ? rawReportedState : null;
|
|
121395
121577
|
const now = Date.now();
|
|
@@ -121419,6 +121601,7 @@ var BridgeHandler = class {
|
|
|
121419
121601
|
}
|
|
121420
121602
|
const reportedStatus = reportedState?.status;
|
|
121421
121603
|
const reportedError = reportedState?.error;
|
|
121604
|
+
const cardKitTimeoutFailure = cardKitTurnTimedOut && reportedStatus !== "ready" && reportedStatus !== "failed";
|
|
121422
121605
|
let success;
|
|
121423
121606
|
let failureReason;
|
|
121424
121607
|
if (reportedStatus === "failed") {
|
|
@@ -121426,6 +121609,9 @@ var BridgeHandler = class {
|
|
|
121426
121609
|
failureReason = reportedError ?? "bot \u62A5\u544A failed (\u65E0 error \u5B57\u6BB5)";
|
|
121427
121610
|
} else if (reportedStatus === "ready") {
|
|
121428
121611
|
success = true;
|
|
121612
|
+
} else if (cardKitTimeoutFailure) {
|
|
121613
|
+
success = false;
|
|
121614
|
+
failureReason = `agent turn timed out after ${timeoutMs}ms; CardKit running card was finalized as interrupted`;
|
|
121429
121615
|
} else if (result.exitCode === 0) {
|
|
121430
121616
|
success = true;
|
|
121431
121617
|
} else {
|
|
@@ -121433,14 +121619,14 @@ var BridgeHandler = class {
|
|
|
121433
121619
|
failureReason = `claude exited ${result.exitCode} \u4E14 bot \u672A\u66F4\u65B0 state.json status \u2014 \u53EF\u80FD\u5D29\u6E83`;
|
|
121434
121620
|
}
|
|
121435
121621
|
const fallbackAnswer = trustedAnswerText.trim() || cardKitProgress?.answerText.trim() || "";
|
|
121436
|
-
const cardBody = reportedState?.last_message ?? (fallbackAnswer ? fallbackAnswer : "\u26A0\uFE0F \u672C\u8F6E\u6CA1\u6709\u62FF\u5230 agent \u7684\u65B0\u56DE\u590D(\u53EF\u80FD\u88AB\u4E2D\u65AD\u6216\u672A\u66F4\u65B0\u72B6\u6001),\u518D @ \u6211\u4E00\u6B21\u91CD\u8BD5\u3002");
|
|
121622
|
+
const cardBody = cardKitTimeoutFailure ? "\u26A0\uFE0F \u672C\u8F6E\u5904\u7406\u8D85\u65F6\uFF0C\u5DF2\u4E2D\u65AD\u3002\u8BF7\u518D @ \u6211\u4E00\u6B21\u91CD\u8BD5\u3002" : reportedState?.last_message ?? (fallbackAnswer ? fallbackAnswer : "\u26A0\uFE0F \u672C\u8F6E\u6CA1\u6709\u62FF\u5230 agent \u7684\u65B0\u56DE\u590D(\u53EF\u80FD\u88AB\u4E2D\u65AD\u6216\u672A\u66F4\u65B0\u72B6\u6001),\u518D @ \u6211\u4E00\u6B21\u91CD\u8BD5\u3002");
|
|
121437
121623
|
const noReportThisTurn = reportedState === null;
|
|
121438
121624
|
const neutralTitle = noReportThisTurn && success && !failureReason ? "\u{1F4AC} \u5DF2\u56DE\u590D" : void 0;
|
|
121439
121625
|
const baseCardPayload = {
|
|
121440
121626
|
finalText: cardBody,
|
|
121441
121627
|
success,
|
|
121442
121628
|
failureReason,
|
|
121443
|
-
titleOverride: reportedState?.card_title ?? neutralTitle,
|
|
121629
|
+
titleOverride: reportedState?.card_title ?? (cardKitTimeoutFailure ? "\u5DF2\u4E2D\u65AD" : neutralTitle),
|
|
121444
121630
|
colorOverride: reportedState?.card_color ?? (neutralTitle ? "neutral" : void 0),
|
|
121445
121631
|
// V2 dynamic-choice buttons — agent-declared, rendered verbatim.
|
|
121446
121632
|
// reportedState is null when state.json wasn't freshly written
|
|
@@ -125581,7 +125767,7 @@ function* parseLinesMulti(line, answerExtractor = new AnswerChannelExtractor())
|
|
|
125581
125767
|
if (typeof item !== "object" || item === null) continue;
|
|
125582
125768
|
const block = item;
|
|
125583
125769
|
if (block["type"] === "text" && typeof block["text"] === "string") {
|
|
125584
|
-
yield* answerExtractor.
|
|
125770
|
+
yield* answerExtractor.ingestGrowingSnapshot(block["text"], obj);
|
|
125585
125771
|
emitted = true;
|
|
125586
125772
|
} else if (block["type"] === "tool_use") {
|
|
125587
125773
|
yield {
|
|
@@ -125893,64 +126079,80 @@ function buildCodexCommand(opts, codexBinPath = "codex") {
|
|
|
125893
126079
|
const freshFlags = opts.cwd != null ? ["-C", opts.cwd, ...commonFlags] : commonFlags;
|
|
125894
126080
|
return [codexBinPath, ["exec", ...freshFlags]];
|
|
125895
126081
|
}
|
|
125896
|
-
|
|
125897
|
-
|
|
125898
|
-
|
|
125899
|
-
|
|
125900
|
-
|
|
125901
|
-
obj
|
|
125902
|
-
|
|
125903
|
-
|
|
125904
|
-
|
|
125905
|
-
|
|
125906
|
-
|
|
125907
|
-
|
|
125908
|
-
|
|
125909
|
-
|
|
125910
|
-
|
|
125911
|
-
|
|
125912
|
-
|
|
125913
|
-
|
|
125914
|
-
|
|
125915
|
-
|
|
125916
|
-
|
|
125917
|
-
|
|
125918
|
-
|
|
125919
|
-
|
|
125920
|
-
|
|
125921
|
-
|
|
125922
|
-
|
|
125923
|
-
|
|
125924
|
-
if (
|
|
125925
|
-
yield
|
|
125926
|
-
type: "tool_use",
|
|
125927
|
-
toolName: "shell",
|
|
125928
|
-
toolInput: { command: itemRecord["command"] },
|
|
125929
|
-
raw: obj
|
|
125930
|
-
};
|
|
126082
|
+
var CodexLineParser = class {
|
|
126083
|
+
answerExtractor = new AnswerChannelExtractor();
|
|
126084
|
+
*parseLine(line) {
|
|
126085
|
+
const trimmed = line.trim();
|
|
126086
|
+
if (trimmed === "") return;
|
|
126087
|
+
let obj;
|
|
126088
|
+
try {
|
|
126089
|
+
obj = JSON.parse(trimmed);
|
|
126090
|
+
} catch {
|
|
126091
|
+
yield { type: "raw", raw: trimmed };
|
|
126092
|
+
return;
|
|
126093
|
+
}
|
|
126094
|
+
if (typeof obj !== "object" || obj === null) {
|
|
126095
|
+
yield { type: "raw", raw: obj };
|
|
126096
|
+
return;
|
|
126097
|
+
}
|
|
126098
|
+
const record = obj;
|
|
126099
|
+
const topType = record["type"];
|
|
126100
|
+
if (topType === "thread.started" && typeof record["thread_id"] === "string") {
|
|
126101
|
+
yield { type: "system_init", sessionId: record["thread_id"], raw: obj };
|
|
126102
|
+
return;
|
|
126103
|
+
}
|
|
126104
|
+
if (topType === "turn.completed") {
|
|
126105
|
+
yield { type: "result", stopReason: "end_turn", raw: obj };
|
|
126106
|
+
return;
|
|
126107
|
+
}
|
|
126108
|
+
const agentMessageText = agentMessageTextFrom(record);
|
|
126109
|
+
if (agentMessageText !== void 0) {
|
|
126110
|
+
if (topType === "item.completed") {
|
|
126111
|
+
yield* this.answerExtractor.ingestSnapshot(agentMessageText, obj);
|
|
125931
126112
|
return;
|
|
125932
126113
|
}
|
|
126114
|
+
yield* this.answerExtractor.ingestGrowingSnapshot(agentMessageText, obj);
|
|
126115
|
+
return;
|
|
125933
126116
|
}
|
|
125934
|
-
|
|
125935
|
-
|
|
125936
|
-
|
|
125937
|
-
|
|
125938
|
-
|
|
125939
|
-
|
|
125940
|
-
|
|
125941
|
-
|
|
125942
|
-
|
|
125943
|
-
|
|
126117
|
+
if (topType === "item.started") {
|
|
126118
|
+
const item = record["item"];
|
|
126119
|
+
if (typeof item === "object" && item !== null) {
|
|
126120
|
+
const itemRecord = item;
|
|
126121
|
+
if (itemRecord["type"] === "command_execution" && typeof itemRecord["command"] === "string") {
|
|
126122
|
+
yield {
|
|
126123
|
+
type: "tool_use",
|
|
126124
|
+
toolName: "shell",
|
|
126125
|
+
toolInput: { command: itemRecord["command"] },
|
|
126126
|
+
raw: obj
|
|
126127
|
+
};
|
|
126128
|
+
return;
|
|
126129
|
+
}
|
|
125944
126130
|
}
|
|
125945
|
-
|
|
125946
|
-
|
|
125947
|
-
|
|
126131
|
+
yield { type: "raw", raw: obj };
|
|
126132
|
+
return;
|
|
126133
|
+
}
|
|
126134
|
+
if (topType === "item.completed") {
|
|
126135
|
+
const item = record["item"];
|
|
126136
|
+
if (typeof item === "object" && item !== null) {
|
|
126137
|
+
const itemRecord = item;
|
|
126138
|
+
if (itemRecord["type"] === "command_execution") {
|
|
126139
|
+
yield { type: "tool_result", raw: obj };
|
|
126140
|
+
return;
|
|
126141
|
+
}
|
|
125948
126142
|
}
|
|
126143
|
+
yield { type: "raw", raw: obj };
|
|
126144
|
+
return;
|
|
125949
126145
|
}
|
|
125950
126146
|
yield { type: "raw", raw: obj };
|
|
125951
|
-
return;
|
|
125952
126147
|
}
|
|
125953
|
-
|
|
126148
|
+
};
|
|
126149
|
+
function agentMessageTextFrom(record) {
|
|
126150
|
+
const item = record["item"];
|
|
126151
|
+
if (typeof item !== "object" || item === null) return void 0;
|
|
126152
|
+
const itemRecord = item;
|
|
126153
|
+
if (itemRecord["type"] !== "agent_message") return void 0;
|
|
126154
|
+
const text = itemRecord["text"];
|
|
126155
|
+
return typeof text === "string" ? text : void 0;
|
|
125954
126156
|
}
|
|
125955
126157
|
function runCodex(opts, codexBinPath = "codex") {
|
|
125956
126158
|
const timeoutMs = opts.timeoutMs ?? 15 * 60 * 1e3;
|
|
@@ -126075,9 +126277,10 @@ stderr: ${stderr}` : "")
|
|
|
126075
126277
|
crlfDelay: Infinity,
|
|
126076
126278
|
signal: rlAbortController.signal
|
|
126077
126279
|
});
|
|
126280
|
+
const parser = new CodexLineParser();
|
|
126078
126281
|
try {
|
|
126079
126282
|
for await (const line of rl) {
|
|
126080
|
-
for (const event of
|
|
126283
|
+
for (const event of parser.parseLine(line)) {
|
|
126081
126284
|
if (event.type === "system_init") {
|
|
126082
126285
|
discoveredSessionId = event.sessionId;
|
|
126083
126286
|
}
|