larkway 0.3.25 → 0.3.27
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/cli/index.js +9 -9
- package/dist/main.js +270 -481
- 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/cli/index.js
CHANGED
|
@@ -124047,9 +124047,9 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
124047
124047
|
*/
|
|
124048
124048
|
allowed_threads: external_exports.array(external_exports.string().min(1)).default([]),
|
|
124049
124049
|
/**
|
|
124050
|
-
*
|
|
124051
|
-
*
|
|
124052
|
-
*
|
|
124050
|
+
* Historical post-first gate retained for config compatibility. The default
|
|
124051
|
+
* runtime no longer uses post-first lazy card creation; CardKit is the main
|
|
124052
|
+
* surface and legacy cards remain the visible fallback.
|
|
124053
124053
|
*/
|
|
124054
124054
|
lazy_card_creation: external_exports.boolean().default(true),
|
|
124055
124055
|
/**
|
|
@@ -124059,8 +124059,8 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
124059
124059
|
*/
|
|
124060
124060
|
kill_switch: external_exports.boolean().default(false),
|
|
124061
124061
|
/**
|
|
124062
|
-
* Gate for real post outbound. Defaults on
|
|
124063
|
-
*
|
|
124062
|
+
* Gate for real post outbound. Defaults on so create-only visible fallback
|
|
124063
|
+
* posts remain available when CardKit and legacy card rendering both fail.
|
|
124064
124064
|
*/
|
|
124065
124065
|
post_outbound_enabled: external_exports.boolean().default(true),
|
|
124066
124066
|
/**
|
|
@@ -124082,8 +124082,8 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
124082
124082
|
*/
|
|
124083
124083
|
allowed_mention_open_ids: external_exports.array(external_exports.string().min(1)).default([]),
|
|
124084
124084
|
/**
|
|
124085
|
-
*
|
|
124086
|
-
*
|
|
124085
|
+
* Historical post dispatch cap retained for schema compatibility and
|
|
124086
|
+
* isolated dispatcher tests.
|
|
124087
124087
|
*/
|
|
124088
124088
|
max_posts_per_turn: external_exports.number().int().min(0).max(10).default(1),
|
|
124089
124089
|
/**
|
|
@@ -124102,8 +124102,8 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
124102
124102
|
*/
|
|
124103
124103
|
max_post_attempts: external_exports.number().int().min(1).max(5).default(3),
|
|
124104
124104
|
/**
|
|
124105
|
-
*
|
|
124106
|
-
*
|
|
124105
|
+
* Historical threshold for removed lazy card creation experiments. Bounded
|
|
124106
|
+
* so older config remains parseable without growing arbitrary business rules.
|
|
124107
124107
|
*/
|
|
124108
124108
|
text_threshold_chars: external_exports.number().int().min(1).max(2e4).default(1200)
|
|
124109
124109
|
}).default(responseSurfacePrototypeConfigDefaults);
|
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") {
|
|
@@ -118689,9 +118708,9 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
118689
118708
|
*/
|
|
118690
118709
|
allowed_threads: external_exports.array(external_exports.string().min(1)).default([]),
|
|
118691
118710
|
/**
|
|
118692
|
-
*
|
|
118693
|
-
*
|
|
118694
|
-
*
|
|
118711
|
+
* Historical post-first gate retained for config compatibility. The default
|
|
118712
|
+
* runtime no longer uses post-first lazy card creation; CardKit is the main
|
|
118713
|
+
* surface and legacy cards remain the visible fallback.
|
|
118695
118714
|
*/
|
|
118696
118715
|
lazy_card_creation: external_exports.boolean().default(true),
|
|
118697
118716
|
/**
|
|
@@ -118701,8 +118720,8 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
118701
118720
|
*/
|
|
118702
118721
|
kill_switch: external_exports.boolean().default(false),
|
|
118703
118722
|
/**
|
|
118704
|
-
* Gate for real post outbound. Defaults on
|
|
118705
|
-
*
|
|
118723
|
+
* Gate for real post outbound. Defaults on so create-only visible fallback
|
|
118724
|
+
* posts remain available when CardKit and legacy card rendering both fail.
|
|
118706
118725
|
*/
|
|
118707
118726
|
post_outbound_enabled: external_exports.boolean().default(true),
|
|
118708
118727
|
/**
|
|
@@ -118724,8 +118743,8 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
118724
118743
|
*/
|
|
118725
118744
|
allowed_mention_open_ids: external_exports.array(external_exports.string().min(1)).default([]),
|
|
118726
118745
|
/**
|
|
118727
|
-
*
|
|
118728
|
-
*
|
|
118746
|
+
* Historical post dispatch cap retained for schema compatibility and
|
|
118747
|
+
* isolated dispatcher tests.
|
|
118729
118748
|
*/
|
|
118730
118749
|
max_posts_per_turn: external_exports.number().int().min(0).max(10).default(1),
|
|
118731
118750
|
/**
|
|
@@ -118744,8 +118763,8 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
118744
118763
|
*/
|
|
118745
118764
|
max_post_attempts: external_exports.number().int().min(1).max(5).default(3),
|
|
118746
118765
|
/**
|
|
118747
|
-
*
|
|
118748
|
-
*
|
|
118766
|
+
* Historical threshold for removed lazy card creation experiments. Bounded
|
|
118767
|
+
* so older config remains parseable without growing arbitrary business rules.
|
|
118749
118768
|
*/
|
|
118750
118769
|
text_threshold_chars: external_exports.number().int().min(1).max(2e4).default(1200)
|
|
118751
118770
|
}).default(responseSurfacePrototypeConfigDefaults);
|
|
@@ -118774,9 +118793,6 @@ function shouldProvideResponseSurfaceCardKitClient(config) {
|
|
|
118774
118793
|
function isResponseSurfaceCardKitAvailable(config, facts, opts) {
|
|
118775
118794
|
return !!(opts.cardKitClientAvailable && shouldProvideResponseSurfaceCardKitClient(config) && isResponseSurfacePrototypeAllowlisted(config, facts));
|
|
118776
118795
|
}
|
|
118777
|
-
function isResponseSurfacePostOutboundAvailable(config, facts, opts) {
|
|
118778
|
-
return !!(opts.postClientAvailable && shouldProvideResponseSurfacePostClient(config) && isResponseSurfacePrototypeAllowlisted(config, facts));
|
|
118779
|
-
}
|
|
118780
118796
|
|
|
118781
118797
|
// src/bridge/stateFile.ts
|
|
118782
118798
|
var optionalUrl = external_exports.preprocess(
|
|
@@ -119736,93 +119752,6 @@ async function finalizeExistingCardKitCard(opts) {
|
|
|
119736
119752
|
return sequence;
|
|
119737
119753
|
}
|
|
119738
119754
|
|
|
119739
|
-
// src/bridge/surfaceController.ts
|
|
119740
|
-
var SurfaceController = class _SurfaceController {
|
|
119741
|
-
decision;
|
|
119742
|
-
constructor(decision) {
|
|
119743
|
-
this.decision = decision;
|
|
119744
|
-
}
|
|
119745
|
-
static create(input) {
|
|
119746
|
-
const cfg = input.prototypeConfig;
|
|
119747
|
-
if (!cfg?.enabled) {
|
|
119748
|
-
return new _SurfaceController({
|
|
119749
|
-
startCardImmediately: true,
|
|
119750
|
-
prototypeEnabled: false,
|
|
119751
|
-
lazyCardCreationEnabled: false,
|
|
119752
|
-
reason: "prototype-disabled"
|
|
119753
|
-
});
|
|
119754
|
-
}
|
|
119755
|
-
if (cfg.kill_switch) {
|
|
119756
|
-
return new _SurfaceController({
|
|
119757
|
-
startCardImmediately: true,
|
|
119758
|
-
prototypeEnabled: false,
|
|
119759
|
-
lazyCardCreationEnabled: false,
|
|
119760
|
-
reason: "kill-switch-active"
|
|
119761
|
-
});
|
|
119762
|
-
}
|
|
119763
|
-
if (!isResponseSurfacePrototypeAllowlisted(cfg, {
|
|
119764
|
-
chatId: input.chatId,
|
|
119765
|
-
threadId: input.threadId
|
|
119766
|
-
})) {
|
|
119767
|
-
return new _SurfaceController({
|
|
119768
|
-
startCardImmediately: true,
|
|
119769
|
-
prototypeEnabled: false,
|
|
119770
|
-
lazyCardCreationEnabled: false,
|
|
119771
|
-
reason: "not-allowlisted"
|
|
119772
|
-
});
|
|
119773
|
-
}
|
|
119774
|
-
if (!cfg.lazy_card_creation) {
|
|
119775
|
-
return new _SurfaceController({
|
|
119776
|
-
startCardImmediately: true,
|
|
119777
|
-
prototypeEnabled: true,
|
|
119778
|
-
lazyCardCreationEnabled: false,
|
|
119779
|
-
reason: "lazy-card-disabled"
|
|
119780
|
-
});
|
|
119781
|
-
}
|
|
119782
|
-
if (!cfg.post_outbound_enabled) {
|
|
119783
|
-
return new _SurfaceController({
|
|
119784
|
-
startCardImmediately: true,
|
|
119785
|
-
prototypeEnabled: true,
|
|
119786
|
-
lazyCardCreationEnabled: false,
|
|
119787
|
-
reason: "post-outbound-disabled"
|
|
119788
|
-
});
|
|
119789
|
-
}
|
|
119790
|
-
if (!input.postOutboundAvailable) {
|
|
119791
|
-
return new _SurfaceController({
|
|
119792
|
-
startCardImmediately: true,
|
|
119793
|
-
prototypeEnabled: true,
|
|
119794
|
-
lazyCardCreationEnabled: false,
|
|
119795
|
-
reason: "post-outbound-unavailable-card-fallback"
|
|
119796
|
-
});
|
|
119797
|
-
}
|
|
119798
|
-
if (input.postLedgerAvailable === false) {
|
|
119799
|
-
return new _SurfaceController({
|
|
119800
|
-
startCardImmediately: true,
|
|
119801
|
-
prototypeEnabled: true,
|
|
119802
|
-
lazyCardCreationEnabled: false,
|
|
119803
|
-
reason: "post-ledger-unavailable-card-fallback"
|
|
119804
|
-
});
|
|
119805
|
-
}
|
|
119806
|
-
if (input.visibleFallbackAvailable === false) {
|
|
119807
|
-
return new _SurfaceController({
|
|
119808
|
-
startCardImmediately: true,
|
|
119809
|
-
prototypeEnabled: true,
|
|
119810
|
-
lazyCardCreationEnabled: false,
|
|
119811
|
-
reason: "visible-fallback-unavailable-card-fallback"
|
|
119812
|
-
});
|
|
119813
|
-
}
|
|
119814
|
-
return new _SurfaceController({
|
|
119815
|
-
startCardImmediately: false,
|
|
119816
|
-
prototypeEnabled: true,
|
|
119817
|
-
lazyCardCreationEnabled: true,
|
|
119818
|
-
reason: "lazy-card-ready"
|
|
119819
|
-
});
|
|
119820
|
-
}
|
|
119821
|
-
shouldStartCardImmediately() {
|
|
119822
|
-
return this.decision.startCardImmediately;
|
|
119823
|
-
}
|
|
119824
|
-
};
|
|
119825
|
-
|
|
119826
119755
|
// src/lark/postContent.ts
|
|
119827
119756
|
function assertSafeUserId(userId) {
|
|
119828
119757
|
if (!/^[A-Za-z0-9_:-]+$/.test(userId)) {
|
|
@@ -120590,162 +120519,6 @@ async function dispatchResponseSurface(input) {
|
|
|
120590
120519
|
return result;
|
|
120591
120520
|
}
|
|
120592
120521
|
|
|
120593
|
-
// src/bridge/postProgress.ts
|
|
120594
|
-
var DEFAULT_PLACEHOLDER_TEXT = "\u52AA\u529B\u56DE\u7B54\u4E2D...";
|
|
120595
|
-
var DEFAULT_PATCH_INTERVAL_MS2 = 1500;
|
|
120596
|
-
var DEFAULT_MAX_PROGRESS_EDITS = 16;
|
|
120597
|
-
function normalizeText2(text) {
|
|
120598
|
-
return text.replace(/\r\n/g, "\n").trim();
|
|
120599
|
-
}
|
|
120600
|
-
function progressText(raw, fallback) {
|
|
120601
|
-
const text = normalizeText2(raw);
|
|
120602
|
-
if (!text) return fallback;
|
|
120603
|
-
return text.length > 3500 ? `${text.slice(0, 3500)}
|
|
120604
|
-
|
|
120605
|
-
_\u5904\u7406\u4E2D\u5185\u5BB9\u8F83\u957F\uFF0C\u7EC8\u7A3F\u4F1A\u6536\u655B\u3002_` : text;
|
|
120606
|
-
}
|
|
120607
|
-
var LivePostProgressHandle = class {
|
|
120608
|
-
messageId;
|
|
120609
|
-
idempotencyKey;
|
|
120610
|
-
role = "primary";
|
|
120611
|
-
postClient;
|
|
120612
|
-
patchIntervalMs;
|
|
120613
|
-
maxProgressEdits;
|
|
120614
|
-
initialText;
|
|
120615
|
-
textBuffer = "";
|
|
120616
|
-
lastPatchedText = "";
|
|
120617
|
-
progressEdits = 0;
|
|
120618
|
-
pendingPatch = null;
|
|
120619
|
-
inFlight = Promise.resolve();
|
|
120620
|
-
closed = false;
|
|
120621
|
-
constructor(opts) {
|
|
120622
|
-
this.postClient = opts.postClient;
|
|
120623
|
-
this.messageId = opts.messageId;
|
|
120624
|
-
this.idempotencyKey = opts.idempotencyKey;
|
|
120625
|
-
this.initialText = opts.initialText;
|
|
120626
|
-
this.lastPatchedText = opts.initialText;
|
|
120627
|
-
this.patchIntervalMs = opts.patchIntervalMs;
|
|
120628
|
-
this.maxProgressEdits = opts.maxProgressEdits;
|
|
120629
|
-
}
|
|
120630
|
-
handle(event) {
|
|
120631
|
-
if (this.closed) return;
|
|
120632
|
-
if (event.type === "answer_delta") {
|
|
120633
|
-
this.textBuffer += event.text;
|
|
120634
|
-
} else if (event.type === "answer_snapshot") {
|
|
120635
|
-
this.textBuffer = event.text;
|
|
120636
|
-
} else {
|
|
120637
|
-
return;
|
|
120638
|
-
}
|
|
120639
|
-
this.schedulePatch();
|
|
120640
|
-
}
|
|
120641
|
-
async finalize(opts) {
|
|
120642
|
-
await this.drain();
|
|
120643
|
-
const finalText = normalizeText2(opts.text) || this.initialText;
|
|
120644
|
-
await this.update(finalText, opts.mentions);
|
|
120645
|
-
}
|
|
120646
|
-
async drain() {
|
|
120647
|
-
this.closed = true;
|
|
120648
|
-
if (this.pendingPatch) {
|
|
120649
|
-
clearTimeout(this.pendingPatch);
|
|
120650
|
-
this.pendingPatch = null;
|
|
120651
|
-
}
|
|
120652
|
-
await this.inFlight;
|
|
120653
|
-
}
|
|
120654
|
-
close() {
|
|
120655
|
-
this.closed = true;
|
|
120656
|
-
if (this.pendingPatch) {
|
|
120657
|
-
clearTimeout(this.pendingPatch);
|
|
120658
|
-
this.pendingPatch = null;
|
|
120659
|
-
}
|
|
120660
|
-
}
|
|
120661
|
-
schedulePatch() {
|
|
120662
|
-
if (this.pendingPatch || this.progressEdits >= this.maxProgressEdits) return;
|
|
120663
|
-
this.pendingPatch = setTimeout(() => {
|
|
120664
|
-
this.pendingPatch = null;
|
|
120665
|
-
void this.patchProgress();
|
|
120666
|
-
}, this.patchIntervalMs);
|
|
120667
|
-
this.pendingPatch.unref?.();
|
|
120668
|
-
}
|
|
120669
|
-
async patchProgress() {
|
|
120670
|
-
if (this.closed || this.progressEdits >= this.maxProgressEdits) return;
|
|
120671
|
-
const nextText = progressText(this.textBuffer, this.initialText);
|
|
120672
|
-
if (nextText === this.lastPatchedText) return;
|
|
120673
|
-
this.progressEdits += 1;
|
|
120674
|
-
this.inFlight = this.inFlight.then(() => this.update(nextText)).catch((err) => {
|
|
120675
|
-
console.warn("[post_progress] progress update failed (continuing):", err);
|
|
120676
|
-
});
|
|
120677
|
-
await this.inFlight;
|
|
120678
|
-
}
|
|
120679
|
-
async update(text, mentions = []) {
|
|
120680
|
-
const content = buildPostContent({ text, mentions });
|
|
120681
|
-
await this.postClient.updatePost(this.messageId, content);
|
|
120682
|
-
this.lastPatchedText = text;
|
|
120683
|
-
}
|
|
120684
|
-
};
|
|
120685
|
-
async function createPostProgressHandle(opts) {
|
|
120686
|
-
const role = "primary";
|
|
120687
|
-
const initialText = normalizeText2(opts.initialText ?? DEFAULT_PLACEHOLDER_TEXT);
|
|
120688
|
-
const idempotencyKey2 = derivePostIdempotencyKey({
|
|
120689
|
-
botId: opts.facts.botId,
|
|
120690
|
-
threadId: opts.facts.threadId,
|
|
120691
|
-
triggerMessageId: opts.facts.triggerMessageId,
|
|
120692
|
-
role,
|
|
120693
|
-
logicalIndex: 0,
|
|
120694
|
-
contentDigest: digestPostContent("live-progress-placeholder")
|
|
120695
|
-
});
|
|
120696
|
-
const sent = await opts.postClient.createPostReply(
|
|
120697
|
-
opts.replyToMessageId,
|
|
120698
|
-
buildPostContent({ text: initialText }),
|
|
120699
|
-
{
|
|
120700
|
-
replyInThread: opts.replyInThread,
|
|
120701
|
-
idempotencyKey: idempotencyKey2
|
|
120702
|
-
}
|
|
120703
|
-
);
|
|
120704
|
-
return new LivePostProgressHandle({
|
|
120705
|
-
postClient: opts.postClient,
|
|
120706
|
-
messageId: sent.messageId,
|
|
120707
|
-
idempotencyKey: idempotencyKey2,
|
|
120708
|
-
initialText,
|
|
120709
|
-
patchIntervalMs: opts.patchIntervalMs ?? DEFAULT_PATCH_INTERVAL_MS2,
|
|
120710
|
-
maxProgressEdits: opts.maxProgressEdits ?? DEFAULT_MAX_PROGRESS_EDITS
|
|
120711
|
-
});
|
|
120712
|
-
}
|
|
120713
|
-
|
|
120714
|
-
// src/bridge/postBudget.ts
|
|
120715
|
-
function scopeKey(scope) {
|
|
120716
|
-
return `${scope.botId}\0${scope.chatId}\0${scope.threadId}`;
|
|
120717
|
-
}
|
|
120718
|
-
var ResponseSurfacePostBudget = class {
|
|
120719
|
-
buckets = /* @__PURE__ */ new Map();
|
|
120720
|
-
reserve(input) {
|
|
120721
|
-
const nowMs = input.nowMs ?? Date.now();
|
|
120722
|
-
const limit = Math.max(0, Math.floor(input.maxPosts));
|
|
120723
|
-
const windowMs = Math.max(1, Math.floor(input.windowMs));
|
|
120724
|
-
const key = scopeKey(input.scope);
|
|
120725
|
-
const cutoff = nowMs - windowMs;
|
|
120726
|
-
const existing = (this.buckets.get(key) ?? []).filter((ts) => ts > cutoff);
|
|
120727
|
-
if (limit < 1 || existing.length >= limit) {
|
|
120728
|
-
this.buckets.set(key, existing);
|
|
120729
|
-
return {
|
|
120730
|
-
allowed: false,
|
|
120731
|
-
used: existing.length,
|
|
120732
|
-
limit,
|
|
120733
|
-
windowMs,
|
|
120734
|
-
resetAt: existing.length > 0 ? new Date(Math.min(...existing) + windowMs).toISOString() : void 0,
|
|
120735
|
-
reason: "post-window-exhausted"
|
|
120736
|
-
};
|
|
120737
|
-
}
|
|
120738
|
-
const next = [...existing, nowMs];
|
|
120739
|
-
this.buckets.set(key, next);
|
|
120740
|
-
return {
|
|
120741
|
-
allowed: true,
|
|
120742
|
-
used: next.length,
|
|
120743
|
-
limit,
|
|
120744
|
-
windowMs
|
|
120745
|
-
};
|
|
120746
|
-
}
|
|
120747
|
-
};
|
|
120748
|
-
|
|
120749
120522
|
// src/bridge/handler.ts
|
|
120750
120523
|
var DEFAULT_CARDKIT_RESPONSE_SURFACE_TIMEOUT_MS = 20 * 60 * 1e3;
|
|
120751
120524
|
function execGit(cwd, args) {
|
|
@@ -121002,7 +120775,6 @@ async function createOnlyPostFallback(opts) {
|
|
|
121002
120775
|
}
|
|
121003
120776
|
var BridgeHandler = class {
|
|
121004
120777
|
deps;
|
|
121005
|
-
responseSurfacePostBudget = new ResponseSurfacePostBudget();
|
|
121006
120778
|
closed = false;
|
|
121007
120779
|
constructor(deps) {
|
|
121008
120780
|
this.deps = deps;
|
|
@@ -121115,31 +120887,19 @@ var BridgeHandler = class {
|
|
|
121115
120887
|
const isTopLevel = !(typeof parsed.raw.root_id === "string" && parsed.raw.root_id);
|
|
121116
120888
|
const replyInThread = isTopLevel;
|
|
121117
120889
|
const prototypeConfig = this.deps.botConfig?.response_surface_prototype;
|
|
121118
|
-
const postOutboundAvailable = isResponseSurfacePostOutboundAvailable(
|
|
121119
|
-
prototypeConfig,
|
|
121120
|
-
{ chatId: parsed.chatId, threadId },
|
|
121121
|
-
{ postClientAvailable: !!this.deps.postClient }
|
|
121122
|
-
);
|
|
121123
120890
|
const cardKitAvailable = isResponseSurfaceCardKitAvailable(
|
|
121124
120891
|
prototypeConfig,
|
|
121125
120892
|
{ chatId: parsed.chatId, threadId },
|
|
121126
120893
|
{ cardKitClientAvailable: !!this.deps.cardKitClient }
|
|
121127
120894
|
);
|
|
121128
|
-
const surfaceController = SurfaceController.create({
|
|
121129
|
-
prototypeConfig,
|
|
121130
|
-
chatId: parsed.chatId,
|
|
121131
|
-
threadId,
|
|
121132
|
-
postOutboundAvailable: false,
|
|
121133
|
-
postLedgerAvailable: true,
|
|
121134
|
-
visibleFallbackAvailable: true
|
|
121135
|
-
});
|
|
121136
120895
|
let card;
|
|
121137
120896
|
let cardKitProgress;
|
|
121138
120897
|
let cardKitRecord;
|
|
121139
120898
|
let cardKitStartFailed = false;
|
|
121140
|
-
let
|
|
121141
|
-
let
|
|
121142
|
-
|
|
120899
|
+
let legacyCardStartFailed = false;
|
|
120900
|
+
let legacyCardStartFailureReason;
|
|
120901
|
+
let startFailurePostFallbackSent = false;
|
|
120902
|
+
if (!cardKitAvailable) {
|
|
121143
120903
|
try {
|
|
121144
120904
|
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
121145
120905
|
await recordEvent({
|
|
@@ -121149,6 +120909,8 @@ var BridgeHandler = class {
|
|
|
121149
120909
|
reason: "\u5DF2\u4EA4\u7ED9\u672C\u5730 Agent \u5904\u7406\u3002"
|
|
121150
120910
|
});
|
|
121151
120911
|
} catch (err) {
|
|
120912
|
+
legacyCardStartFailed = true;
|
|
120913
|
+
legacyCardStartFailureReason = String(err);
|
|
121152
120914
|
console.error("[bridge.handler] Failed to start card for thread", threadId, err);
|
|
121153
120915
|
await recordEvent({
|
|
121154
120916
|
status: "running",
|
|
@@ -121164,7 +120926,7 @@ var BridgeHandler = class {
|
|
|
121164
120926
|
status: "running",
|
|
121165
120927
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
121166
120928
|
appendPath: "\u5EF6\u8FDF\u521B\u5EFA\u5361\u7247",
|
|
121167
|
-
reason: "
|
|
120929
|
+
reason: "CardKit response surface is available; legacy card is reserved for fallback."
|
|
121168
120930
|
});
|
|
121169
120931
|
}
|
|
121170
120932
|
try {
|
|
@@ -121386,72 +121148,34 @@ var BridgeHandler = class {
|
|
|
121386
121148
|
}
|
|
121387
121149
|
}
|
|
121388
121150
|
}
|
|
121389
|
-
if (!card &&
|
|
121390
|
-
const budget = prototypeConfig ? this.responseSurfacePostBudget.reserve({
|
|
121391
|
-
scope: {
|
|
121392
|
-
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
121393
|
-
chatId: parsed.chatId,
|
|
121394
|
-
threadId
|
|
121395
|
-
},
|
|
121396
|
-
maxPosts: prototypeConfig.max_posts_per_window,
|
|
121397
|
-
windowMs: prototypeConfig.post_window_ms
|
|
121398
|
-
}) : void 0;
|
|
121399
|
-
if (budget?.allowed === false) {
|
|
121400
|
-
console.warn("[bridge.handler] post progress budget exhausted; using card fallback");
|
|
121401
|
-
progressPostStartFailed = true;
|
|
121402
|
-
} else {
|
|
121403
|
-
try {
|
|
121404
|
-
progressPost = await createPostProgressHandle({
|
|
121405
|
-
postClient: this.deps.postClient,
|
|
121406
|
-
replyToMessageId: messageId,
|
|
121407
|
-
replyInThread,
|
|
121408
|
-
facts: {
|
|
121409
|
-
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
121410
|
-
threadId,
|
|
121411
|
-
triggerMessageId: messageId
|
|
121412
|
-
},
|
|
121413
|
-
initialText: "\u52AA\u529B\u56DE\u7B54\u4E2D..."
|
|
121414
|
-
});
|
|
121415
|
-
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
121416
|
-
await recordEvent({
|
|
121417
|
-
status: "running",
|
|
121418
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
121419
|
-
appendPath: "\u5DF2\u521B\u5EFA post",
|
|
121420
|
-
reason: "response surface \u4F7F\u7528 post \u4F5C\u4E3A\u672C\u8F6E\u4E3B\u56DE\u590D\u9762\u3002"
|
|
121421
|
-
});
|
|
121422
|
-
} catch (err) {
|
|
121423
|
-
progressPostStartFailed = true;
|
|
121424
|
-
console.warn("[bridge.handler] create progress post failed; using card fallback:", err);
|
|
121425
|
-
}
|
|
121426
|
-
}
|
|
121427
|
-
}
|
|
121428
|
-
if (!card && (progressPostStartFailed || cardKitStartFailed)) {
|
|
121151
|
+
if (!card && cardKitStartFailed) {
|
|
121429
121152
|
try {
|
|
121430
121153
|
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
121431
121154
|
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
121432
121155
|
await recordEvent({
|
|
121433
121156
|
status: "running",
|
|
121434
121157
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
121435
|
-
appendPath:
|
|
121436
|
-
reason:
|
|
121158
|
+
appendPath: "CardKit \u5931\u8D25\uFF0C\u5DF2\u521B\u5EFA\u5361\u7247",
|
|
121159
|
+
reason: "CardKit \u4E3B\u9762\u521B\u5EFA\u5931\u8D25\uFF0Cbridge \u4F7F\u7528\u53EF\u89C1\u5361\u7247\u515C\u5E95\u3002"
|
|
121437
121160
|
});
|
|
121438
121161
|
} catch (err) {
|
|
121439
121162
|
console.error(
|
|
121440
121163
|
"[bridge.handler] visible card fallback start failed after primary surface start failure:",
|
|
121441
121164
|
err
|
|
121442
121165
|
);
|
|
121443
|
-
await createOnlyPostFallback({
|
|
121166
|
+
const postFallback = await createOnlyPostFallback({
|
|
121444
121167
|
postClient: this.deps.postClient,
|
|
121445
121168
|
replyToMessageId: messageId,
|
|
121446
121169
|
replyInThread,
|
|
121447
121170
|
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
121448
121171
|
threadId,
|
|
121449
121172
|
triggerMessageId: messageId,
|
|
121450
|
-
finalText:
|
|
121173
|
+
finalText: "CardKit \u4E3B\u56DE\u590D\u9762\u521B\u5EFA\u5931\u8D25, legacy \u53EF\u89C1\u5361\u7247\u515C\u5E95\u4E5F\u521B\u5EFA\u5931\u8D25\u3002",
|
|
121451
121174
|
failureReason: String(err),
|
|
121452
121175
|
title: "Larkway fallback",
|
|
121453
121176
|
logPrefix: "[bridge.handler]"
|
|
121454
121177
|
});
|
|
121178
|
+
if (postFallback) startFailurePostFallbackSent = true;
|
|
121455
121179
|
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
121456
121180
|
await recordEvent({
|
|
121457
121181
|
status: "running",
|
|
@@ -121541,7 +121265,6 @@ var BridgeHandler = class {
|
|
|
121541
121265
|
for await (const ev of handle.events) {
|
|
121542
121266
|
if (cardKitProgress) cardKitProgress.handle(ev);
|
|
121543
121267
|
else if (card) card.handle(ev);
|
|
121544
|
-
else progressPost?.handle(ev);
|
|
121545
121268
|
if (ev.type === "system_init") {
|
|
121546
121269
|
sessionId = ev.sessionId;
|
|
121547
121270
|
}
|
|
@@ -121688,7 +121411,6 @@ var BridgeHandler = class {
|
|
|
121688
121411
|
}
|
|
121689
121412
|
}
|
|
121690
121413
|
} else {
|
|
121691
|
-
await progressPost?.drain();
|
|
121692
121414
|
const surfaceDispatch = await dispatchResponseSurface({
|
|
121693
121415
|
state: reportedState,
|
|
121694
121416
|
prototypeConfig,
|
|
@@ -121706,80 +121428,90 @@ var BridgeHandler = class {
|
|
|
121706
121428
|
postOutboundAvailable: false,
|
|
121707
121429
|
postLedgerAvailable: true,
|
|
121708
121430
|
visibleFallbackAvailable: true,
|
|
121709
|
-
postClient: this.deps.postClient
|
|
121710
|
-
livePost: progressPost ? {
|
|
121711
|
-
messageId: progressPost.messageId,
|
|
121712
|
-
idempotencyKey: progressPost.idempotencyKey,
|
|
121713
|
-
role: progressPost.role
|
|
121714
|
-
} : void 0,
|
|
121715
|
-
postBudget: prototypeConfig ? {
|
|
121716
|
-
reserve: () => this.responseSurfacePostBudget.reserve({
|
|
121717
|
-
scope: {
|
|
121718
|
-
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
121719
|
-
chatId: parsed.chatId,
|
|
121720
|
-
threadId
|
|
121721
|
-
},
|
|
121722
|
-
maxPosts: prototypeConfig.max_posts_per_window,
|
|
121723
|
-
windowMs: prototypeConfig.post_window_ms
|
|
121724
|
-
})
|
|
121725
|
-
} : void 0
|
|
121431
|
+
postClient: this.deps.postClient
|
|
121726
121432
|
});
|
|
121727
121433
|
if (surfaceDispatch.card) {
|
|
121728
121434
|
if (!card) {
|
|
121729
|
-
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
121730
121435
|
try {
|
|
121731
|
-
await
|
|
121732
|
-
|
|
121733
|
-
|
|
121734
|
-
|
|
121735
|
-
|
|
121736
|
-
|
|
121737
|
-
|
|
121738
|
-
|
|
121739
|
-
|
|
121740
|
-
|
|
121741
|
-
|
|
121742
|
-
|
|
121743
|
-
|
|
121744
|
-
let keepCardFileForRetry = false;
|
|
121745
|
-
if (surfaceDispatch.post?.requiresFallbackLedgerMark) {
|
|
121746
|
-
try {
|
|
121747
|
-
await markPostLedgerFallbackVisible(
|
|
121748
|
-
worktreePath,
|
|
121749
|
-
surfaceDispatch.post.idempotencyKey,
|
|
121750
|
-
{
|
|
121751
|
-
fallbackCardMessageId: card.messageId,
|
|
121752
|
-
error: surfaceDispatch.post.fallbackError ?? surfaceDispatch.card.failureReason ?? "post outbound failed; visible card fallback used"
|
|
121753
|
-
}
|
|
121754
|
-
);
|
|
121436
|
+
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
121437
|
+
try {
|
|
121438
|
+
await writeCardFile(worktreePath, {
|
|
121439
|
+
messageId: card.messageId,
|
|
121440
|
+
chatId: parsed.chatId,
|
|
121441
|
+
threadId,
|
|
121442
|
+
botId: this.deps.botConfig?.id ?? "",
|
|
121443
|
+
replyInThread,
|
|
121444
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
121445
|
+
});
|
|
121446
|
+
} catch (err) {
|
|
121447
|
+
console.warn("[bridge.handler] writeCardFile(late) failed (continuing):", err);
|
|
121448
|
+
}
|
|
121755
121449
|
} catch (err) {
|
|
121756
|
-
|
|
121757
|
-
|
|
121758
|
-
"[bridge.handler] fallback ledger mark failed after visible card finalize; keeping card.json for retry:",
|
|
121450
|
+
console.error(
|
|
121451
|
+
"[bridge.handler] late visible card fallback start failed; creating post fallback:",
|
|
121759
121452
|
err
|
|
121760
121453
|
);
|
|
121454
|
+
const failureReason2 = [
|
|
121455
|
+
legacyCardStartFailed ? `initial legacy visible card start failed: ${legacyCardStartFailureReason ?? "unknown"}` : void 0,
|
|
121456
|
+
`late legacy visible card fallback start failed: ${String(err)}`
|
|
121457
|
+
].filter((part) => !!part).join("; ");
|
|
121458
|
+
const postFallback = await createOnlyPostFallback({
|
|
121459
|
+
postClient: this.deps.postClient,
|
|
121460
|
+
replyToMessageId: messageId,
|
|
121461
|
+
replyInThread,
|
|
121462
|
+
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
121463
|
+
threadId,
|
|
121464
|
+
triggerMessageId: messageId,
|
|
121465
|
+
finalText: surfaceDispatch.card.finalText ?? "Larkway completed but no visible card was available.",
|
|
121466
|
+
failureReason: failureReason2,
|
|
121467
|
+
title: surfaceDispatch.card.titleOverride ?? "Larkway fallback",
|
|
121468
|
+
logPrefix: "[bridge.handler]"
|
|
121469
|
+
});
|
|
121470
|
+
if (!postFallback) throw err;
|
|
121761
121471
|
}
|
|
121762
121472
|
}
|
|
121763
|
-
if (
|
|
121764
|
-
|
|
121765
|
-
|
|
121766
|
-
|
|
121767
|
-
|
|
121768
|
-
|
|
121769
|
-
|
|
121770
|
-
|
|
121771
|
-
|
|
121772
|
-
|
|
121773
|
-
|
|
121774
|
-
|
|
121775
|
-
|
|
121776
|
-
|
|
121777
|
-
|
|
121778
|
-
|
|
121473
|
+
if (card) {
|
|
121474
|
+
await card.finalize(surfaceDispatch.card);
|
|
121475
|
+
let keepCardFileForRetry = false;
|
|
121476
|
+
if (surfaceDispatch.post?.requiresFallbackLedgerMark) {
|
|
121477
|
+
try {
|
|
121478
|
+
await markPostLedgerFallbackVisible(
|
|
121479
|
+
worktreePath,
|
|
121480
|
+
surfaceDispatch.post.idempotencyKey,
|
|
121481
|
+
{
|
|
121482
|
+
fallbackCardMessageId: card.messageId,
|
|
121483
|
+
error: surfaceDispatch.post.fallbackError ?? surfaceDispatch.card.failureReason ?? "post outbound failed; visible card fallback used"
|
|
121484
|
+
}
|
|
121485
|
+
);
|
|
121486
|
+
} catch (err) {
|
|
121487
|
+
keepCardFileForRetry = true;
|
|
121488
|
+
console.warn(
|
|
121489
|
+
"[bridge.handler] fallback ledger mark failed after visible card finalize; keeping card.json for retry:",
|
|
121490
|
+
err
|
|
121491
|
+
);
|
|
121492
|
+
}
|
|
121493
|
+
}
|
|
121494
|
+
if (surfaceDispatch.post?.requiresPolicyLedgerMark) {
|
|
121495
|
+
try {
|
|
121496
|
+
await markPostLedgerPolicyBlockedVisible(
|
|
121497
|
+
worktreePath,
|
|
121498
|
+
surfaceDispatch.post.idempotencyKey,
|
|
121499
|
+
{
|
|
121500
|
+
fallbackCardMessageId: card.messageId,
|
|
121501
|
+
error: surfaceDispatch.post.policyError ?? surfaceDispatch.card.failureReason ?? "mention policy blocked; visible card fallback used"
|
|
121502
|
+
}
|
|
121503
|
+
);
|
|
121504
|
+
} catch (err) {
|
|
121505
|
+
keepCardFileForRetry = true;
|
|
121506
|
+
console.warn(
|
|
121507
|
+
"[bridge.handler] policy-blocked ledger mark failed after visible card finalize; keeping card.json for retry:",
|
|
121508
|
+
err
|
|
121509
|
+
);
|
|
121510
|
+
}
|
|
121511
|
+
}
|
|
121512
|
+
if (!keepCardFileForRetry) {
|
|
121513
|
+
await deleteCardFile(worktreePath);
|
|
121779
121514
|
}
|
|
121780
|
-
}
|
|
121781
|
-
if (!keepCardFileForRetry) {
|
|
121782
|
-
await deleteCardFile(worktreePath);
|
|
121783
121515
|
}
|
|
121784
121516
|
}
|
|
121785
121517
|
}
|
|
@@ -121858,25 +121590,10 @@ var BridgeHandler = class {
|
|
|
121858
121590
|
}
|
|
121859
121591
|
}
|
|
121860
121592
|
}
|
|
121861
|
-
if (!card &&
|
|
121862
|
-
|
|
121863
|
-
|
|
121864
|
-
|
|
121865
|
-
});
|
|
121866
|
-
} catch (postFinalizeErr) {
|
|
121867
|
-
console.error(
|
|
121868
|
-
"[bridge.handler] progress post failure update failed; creating card fallback:",
|
|
121869
|
-
postFinalizeErr
|
|
121870
|
-
);
|
|
121871
|
-
try {
|
|
121872
|
-
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
121873
|
-
} catch (cardStartErr) {
|
|
121874
|
-
console.error("[bridge.handler] failure card start also failed:", cardStartErr);
|
|
121875
|
-
await createHardFailurePostFallback(
|
|
121876
|
-
`progress post failure update failed: ${String(postFinalizeErr)}; legacy visible card fallback also failed: ${String(cardStartErr)}`
|
|
121877
|
-
);
|
|
121878
|
-
}
|
|
121879
|
-
}
|
|
121593
|
+
if (!card && !cardKitProgress && !startFailurePostFallbackSent) {
|
|
121594
|
+
await createHardFailurePostFallback(
|
|
121595
|
+
legacyCardStartFailed ? `legacy visible card was unavailable before agent failure: ${legacyCardStartFailureReason ?? "unknown"}` : "no visible response surface was available before agent failure"
|
|
121596
|
+
);
|
|
121880
121597
|
}
|
|
121881
121598
|
if (card) {
|
|
121882
121599
|
try {
|
|
@@ -125748,7 +125465,7 @@ function* parseLinesMulti(line, answerExtractor = new AnswerChannelExtractor())
|
|
|
125748
125465
|
if (typeof item !== "object" || item === null) continue;
|
|
125749
125466
|
const block = item;
|
|
125750
125467
|
if (block["type"] === "text" && typeof block["text"] === "string") {
|
|
125751
|
-
yield* answerExtractor.
|
|
125468
|
+
yield* answerExtractor.ingestGrowingSnapshot(block["text"], obj);
|
|
125752
125469
|
emitted = true;
|
|
125753
125470
|
} else if (block["type"] === "tool_use") {
|
|
125754
125471
|
yield {
|
|
@@ -126026,111 +125743,104 @@ function buildCodexEnv(botGitIdentity, gitlabToken) {
|
|
|
126026
125743
|
}
|
|
126027
125744
|
return env;
|
|
126028
125745
|
}
|
|
126029
|
-
function
|
|
126030
|
-
|
|
126031
|
-
|
|
126032
|
-
return ["--dangerously-bypass-approvals-and-sandbox"];
|
|
126033
|
-
case "acceptEdits":
|
|
126034
|
-
return ["--dangerously-bypass-approvals-and-sandbox"];
|
|
126035
|
-
case "ask":
|
|
126036
|
-
return ["--sandbox", "read-only"];
|
|
126037
|
-
}
|
|
125746
|
+
function buildCodexCommand(opts, codexBinPath = "codex") {
|
|
125747
|
+
void opts;
|
|
125748
|
+
return [codexBinPath, ["app-server", "--stdio"]];
|
|
126038
125749
|
}
|
|
126039
|
-
function
|
|
126040
|
-
return mode === "
|
|
125750
|
+
function codexThreadSandboxMode(mode) {
|
|
125751
|
+
return mode === "ask" ? "read-only" : "danger-full-access";
|
|
126041
125752
|
}
|
|
126042
|
-
function
|
|
126043
|
-
|
|
126044
|
-
|
|
126045
|
-
"--json",
|
|
126046
|
-
"--skip-git-repo-check",
|
|
126047
|
-
...sandboxFlag(mode)
|
|
126048
|
-
];
|
|
126049
|
-
if (opts.resumeSessionId != null) {
|
|
126050
|
-
const resumeFlags = [
|
|
126051
|
-
"--json",
|
|
126052
|
-
"--skip-git-repo-check",
|
|
126053
|
-
...resumePermissionFlag(mode)
|
|
126054
|
-
];
|
|
126055
|
-
return [
|
|
126056
|
-
codexBinPath,
|
|
126057
|
-
["exec", "resume", opts.resumeSessionId, ...resumeFlags, "-"]
|
|
126058
|
-
];
|
|
126059
|
-
}
|
|
126060
|
-
const freshFlags = opts.cwd != null ? ["-C", opts.cwd, ...commonFlags] : commonFlags;
|
|
126061
|
-
return [codexBinPath, ["exec", ...freshFlags]];
|
|
125753
|
+
function codexTurnSandboxPolicy(mode) {
|
|
125754
|
+
if (mode === "ask") return { type: "readOnly", networkAccess: false };
|
|
125755
|
+
return { type: "dangerFullAccess" };
|
|
126062
125756
|
}
|
|
126063
|
-
function
|
|
126064
|
-
|
|
126065
|
-
|
|
126066
|
-
|
|
126067
|
-
|
|
126068
|
-
|
|
126069
|
-
|
|
126070
|
-
|
|
126071
|
-
|
|
126072
|
-
|
|
126073
|
-
|
|
126074
|
-
|
|
126075
|
-
|
|
126076
|
-
|
|
126077
|
-
|
|
126078
|
-
|
|
126079
|
-
|
|
126080
|
-
|
|
126081
|
-
|
|
126082
|
-
|
|
126083
|
-
|
|
126084
|
-
|
|
126085
|
-
|
|
126086
|
-
|
|
126087
|
-
|
|
126088
|
-
|
|
126089
|
-
|
|
126090
|
-
|
|
126091
|
-
|
|
125757
|
+
function codexApprovalPolicy(mode) {
|
|
125758
|
+
return mode === "ask" ? "on-request" : "never";
|
|
125759
|
+
}
|
|
125760
|
+
var CodexAppServerLineParser = class {
|
|
125761
|
+
answerExtractor = new AnswerChannelExtractor();
|
|
125762
|
+
*parseMessage(obj) {
|
|
125763
|
+
if (typeof obj !== "object" || obj === null) {
|
|
125764
|
+
yield { type: "raw", raw: obj };
|
|
125765
|
+
return;
|
|
125766
|
+
}
|
|
125767
|
+
const record = obj;
|
|
125768
|
+
const method = record["method"];
|
|
125769
|
+
if (typeof method !== "string") {
|
|
125770
|
+
yield { type: "raw", raw: obj };
|
|
125771
|
+
return;
|
|
125772
|
+
}
|
|
125773
|
+
const params = asRecord(record["params"]);
|
|
125774
|
+
if (method === "thread/started") {
|
|
125775
|
+
const thread = asRecord(params?.["thread"]);
|
|
125776
|
+
const threadId = typeof thread?.["id"] === "string" ? thread["id"] : void 0;
|
|
125777
|
+
if (threadId) yield { type: "system_init", sessionId: threadId, raw: obj };
|
|
125778
|
+
return;
|
|
125779
|
+
}
|
|
125780
|
+
if (method === "turn/completed") {
|
|
125781
|
+
yield { type: "result", stopReason: "end_turn", raw: obj };
|
|
125782
|
+
return;
|
|
125783
|
+
}
|
|
125784
|
+
if (method === "item/agentMessage/delta") {
|
|
125785
|
+
const delta = typeof params?.["delta"] === "string" ? params["delta"] : "";
|
|
125786
|
+
yield* this.answerExtractor.ingestDelta(delta, obj);
|
|
125787
|
+
return;
|
|
125788
|
+
}
|
|
125789
|
+
if (method === "item/started") {
|
|
125790
|
+
const item = asRecord(params?.["item"]);
|
|
125791
|
+
if (item?.["type"] === "commandExecution" && typeof item["command"] === "string") {
|
|
126092
125792
|
yield {
|
|
126093
125793
|
type: "tool_use",
|
|
126094
125794
|
toolName: "shell",
|
|
126095
|
-
toolInput: { command:
|
|
125795
|
+
toolInput: { command: item["command"] },
|
|
126096
125796
|
raw: obj
|
|
126097
125797
|
};
|
|
126098
125798
|
return;
|
|
126099
125799
|
}
|
|
125800
|
+
return;
|
|
126100
125801
|
}
|
|
126101
|
-
|
|
126102
|
-
|
|
126103
|
-
|
|
126104
|
-
if (topType === "item.completed") {
|
|
126105
|
-
const item = record["item"];
|
|
126106
|
-
if (typeof item === "object" && item !== null) {
|
|
126107
|
-
const itemRecord = item;
|
|
126108
|
-
if (itemRecord["type"] === "command_execution") {
|
|
125802
|
+
if (method === "item/completed") {
|
|
125803
|
+
const item = asRecord(params?.["item"]);
|
|
125804
|
+
if (item?.["type"] === "commandExecution") {
|
|
126109
125805
|
yield { type: "tool_result", raw: obj };
|
|
126110
125806
|
return;
|
|
126111
125807
|
}
|
|
126112
|
-
if (
|
|
126113
|
-
yield*
|
|
125808
|
+
if (item?.["type"] === "agentMessage" && typeof item["text"] === "string") {
|
|
125809
|
+
yield* this.answerExtractor.ingestSnapshot(item["text"], obj);
|
|
126114
125810
|
return;
|
|
126115
125811
|
}
|
|
125812
|
+
return;
|
|
126116
125813
|
}
|
|
126117
125814
|
yield { type: "raw", raw: obj };
|
|
126118
|
-
return;
|
|
126119
125815
|
}
|
|
126120
|
-
|
|
125816
|
+
};
|
|
125817
|
+
function asRecord(value) {
|
|
125818
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
125819
|
+
}
|
|
125820
|
+
function extractThreadIdFromThreadResponse(obj) {
|
|
125821
|
+
const record = asRecord(obj);
|
|
125822
|
+
const result = asRecord(record?.["result"]);
|
|
125823
|
+
const thread = asRecord(result?.["thread"]);
|
|
125824
|
+
const threadId = thread?.["id"];
|
|
125825
|
+
return typeof threadId === "string" ? threadId : void 0;
|
|
126121
125826
|
}
|
|
126122
125827
|
function runCodex(opts, codexBinPath = "codex") {
|
|
126123
125828
|
const timeoutMs = opts.timeoutMs ?? 15 * 60 * 1e3;
|
|
126124
125829
|
const [bin, args] = buildCodexCommand(opts, codexBinPath);
|
|
126125
125830
|
const env = buildCodexEnv(opts.botGitIdentity, opts.gitlabToken);
|
|
125831
|
+
const mode = opts.permissionMode ?? "acceptEdits";
|
|
125832
|
+
const requestById = /* @__PURE__ */ new Map();
|
|
125833
|
+
let nextRequestId = 1;
|
|
126126
125834
|
const child = spawn3(bin, args, {
|
|
126127
125835
|
env,
|
|
126128
125836
|
stdio: ["pipe", "pipe", "pipe"],
|
|
126129
125837
|
...opts.cwd != null ? { cwd: opts.cwd } : {}
|
|
126130
125838
|
});
|
|
126131
|
-
|
|
126132
|
-
|
|
126133
|
-
|
|
125839
|
+
function sendRequest(method, params) {
|
|
125840
|
+
const id = nextRequestId++;
|
|
125841
|
+
requestById.set(id, method);
|
|
125842
|
+
child.stdin?.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
|
|
125843
|
+
return id;
|
|
126134
125844
|
}
|
|
126135
125845
|
let discoveredSessionId;
|
|
126136
125846
|
let killScheduled = false;
|
|
@@ -126144,6 +125854,10 @@ function runCodex(opts, codexBinPath = "codex") {
|
|
|
126144
125854
|
}, SIGKILL_GRACE_MS2);
|
|
126145
125855
|
killTimer.unref();
|
|
126146
125856
|
}
|
|
125857
|
+
function stopAppServerAfterTurn() {
|
|
125858
|
+
if (child.killed || killScheduled) return;
|
|
125859
|
+
child.kill("SIGTERM");
|
|
125860
|
+
}
|
|
126147
125861
|
const TOTAL_TIMEOUT_EXTRA_MS = SIGKILL_GRACE_MS2 + 2e3;
|
|
126148
125862
|
let totalTimeoutFallbackHandle;
|
|
126149
125863
|
let _forceFinalizeForTimeout = () => {
|
|
@@ -126166,6 +125880,8 @@ function runCodex(opts, codexBinPath = "codex") {
|
|
|
126166
125880
|
const stderrChunks = [];
|
|
126167
125881
|
child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
|
|
126168
125882
|
const rlAbortController = new AbortController();
|
|
125883
|
+
let finishAppServerTurn;
|
|
125884
|
+
let failAppServerTurn;
|
|
126169
125885
|
const done = new Promise(
|
|
126170
125886
|
(resolve2, reject) => {
|
|
126171
125887
|
let settled = false;
|
|
@@ -126195,6 +125911,17 @@ stderr: ${stderr}` : "")
|
|
|
126195
125911
|
}
|
|
126196
125912
|
resolve2({ exitCode, sessionId: discoveredSessionId });
|
|
126197
125913
|
};
|
|
125914
|
+
const finalizeReject = (err) => {
|
|
125915
|
+
if (settled) return;
|
|
125916
|
+
settled = true;
|
|
125917
|
+
clearTimeout(timeoutHandle);
|
|
125918
|
+
clearTimeout(killTimer);
|
|
125919
|
+
clearTimeout(totalTimeoutFallbackHandle);
|
|
125920
|
+
rlAbortController.abort();
|
|
125921
|
+
reject(err);
|
|
125922
|
+
};
|
|
125923
|
+
finishAppServerTurn = finalizeResolve;
|
|
125924
|
+
failAppServerTurn = finalizeReject;
|
|
126198
125925
|
_forceFinalizeForTimeout = () => {
|
|
126199
125926
|
if (settled) return;
|
|
126200
125927
|
console.warn(
|
|
@@ -126242,14 +125969,76 @@ stderr: ${stderr}` : "")
|
|
|
126242
125969
|
crlfDelay: Infinity,
|
|
126243
125970
|
signal: rlAbortController.signal
|
|
126244
125971
|
});
|
|
125972
|
+
const parser = new CodexAppServerLineParser();
|
|
125973
|
+
let turnCompleted = false;
|
|
125974
|
+
sendRequest("initialize", {
|
|
125975
|
+
clientInfo: { name: "larkway", version: "0.3" },
|
|
125976
|
+
capabilities: {}
|
|
125977
|
+
});
|
|
126245
125978
|
try {
|
|
126246
125979
|
for await (const line of rl) {
|
|
126247
|
-
|
|
125980
|
+
const trimmed = line.trim();
|
|
125981
|
+
if (!trimmed) continue;
|
|
125982
|
+
let obj;
|
|
125983
|
+
try {
|
|
125984
|
+
obj = JSON.parse(trimmed);
|
|
125985
|
+
} catch {
|
|
125986
|
+
yield { type: "raw", raw: trimmed };
|
|
125987
|
+
continue;
|
|
125988
|
+
}
|
|
125989
|
+
const response = asRecord(obj);
|
|
125990
|
+
if (typeof response?.["id"] === "number") {
|
|
125991
|
+
const id = response["id"];
|
|
125992
|
+
const method = requestById.get(id);
|
|
125993
|
+
requestById.delete(id);
|
|
125994
|
+
const error = asRecord(response["error"]);
|
|
125995
|
+
if (error) {
|
|
125996
|
+
const message = typeof error["message"] === "string" ? error["message"] : JSON.stringify(error);
|
|
125997
|
+
failAppServerTurn?.(new Error(`codex app-server ${method ?? "request"} failed: ${message}`));
|
|
125998
|
+
stopAppServerAfterTurn();
|
|
125999
|
+
return;
|
|
126000
|
+
}
|
|
126001
|
+
if (method === "initialize") {
|
|
126002
|
+
const threadMethod = opts.resumeSessionId != null ? "thread/resume" : "thread/start";
|
|
126003
|
+
const threadParams = opts.resumeSessionId != null ? { threadId: opts.resumeSessionId } : { ephemeral: false, sessionStartSource: "startup" };
|
|
126004
|
+
if (opts.cwd != null) threadParams["cwd"] = opts.cwd;
|
|
126005
|
+
threadParams["approvalPolicy"] = codexApprovalPolicy(mode);
|
|
126006
|
+
threadParams["sandbox"] = codexThreadSandboxMode(mode);
|
|
126007
|
+
sendRequest(threadMethod, threadParams);
|
|
126008
|
+
continue;
|
|
126009
|
+
}
|
|
126010
|
+
if (method === "thread/start" || method === "thread/resume") {
|
|
126011
|
+
const threadId = extractThreadIdFromThreadResponse(obj);
|
|
126012
|
+
if (threadId) {
|
|
126013
|
+
discoveredSessionId = threadId;
|
|
126014
|
+
yield { type: "system_init", sessionId: threadId, raw: obj };
|
|
126015
|
+
const turnParams = {
|
|
126016
|
+
threadId,
|
|
126017
|
+
input: [{ type: "text", text: opts.prompt, text_elements: [] }],
|
|
126018
|
+
approvalPolicy: codexApprovalPolicy(mode),
|
|
126019
|
+
sandboxPolicy: codexTurnSandboxPolicy(mode)
|
|
126020
|
+
};
|
|
126021
|
+
if (opts.cwd != null) turnParams["cwd"] = opts.cwd;
|
|
126022
|
+
sendRequest("turn/start", turnParams);
|
|
126023
|
+
}
|
|
126024
|
+
continue;
|
|
126025
|
+
}
|
|
126026
|
+
continue;
|
|
126027
|
+
}
|
|
126028
|
+
for (const event of parser.parseMessage(obj)) {
|
|
126248
126029
|
if (event.type === "system_init") {
|
|
126249
126030
|
discoveredSessionId = event.sessionId;
|
|
126250
126031
|
}
|
|
126032
|
+
if (event.type === "result") {
|
|
126033
|
+
turnCompleted = true;
|
|
126034
|
+
}
|
|
126251
126035
|
yield event;
|
|
126252
126036
|
}
|
|
126037
|
+
if (turnCompleted) {
|
|
126038
|
+
stopAppServerAfterTurn();
|
|
126039
|
+
finishAppServerTurn?.(0);
|
|
126040
|
+
return;
|
|
126041
|
+
}
|
|
126253
126042
|
}
|
|
126254
126043
|
} catch (err) {
|
|
126255
126044
|
const isAbort = err instanceof Error && (err.name === "AbortError" || err.code === "ABORT_ERR");
|