lody 0.52.3 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1046 -201
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -23,9 +23,9 @@ import require$$1$4 from "async_hooks";
|
|
|
23
23
|
import require$$1$5, { execFile, spawn as spawn$1 } from "node:child_process";
|
|
24
24
|
import fs$6, { readdir, readFile, createReadStream, existsSync, readFileSync as readFileSync$1, promises } from "node:fs";
|
|
25
25
|
import * as os from "node:os";
|
|
26
|
-
import os__default$1 from "node:os";
|
|
26
|
+
import os__default$1, { homedir } from "node:os";
|
|
27
27
|
import * as path$3 from "node:path";
|
|
28
|
-
import path__default$1, { join as join$2, dirname as dirname$1, posix, sep as sep$1, resolve as resolve$2, relative, isAbsolute } from "node:path";
|
|
28
|
+
import path__default$1, { join as join$2, dirname as dirname$1, posix, sep as sep$1, delimiter, normalize as normalize$2, resolve as resolve$2, relative, isAbsolute } from "node:path";
|
|
29
29
|
import * as util$2 from "node:util";
|
|
30
30
|
import util__default, { format as format$8, promisify, inspect as inspect$2 } from "node:util";
|
|
31
31
|
import * as readline$1 from "node:readline";
|
|
@@ -5144,8 +5144,8 @@ let __tla = Promise.all([
|
|
|
5144
5144
|
}
|
|
5145
5145
|
return debug2;
|
|
5146
5146
|
}
|
|
5147
|
-
function extend2(namespace,
|
|
5148
|
-
const newDebug = createDebug(this.namespace + (typeof
|
|
5147
|
+
function extend2(namespace, delimiter2) {
|
|
5148
|
+
const newDebug = createDebug(this.namespace + (typeof delimiter2 === "undefined" ? ":" : delimiter2) + namespace);
|
|
5149
5149
|
newDebug.log = this.log;
|
|
5150
5150
|
return newDebug;
|
|
5151
5151
|
}
|
|
@@ -8644,7 +8644,7 @@ Error:`, e);
|
|
|
8644
8644
|
}
|
|
8645
8645
|
return newLine;
|
|
8646
8646
|
}
|
|
8647
|
-
function safeJoin(input2,
|
|
8647
|
+
function safeJoin(input2, delimiter2) {
|
|
8648
8648
|
if (!Array.isArray(input2)) {
|
|
8649
8649
|
return "";
|
|
8650
8650
|
}
|
|
@@ -8661,7 +8661,7 @@ Error:`, e);
|
|
|
8661
8661
|
output.push("[value cannot be serialized]");
|
|
8662
8662
|
}
|
|
8663
8663
|
}
|
|
8664
|
-
return output.join(
|
|
8664
|
+
return output.join(delimiter2);
|
|
8665
8665
|
}
|
|
8666
8666
|
function isMatchingPattern(value, pattern2, requireExactStringMatch = false) {
|
|
8667
8667
|
if (!isString$4(value)) {
|
|
@@ -36822,7 +36822,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
|
|
|
36822
36822
|
return client;
|
|
36823
36823
|
}
|
|
36824
36824
|
const name = "lody";
|
|
36825
|
-
const version$4 = "0.
|
|
36825
|
+
const version$4 = "0.53.0";
|
|
36826
36826
|
const description$1 = "Lody Agent CLI tool for managing remote command execution";
|
|
36827
36827
|
const type$2 = "module";
|
|
36828
36828
|
const main$3 = "dist/index.js";
|
|
@@ -36866,7 +36866,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
|
|
|
36866
36866
|
};
|
|
36867
36867
|
const optionalDependencies = {
|
|
36868
36868
|
"acp-extension-claude": "0.34.3",
|
|
36869
|
-
"acp-extension-codex": "0.14.
|
|
36869
|
+
"acp-extension-codex": "0.14.5"
|
|
36870
36870
|
};
|
|
36871
36871
|
const devDependencies = {
|
|
36872
36872
|
"@agentclientprotocol/sdk": "catalog:",
|
|
@@ -48967,8 +48967,8 @@ ${originalIndentation}`;
|
|
|
48967
48967
|
return "#" + Array(6 - color.length + 1).join("0") + color;
|
|
48968
48968
|
};
|
|
48969
48969
|
var hex = getDefaultExportFromCjs2(textHex);
|
|
48970
|
-
function colorspace(namespace,
|
|
48971
|
-
const split2 = namespace.split(
|
|
48970
|
+
function colorspace(namespace, delimiter2) {
|
|
48971
|
+
const split2 = namespace.split(delimiter2 || ":");
|
|
48972
48972
|
let base = hex(split2[0]);
|
|
48973
48973
|
if (!split2.length) return base;
|
|
48974
48974
|
for (let i2 = 0, l = split2.length - 1; i2 < l; i2++) {
|
|
@@ -73599,13 +73599,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
73599
73599
|
const getLoroPreviewCommentStreamId = (workspaceId, sessionId) => `${workspaceId}:${LORO_PREVIEW_COMMENT_STREAM_SEGMENT}:${sessionId}`;
|
|
73600
73600
|
const LODY_FULL_ACCESS_MODE_ID = "lodyFullAccess";
|
|
73601
73601
|
const isFullAccessModeId = (modeId) => modeId === LODY_FULL_ACCESS_MODE_ID || modeId === "bypassPermissions" || modeId === "full-access";
|
|
73602
|
-
const ACP_CAPABILITY_CACHE_VERSION =
|
|
73602
|
+
const ACP_CAPABILITY_CACHE_VERSION = 2;
|
|
73603
73603
|
const getAcpCapabilityCacheKey = (cliType, agentType) => `${cliType}:${agentType}`;
|
|
73604
|
+
const isAcpCapabilityCacheEntryCurrent = (entry2) => entry2?.cacheVersion === ACP_CAPABILITY_CACHE_VERSION;
|
|
73604
73605
|
const getAcpCapabilityCacheStaleReason = (entry2, expectedSourceVersion) => {
|
|
73605
73606
|
if (!entry2) {
|
|
73606
73607
|
return "missing";
|
|
73607
73608
|
}
|
|
73608
|
-
if (entry2
|
|
73609
|
+
if (!isAcpCapabilityCacheEntryCurrent(entry2)) {
|
|
73609
73610
|
return "cache-version-mismatch";
|
|
73610
73611
|
}
|
|
73611
73612
|
if (entry2.sourceVersion !== expectedSourceVersion) {
|
|
@@ -77626,6 +77627,8 @@ Task description:
|
|
|
77626
77627
|
return Array.isArray(v.images) && v.images.length > 0 ? true : "Missing images";
|
|
77627
77628
|
case "plan":
|
|
77628
77629
|
return Array.isArray(v.entries) ? true : "Missing entries";
|
|
77630
|
+
case "proposed_plan":
|
|
77631
|
+
return typeof v.turnId === "string" && typeof v.markdown === "string" && typeof v.status === "string" && typeof v.isLatest === "boolean" ? true : "Missing proposed plan metadata";
|
|
77629
77632
|
case "goal":
|
|
77630
77633
|
return typeof v.threadId === "string" && typeof v.objective === "string" && typeof v.status === "string" && typeof v.tokensUsed === "number" && typeof v.timeUsedSeconds === "number" && typeof v.createdAt === "number" && typeof v.updatedAt === "number" ? true : "Missing goal metadata";
|
|
77631
77634
|
case "tool_call":
|
|
@@ -79151,6 +79154,17 @@ Task description:
|
|
|
79151
79154
|
type: literal("plan"),
|
|
79152
79155
|
entries: array$3(PlanEntrySchema)
|
|
79153
79156
|
}),
|
|
79157
|
+
object$1({
|
|
79158
|
+
type: literal("proposed_plan"),
|
|
79159
|
+
turnId: string$2(),
|
|
79160
|
+
markdown: string$2(),
|
|
79161
|
+
status: _enum$1([
|
|
79162
|
+
"delta",
|
|
79163
|
+
"completed",
|
|
79164
|
+
"cleared"
|
|
79165
|
+
]),
|
|
79166
|
+
isLatest: boolean()
|
|
79167
|
+
}),
|
|
79154
79168
|
object$1({
|
|
79155
79169
|
type: literal("goal"),
|
|
79156
79170
|
threadId: string$2(),
|
|
@@ -79468,12 +79482,12 @@ Task description:
|
|
|
79468
79482
|
{
|
|
79469
79483
|
id: "auggie",
|
|
79470
79484
|
name: "Auggie CLI",
|
|
79471
|
-
version: "0.
|
|
79485
|
+
version: "0.27.2",
|
|
79472
79486
|
description: "Augment Code's powerful software agent, backed by industry-leading context engine",
|
|
79473
79487
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/auggie.svg",
|
|
79474
79488
|
distribution: {
|
|
79475
79489
|
npx: {
|
|
79476
|
-
package: "@augmentcode/auggie@0.
|
|
79490
|
+
package: "@augmentcode/auggie@0.27.2",
|
|
79477
79491
|
args: [
|
|
79478
79492
|
"--acp"
|
|
79479
79493
|
],
|
|
@@ -79498,12 +79512,12 @@ Task description:
|
|
|
79498
79512
|
{
|
|
79499
79513
|
id: "cline",
|
|
79500
79514
|
name: "Cline",
|
|
79501
|
-
version: "3.0.
|
|
79515
|
+
version: "3.0.7",
|
|
79502
79516
|
description: "Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more",
|
|
79503
79517
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/cline.svg",
|
|
79504
79518
|
distribution: {
|
|
79505
79519
|
npx: {
|
|
79506
|
-
package: "cline@3.0.
|
|
79520
|
+
package: "cline@3.0.7",
|
|
79507
79521
|
args: [
|
|
79508
79522
|
"--acp"
|
|
79509
79523
|
]
|
|
@@ -79513,12 +79527,12 @@ Task description:
|
|
|
79513
79527
|
{
|
|
79514
79528
|
id: "codebuddy-code",
|
|
79515
79529
|
name: "Codebuddy Code",
|
|
79516
|
-
version: "2.97.
|
|
79530
|
+
version: "2.97.3",
|
|
79517
79531
|
description: "Tencent Cloud's official intelligent coding tool",
|
|
79518
79532
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/codebuddy-code.svg",
|
|
79519
79533
|
distribution: {
|
|
79520
79534
|
npx: {
|
|
79521
|
-
package: "@tencent-ai/codebuddy-code@2.97.
|
|
79535
|
+
package: "@tencent-ai/codebuddy-code@2.97.3",
|
|
79522
79536
|
args: [
|
|
79523
79537
|
"--acp"
|
|
79524
79538
|
]
|
|
@@ -79573,12 +79587,12 @@ Task description:
|
|
|
79573
79587
|
{
|
|
79574
79588
|
id: "dirac",
|
|
79575
79589
|
name: "Dirac",
|
|
79576
|
-
version: "0.3.
|
|
79590
|
+
version: "0.3.44",
|
|
79577
79591
|
description: "Reduces API costs by more than 50%, produces better and faster work. Uses Hash anchored parallel edits, AST manipulation and a whole lot of neat optimizations. Fully Open Source.",
|
|
79578
79592
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/dirac.svg",
|
|
79579
79593
|
distribution: {
|
|
79580
79594
|
npx: {
|
|
79581
|
-
package: "dirac-cli@0.3.
|
|
79595
|
+
package: "dirac-cli@0.3.44",
|
|
79582
79596
|
args: [
|
|
79583
79597
|
"--acp"
|
|
79584
79598
|
]
|
|
@@ -79588,16 +79602,16 @@ Task description:
|
|
|
79588
79602
|
{
|
|
79589
79603
|
id: "factory-droid",
|
|
79590
79604
|
name: "Factory Droid",
|
|
79591
|
-
version: "0.
|
|
79605
|
+
version: "0.129.0",
|
|
79592
79606
|
description: "Factory Droid - AI coding agent powered by Factory AI",
|
|
79593
79607
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/factory-droid.svg",
|
|
79594
79608
|
distribution: {
|
|
79595
79609
|
npx: {
|
|
79596
|
-
package: "droid@0.
|
|
79610
|
+
package: "droid@0.129.0",
|
|
79597
79611
|
args: [
|
|
79598
79612
|
"exec",
|
|
79599
79613
|
"--output-format",
|
|
79600
|
-
"acp
|
|
79614
|
+
"acp"
|
|
79601
79615
|
],
|
|
79602
79616
|
env: {
|
|
79603
79617
|
DROID_DISABLE_AUTO_UPDATE: "true",
|
|
@@ -79609,12 +79623,12 @@ Task description:
|
|
|
79609
79623
|
{
|
|
79610
79624
|
id: "fast-agent",
|
|
79611
79625
|
name: "fast-agent",
|
|
79612
|
-
version: "0.7.
|
|
79626
|
+
version: "0.7.6",
|
|
79613
79627
|
description: "Code and build agents with comprehensive multi-provider support",
|
|
79614
79628
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/fast-agent.svg",
|
|
79615
79629
|
distribution: {
|
|
79616
79630
|
uvx: {
|
|
79617
|
-
package: "fast-agent-acp==0.7.
|
|
79631
|
+
package: "fast-agent-acp==0.7.6",
|
|
79618
79632
|
args: [
|
|
79619
79633
|
"-x"
|
|
79620
79634
|
]
|
|
@@ -79639,12 +79653,12 @@ Task description:
|
|
|
79639
79653
|
{
|
|
79640
79654
|
id: "github-copilot-cli",
|
|
79641
79655
|
name: "GitHub Copilot",
|
|
79642
|
-
version: "1.0.
|
|
79656
|
+
version: "1.0.50",
|
|
79643
79657
|
description: "GitHub's AI pair programmer",
|
|
79644
79658
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/github-copilot-cli.svg",
|
|
79645
79659
|
distribution: {
|
|
79646
79660
|
npx: {
|
|
79647
|
-
package: "@github/copilot@1.0.
|
|
79661
|
+
package: "@github/copilot@1.0.50",
|
|
79648
79662
|
args: [
|
|
79649
79663
|
"--acp"
|
|
79650
79664
|
]
|
|
@@ -79654,19 +79668,19 @@ Task description:
|
|
|
79654
79668
|
{
|
|
79655
79669
|
id: "glm-acp-agent",
|
|
79656
79670
|
name: "GLM Agent",
|
|
79657
|
-
version: "1.1.
|
|
79671
|
+
version: "1.1.4",
|
|
79658
79672
|
description: "ACP agent powered by Zhipu AI's GLM Coding Plan models (glm-5.1, glm-5-turbo, glm-4.7, glm-4.5-air). Supports streaming, tool calls, mid-session model switching, image input via Z.AI Coding Plan Vision MCP, and session load/fork/resume with on-disk persistence.",
|
|
79659
79673
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/glm-acp-agent.svg",
|
|
79660
79674
|
distribution: {
|
|
79661
79675
|
npx: {
|
|
79662
|
-
package: "glm-acp-agent@1.1.
|
|
79676
|
+
package: "glm-acp-agent@1.1.4"
|
|
79663
79677
|
}
|
|
79664
79678
|
}
|
|
79665
79679
|
},
|
|
79666
79680
|
{
|
|
79667
79681
|
id: "goose",
|
|
79668
79682
|
name: "goose",
|
|
79669
|
-
version: "1.
|
|
79683
|
+
version: "1.34.1",
|
|
79670
79684
|
description: "A local, extensible, open source AI agent that automates engineering tasks",
|
|
79671
79685
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/goose.svg",
|
|
79672
79686
|
distribution: {
|
|
@@ -79702,12 +79716,12 @@ Task description:
|
|
|
79702
79716
|
{
|
|
79703
79717
|
id: "kilo",
|
|
79704
79718
|
name: "Kilo",
|
|
79705
|
-
version: "7.
|
|
79719
|
+
version: "7.3.0",
|
|
79706
79720
|
description: "The open source coding agent",
|
|
79707
79721
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/kilo.svg",
|
|
79708
79722
|
distribution: {
|
|
79709
79723
|
npx: {
|
|
79710
|
-
package: "@kilocode/cli@7.
|
|
79724
|
+
package: "@kilocode/cli@7.3.0",
|
|
79711
79725
|
args: [
|
|
79712
79726
|
"acp"
|
|
79713
79727
|
]
|
|
@@ -79717,7 +79731,7 @@ Task description:
|
|
|
79717
79731
|
{
|
|
79718
79732
|
id: "kimi",
|
|
79719
79733
|
name: "Kimi CLI",
|
|
79720
|
-
version: "1.
|
|
79734
|
+
version: "1.44.0",
|
|
79721
79735
|
description: "Moonshot AI's coding assistant",
|
|
79722
79736
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/kimi.svg",
|
|
79723
79737
|
distribution: {
|
|
@@ -79769,12 +79783,12 @@ Task description:
|
|
|
79769
79783
|
{
|
|
79770
79784
|
id: "nova",
|
|
79771
79785
|
name: "Nova",
|
|
79772
|
-
version: "1.1.
|
|
79786
|
+
version: "1.1.9",
|
|
79773
79787
|
description: "Nova by Compass AI - a fully-fledged software engineer at your command",
|
|
79774
79788
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/nova.svg",
|
|
79775
79789
|
distribution: {
|
|
79776
79790
|
npx: {
|
|
79777
|
-
package: "@compass-ai/nova@1.1.
|
|
79791
|
+
package: "@compass-ai/nova@1.1.9",
|
|
79778
79792
|
args: [
|
|
79779
79793
|
"acp"
|
|
79780
79794
|
]
|
|
@@ -79784,7 +79798,7 @@ Task description:
|
|
|
79784
79798
|
{
|
|
79785
79799
|
id: "opencode",
|
|
79786
79800
|
name: "OpenCode",
|
|
79787
|
-
version: "1.
|
|
79801
|
+
version: "1.15.5",
|
|
79788
79802
|
description: "The open source coding agent",
|
|
79789
79803
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/opencode.svg",
|
|
79790
79804
|
distribution: {
|
|
@@ -79802,24 +79816,24 @@ Task description:
|
|
|
79802
79816
|
{
|
|
79803
79817
|
id: "pi-acp",
|
|
79804
79818
|
name: "pi ACP",
|
|
79805
|
-
version: "0.0.
|
|
79819
|
+
version: "0.0.27",
|
|
79806
79820
|
description: "ACP adapter for pi coding agent",
|
|
79807
79821
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/pi-acp.svg",
|
|
79808
79822
|
distribution: {
|
|
79809
79823
|
npx: {
|
|
79810
|
-
package: "pi-acp@0.0.
|
|
79824
|
+
package: "pi-acp@0.0.27"
|
|
79811
79825
|
}
|
|
79812
79826
|
}
|
|
79813
79827
|
},
|
|
79814
79828
|
{
|
|
79815
79829
|
id: "qoder",
|
|
79816
79830
|
name: "Qoder CLI",
|
|
79817
|
-
version: "0.2.
|
|
79831
|
+
version: "0.2.14",
|
|
79818
79832
|
description: "AI coding assistant with agentic capabilities",
|
|
79819
79833
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/qoder.svg",
|
|
79820
79834
|
distribution: {
|
|
79821
79835
|
npx: {
|
|
79822
|
-
package: "@qoder-ai/qodercli@0.2.
|
|
79836
|
+
package: "@qoder-ai/qodercli@0.2.14",
|
|
79823
79837
|
args: [
|
|
79824
79838
|
"--acp"
|
|
79825
79839
|
]
|
|
@@ -79857,7 +79871,7 @@ Task description:
|
|
|
79857
79871
|
{
|
|
79858
79872
|
id: "stakpak",
|
|
79859
79873
|
name: "Stakpak",
|
|
79860
|
-
version: "0.3.
|
|
79874
|
+
version: "0.3.81",
|
|
79861
79875
|
description: "Open-source DevOps agent in Rust with enterprise-grade security",
|
|
79862
79876
|
icon: "https://cdn.agentclientprotocol.com/registry/v1/latest/stakpak.svg",
|
|
79863
79877
|
distribution: {
|
|
@@ -82155,6 +82169,68 @@ Task description:
|
|
|
82155
82169
|
}
|
|
82156
82170
|
return result;
|
|
82157
82171
|
};
|
|
82172
|
+
const parseCodexProposedPlanTags = (text, turnId) => {
|
|
82173
|
+
const planRegex = /(^|\r?\n)[ \t]*<proposed_plan>[ \t]*(?:\r?\n)((?:(?!<proposed_plan>)[\s\S])*?)(\r?\n)[ \t]*<\/proposed_plan>[ \t]*(?=\r?\n|$)/g;
|
|
82174
|
+
const result = [];
|
|
82175
|
+
let lastIndex = 0;
|
|
82176
|
+
let insertIndex;
|
|
82177
|
+
let markdown = "";
|
|
82178
|
+
let match5;
|
|
82179
|
+
while ((match5 = planRegex.exec(text)) !== null) {
|
|
82180
|
+
const leadingNewline = match5[1] ?? "";
|
|
82181
|
+
const textBeforeEnd = match5.index + leadingNewline.length;
|
|
82182
|
+
if (textBeforeEnd > lastIndex) {
|
|
82183
|
+
const textBefore = text.slice(lastIndex, textBeforeEnd);
|
|
82184
|
+
if (textBefore) {
|
|
82185
|
+
result.push({
|
|
82186
|
+
type: "text",
|
|
82187
|
+
text: textBefore
|
|
82188
|
+
});
|
|
82189
|
+
}
|
|
82190
|
+
}
|
|
82191
|
+
insertIndex ??= result.length;
|
|
82192
|
+
markdown += match5[2] ?? "";
|
|
82193
|
+
lastIndex = planRegex.lastIndex;
|
|
82194
|
+
}
|
|
82195
|
+
if (insertIndex === void 0) {
|
|
82196
|
+
return [
|
|
82197
|
+
{
|
|
82198
|
+
type: "text",
|
|
82199
|
+
text
|
|
82200
|
+
}
|
|
82201
|
+
];
|
|
82202
|
+
}
|
|
82203
|
+
if (lastIndex < text.length) {
|
|
82204
|
+
const textAfter = text.slice(lastIndex);
|
|
82205
|
+
if (textAfter) {
|
|
82206
|
+
result.push({
|
|
82207
|
+
type: "text",
|
|
82208
|
+
text: textAfter
|
|
82209
|
+
});
|
|
82210
|
+
}
|
|
82211
|
+
}
|
|
82212
|
+
if (markdown.trim()) {
|
|
82213
|
+
result.splice(insertIndex, 0, {
|
|
82214
|
+
type: "proposed_plan",
|
|
82215
|
+
turnId,
|
|
82216
|
+
markdown,
|
|
82217
|
+
status: "completed",
|
|
82218
|
+
isLatest: true
|
|
82219
|
+
});
|
|
82220
|
+
}
|
|
82221
|
+
return result;
|
|
82222
|
+
};
|
|
82223
|
+
const parseAssistantTextTags = (text, turnId) => {
|
|
82224
|
+
const withThoughts = parseClaudeCodeThinkingTags(text);
|
|
82225
|
+
return withThoughts.flatMap((item) => {
|
|
82226
|
+
if (item.type !== "text") {
|
|
82227
|
+
return [
|
|
82228
|
+
item
|
|
82229
|
+
];
|
|
82230
|
+
}
|
|
82231
|
+
return parseCodexProposedPlanTags(item.text, turnId);
|
|
82232
|
+
});
|
|
82233
|
+
};
|
|
82158
82234
|
const buildMessageContentFromNotification = (message) => {
|
|
82159
82235
|
const { update: update2 } = message;
|
|
82160
82236
|
switch (update2.sessionUpdate) {
|
|
@@ -82412,6 +82488,11 @@ Task description:
|
|
|
82412
82488
|
this.upsertSingletonItem(entryIndex, "available_commands", message);
|
|
82413
82489
|
return;
|
|
82414
82490
|
}
|
|
82491
|
+
case "proposed_plan": {
|
|
82492
|
+
const entryIndex = this.ensureActiveAssistantEntry();
|
|
82493
|
+
this.upsertProposedPlanItem(entryIndex, message);
|
|
82494
|
+
return;
|
|
82495
|
+
}
|
|
82415
82496
|
case "tool_call": {
|
|
82416
82497
|
const existingEntryIndex = this.resolveToolCallEntryIndex(message.toolCallId);
|
|
82417
82498
|
if (existingEntryIndex !== void 0) {
|
|
@@ -82471,6 +82552,20 @@ Task description:
|
|
|
82471
82552
|
entry2.items = compacted;
|
|
82472
82553
|
this.parsedItemsByEntryIndex[entryIndex] = compacted;
|
|
82473
82554
|
}
|
|
82555
|
+
upsertProposedPlanItem(entryIndex, next) {
|
|
82556
|
+
const entry2 = this.history[entryIndex];
|
|
82557
|
+
if (!entry2) return;
|
|
82558
|
+
const items2 = this.ensureEntryItems(entryIndex);
|
|
82559
|
+
const existingIndex = items2.findIndex((item) => item.type === "proposed_plan" && item.turnId === next.turnId);
|
|
82560
|
+
if (existingIndex >= 0) {
|
|
82561
|
+
items2[existingIndex] = next;
|
|
82562
|
+
return;
|
|
82563
|
+
}
|
|
82564
|
+
items2.push(next);
|
|
82565
|
+
const compacted = compactAdjacentTextAndThought(items2);
|
|
82566
|
+
entry2.items = compacted;
|
|
82567
|
+
this.parsedItemsByEntryIndex[entryIndex] = compacted;
|
|
82568
|
+
}
|
|
82474
82569
|
upsertToolCall(entryIndex, incoming) {
|
|
82475
82570
|
const entry2 = this.history[entryIndex];
|
|
82476
82571
|
if (!entry2) return;
|
|
@@ -82502,12 +82597,12 @@ Task description:
|
|
|
82502
82597
|
continue;
|
|
82503
82598
|
}
|
|
82504
82599
|
const text = item.text;
|
|
82505
|
-
if (!text.includes("<thinking>")) {
|
|
82600
|
+
if (!text.includes("<thinking>") && !text.includes("<proposed_plan>")) {
|
|
82506
82601
|
newItems.push(item);
|
|
82507
82602
|
continue;
|
|
82508
82603
|
}
|
|
82509
|
-
const parsed =
|
|
82510
|
-
if (parsed.length
|
|
82604
|
+
const parsed = parseAssistantTextTags(text, entry2.id);
|
|
82605
|
+
if (parsed.length !== 1 || parsed[0]?.type !== "text" || parsed[0]?.type === "text" && parsed[0].text !== text) {
|
|
82511
82606
|
newItems.push(...parsed);
|
|
82512
82607
|
modified = true;
|
|
82513
82608
|
} else {
|
|
@@ -82525,6 +82620,216 @@ Task description:
|
|
|
82525
82620
|
const applyNotificationOnHistory = (history, notifications, model, options = {}) => {
|
|
82526
82621
|
return new NotificationOnHistoryApplier(history, options, model).apply(notifications);
|
|
82527
82622
|
};
|
|
82623
|
+
const applyMessageContentsBatch = (history, messages, options = {}) => {
|
|
82624
|
+
if (messages.length === 0) {
|
|
82625
|
+
return history;
|
|
82626
|
+
}
|
|
82627
|
+
const createId = options.createId ?? defaultCreateId$1;
|
|
82628
|
+
const now2 = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
82629
|
+
const parseEntryItems = (entry2) => {
|
|
82630
|
+
const rawItems = entry2.items;
|
|
82631
|
+
return Array.isArray(rawItems) ? rawItems : [];
|
|
82632
|
+
};
|
|
82633
|
+
const writeEntryItems2 = (entry2, items2) => {
|
|
82634
|
+
return {
|
|
82635
|
+
...entry2,
|
|
82636
|
+
items: items2
|
|
82637
|
+
};
|
|
82638
|
+
};
|
|
82639
|
+
const createAssistantEntryState = () => ({
|
|
82640
|
+
entry: {
|
|
82641
|
+
id: options.targetAssistantEntryId ?? createId(),
|
|
82642
|
+
role: "assistant",
|
|
82643
|
+
items: [],
|
|
82644
|
+
timestamp: now2(),
|
|
82645
|
+
userId: void 0,
|
|
82646
|
+
read: void 0,
|
|
82647
|
+
fileDiff: []
|
|
82648
|
+
},
|
|
82649
|
+
items: [],
|
|
82650
|
+
dirty: true
|
|
82651
|
+
});
|
|
82652
|
+
const entryStates = history.map((entry2) => {
|
|
82653
|
+
return {
|
|
82654
|
+
entry: entry2,
|
|
82655
|
+
items: parseEntryItems(entry2),
|
|
82656
|
+
dirty: false
|
|
82657
|
+
};
|
|
82658
|
+
});
|
|
82659
|
+
const ensureActiveAssistantEntry = () => {
|
|
82660
|
+
if (options.targetAssistantEntryId) {
|
|
82661
|
+
const targetIndex = entryStates.findIndex((state2) => state2.entry.role === "assistant" && state2.entry.id === options.targetAssistantEntryId);
|
|
82662
|
+
if (targetIndex >= 0) {
|
|
82663
|
+
return targetIndex;
|
|
82664
|
+
}
|
|
82665
|
+
entryStates.push(createAssistantEntryState());
|
|
82666
|
+
return entryStates.length - 1;
|
|
82667
|
+
}
|
|
82668
|
+
const lastIndex = entryStates.length - 1;
|
|
82669
|
+
const last2 = lastIndex >= 0 ? entryStates[lastIndex] : void 0;
|
|
82670
|
+
if (last2 && last2.entry.role === "assistant") {
|
|
82671
|
+
return lastIndex;
|
|
82672
|
+
}
|
|
82673
|
+
entryStates.push(createAssistantEntryState());
|
|
82674
|
+
return entryStates.length - 1;
|
|
82675
|
+
};
|
|
82676
|
+
const appendOrMergeAdjacentText = (entryIndex, kind, delta) => {
|
|
82677
|
+
if (!delta) return;
|
|
82678
|
+
const state2 = entryStates[entryIndex];
|
|
82679
|
+
if (!state2) return;
|
|
82680
|
+
const last2 = state2.items[state2.items.length - 1];
|
|
82681
|
+
if (last2 && last2.type === kind) {
|
|
82682
|
+
const existing = last2;
|
|
82683
|
+
const text = sanitizeLodyInternalInstructions(mergeStreamChunk(existing.text, delta));
|
|
82684
|
+
if (text) {
|
|
82685
|
+
state2.items[state2.items.length - 1] = {
|
|
82686
|
+
...existing,
|
|
82687
|
+
text
|
|
82688
|
+
};
|
|
82689
|
+
} else {
|
|
82690
|
+
state2.items.pop();
|
|
82691
|
+
}
|
|
82692
|
+
} else {
|
|
82693
|
+
state2.items.push({
|
|
82694
|
+
type: kind,
|
|
82695
|
+
text: delta
|
|
82696
|
+
});
|
|
82697
|
+
}
|
|
82698
|
+
state2.dirty = true;
|
|
82699
|
+
};
|
|
82700
|
+
const upsertSingletonItem = (entryIndex, type2, next) => {
|
|
82701
|
+
const state2 = entryStates[entryIndex];
|
|
82702
|
+
if (!state2) return;
|
|
82703
|
+
const last2 = state2.items[state2.items.length - 1];
|
|
82704
|
+
if (last2 && last2.type === type2) {
|
|
82705
|
+
state2.items[state2.items.length - 1] = next;
|
|
82706
|
+
state2.dirty = true;
|
|
82707
|
+
return;
|
|
82708
|
+
}
|
|
82709
|
+
const withoutType = state2.items.filter((m) => m.type !== type2);
|
|
82710
|
+
withoutType.push(next);
|
|
82711
|
+
state2.items = compactAdjacentTextAndThought(withoutType);
|
|
82712
|
+
state2.dirty = true;
|
|
82713
|
+
};
|
|
82714
|
+
const upsertProposedPlanItem = (entryIndex, next) => {
|
|
82715
|
+
const state2 = entryStates[entryIndex];
|
|
82716
|
+
if (!state2) return;
|
|
82717
|
+
const existingIndex = state2.items.findIndex((item) => item.type === "proposed_plan" && item.turnId === next.turnId);
|
|
82718
|
+
if (existingIndex >= 0) {
|
|
82719
|
+
state2.items[existingIndex] = next;
|
|
82720
|
+
state2.dirty = true;
|
|
82721
|
+
return;
|
|
82722
|
+
}
|
|
82723
|
+
state2.items.push(next);
|
|
82724
|
+
state2.items = compactAdjacentTextAndThought(state2.items);
|
|
82725
|
+
state2.dirty = true;
|
|
82726
|
+
};
|
|
82727
|
+
const upsertToolCall = (entryIndex, incoming) => {
|
|
82728
|
+
const state2 = entryStates[entryIndex];
|
|
82729
|
+
if (!state2) return;
|
|
82730
|
+
const toolIndex = state2.items.findIndex((m) => m.type === "tool_call" && m.toolCallId === incoming.toolCallId);
|
|
82731
|
+
if (toolIndex >= 0) {
|
|
82732
|
+
const prevTool = state2.items[toolIndex];
|
|
82733
|
+
state2.items[toolIndex] = mergeToolCallMessage(prevTool, incoming);
|
|
82734
|
+
} else {
|
|
82735
|
+
state2.items.push({
|
|
82736
|
+
...incoming,
|
|
82737
|
+
status: incoming.status || "pending",
|
|
82738
|
+
content: incoming.content ? compactToolCallContentForHistory(incoming.content, {
|
|
82739
|
+
kind: incoming.kind ?? void 0
|
|
82740
|
+
}) : void 0
|
|
82741
|
+
});
|
|
82742
|
+
}
|
|
82743
|
+
state2.dirty = true;
|
|
82744
|
+
};
|
|
82745
|
+
const toolCallEntryIndexById = /* @__PURE__ */ new Map();
|
|
82746
|
+
for (let i2 = 0; i2 < entryStates.length; i2++) {
|
|
82747
|
+
const state2 = entryStates[i2];
|
|
82748
|
+
if (!state2) continue;
|
|
82749
|
+
for (const content of state2.items) {
|
|
82750
|
+
if (content.type === "tool_call") {
|
|
82751
|
+
toolCallEntryIndexById.set(content.toolCallId, i2);
|
|
82752
|
+
}
|
|
82753
|
+
}
|
|
82754
|
+
}
|
|
82755
|
+
for (const message of messages) {
|
|
82756
|
+
switch (message.type) {
|
|
82757
|
+
case "text": {
|
|
82758
|
+
const text = sanitizeLodyInternalInstructions(message.text);
|
|
82759
|
+
if (!text) break;
|
|
82760
|
+
const entryIndex = ensureActiveAssistantEntry();
|
|
82761
|
+
appendOrMergeAdjacentText(entryIndex, "text", text);
|
|
82762
|
+
break;
|
|
82763
|
+
}
|
|
82764
|
+
case "thought": {
|
|
82765
|
+
const text = sanitizeLodyInternalInstructions(message.text);
|
|
82766
|
+
if (!text) break;
|
|
82767
|
+
const entryIndex = ensureActiveAssistantEntry();
|
|
82768
|
+
appendOrMergeAdjacentText(entryIndex, "thought", text);
|
|
82769
|
+
break;
|
|
82770
|
+
}
|
|
82771
|
+
case "plan": {
|
|
82772
|
+
const entryIndex = ensureActiveAssistantEntry();
|
|
82773
|
+
const state2 = entryStates[entryIndex];
|
|
82774
|
+
if (state2) {
|
|
82775
|
+
state2.entry.plan = message.entries;
|
|
82776
|
+
state2.dirty = true;
|
|
82777
|
+
}
|
|
82778
|
+
break;
|
|
82779
|
+
}
|
|
82780
|
+
case "available_commands": {
|
|
82781
|
+
const entryIndex = ensureActiveAssistantEntry();
|
|
82782
|
+
upsertSingletonItem(entryIndex, "available_commands", message);
|
|
82783
|
+
break;
|
|
82784
|
+
}
|
|
82785
|
+
case "proposed_plan": {
|
|
82786
|
+
const entryIndex = ensureActiveAssistantEntry();
|
|
82787
|
+
upsertProposedPlanItem(entryIndex, message);
|
|
82788
|
+
break;
|
|
82789
|
+
}
|
|
82790
|
+
case "tool_call": {
|
|
82791
|
+
const existingEntryIndex = toolCallEntryIndexById.get(message.toolCallId);
|
|
82792
|
+
if (existingEntryIndex !== void 0) {
|
|
82793
|
+
upsertToolCall(existingEntryIndex, message);
|
|
82794
|
+
} else {
|
|
82795
|
+
const entryIndex = ensureActiveAssistantEntry();
|
|
82796
|
+
upsertToolCall(entryIndex, message);
|
|
82797
|
+
toolCallEntryIndexById.set(message.toolCallId, entryIndex);
|
|
82798
|
+
}
|
|
82799
|
+
break;
|
|
82800
|
+
}
|
|
82801
|
+
}
|
|
82802
|
+
}
|
|
82803
|
+
for (const state2 of entryStates) {
|
|
82804
|
+
if (!state2.dirty || state2.entry.role !== "assistant") continue;
|
|
82805
|
+
let modified = false;
|
|
82806
|
+
const newItems = [];
|
|
82807
|
+
for (const item of state2.items) {
|
|
82808
|
+
if (item.type !== "text") {
|
|
82809
|
+
newItems.push(item);
|
|
82810
|
+
continue;
|
|
82811
|
+
}
|
|
82812
|
+
if (!item.text.includes("<thinking>") && !item.text.includes("<proposed_plan>")) {
|
|
82813
|
+
newItems.push(item);
|
|
82814
|
+
continue;
|
|
82815
|
+
}
|
|
82816
|
+
const parsed = parseAssistantTextTags(item.text, state2.entry.id);
|
|
82817
|
+
if (parsed.length !== 1 || parsed[0]?.type !== "text" || parsed[0]?.type === "text" && parsed[0].text !== item.text) {
|
|
82818
|
+
newItems.push(...parsed);
|
|
82819
|
+
modified = true;
|
|
82820
|
+
} else {
|
|
82821
|
+
newItems.push(item);
|
|
82822
|
+
}
|
|
82823
|
+
}
|
|
82824
|
+
if (modified) {
|
|
82825
|
+
state2.items = compactAdjacentTextAndThought(newItems);
|
|
82826
|
+
}
|
|
82827
|
+
}
|
|
82828
|
+
return entryStates.map((state2) => {
|
|
82829
|
+
if (!state2.dirty) return state2.entry;
|
|
82830
|
+
return writeEntryItems2(state2.entry, state2.items);
|
|
82831
|
+
});
|
|
82832
|
+
};
|
|
82528
82833
|
const defaultNow = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
82529
82834
|
const defaultCreateId = () => {
|
|
82530
82835
|
const maybeCrypto = globalThis.crypto;
|
|
@@ -82647,14 +82952,29 @@ Task description:
|
|
|
82647
82952
|
};
|
|
82648
82953
|
}
|
|
82649
82954
|
const isRecord$4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
82955
|
+
const getBooleanField = (value, camelCaseKey, snakeCaseKey) => value[camelCaseKey] === true || value[snakeCaseKey] === true;
|
|
82650
82956
|
const getClaudeCodeMeta = (meta) => {
|
|
82651
82957
|
if (!isRecord$4(meta)) return null;
|
|
82652
82958
|
const claudeCode = meta.claudeCode;
|
|
82653
82959
|
return isRecord$4(claudeCode) ? claudeCode : null;
|
|
82654
82960
|
};
|
|
82961
|
+
const getCodexMeta = (meta) => {
|
|
82962
|
+
if (!isRecord$4(meta)) return null;
|
|
82963
|
+
const codex = meta.codex;
|
|
82964
|
+
return isRecord$4(codex) ? codex : null;
|
|
82965
|
+
};
|
|
82655
82966
|
function parseAskUserQuestionPermissionMeta(meta) {
|
|
82656
82967
|
const claudeCode = getClaudeCodeMeta(meta);
|
|
82657
|
-
if (
|
|
82968
|
+
if (claudeCode) {
|
|
82969
|
+
return parseClaudeAskUserQuestionPermissionMeta(claudeCode);
|
|
82970
|
+
}
|
|
82971
|
+
const codex = getCodexMeta(meta);
|
|
82972
|
+
if (codex) {
|
|
82973
|
+
return parseCodexRequestUserInputPermissionMeta(codex);
|
|
82974
|
+
}
|
|
82975
|
+
return null;
|
|
82976
|
+
}
|
|
82977
|
+
function parseClaudeAskUserQuestionPermissionMeta(claudeCode) {
|
|
82658
82978
|
const raw = claudeCode.askUserQuestion;
|
|
82659
82979
|
if (!isRecord$4(raw)) return null;
|
|
82660
82980
|
const rawQuestions = raw.questions;
|
|
@@ -82687,11 +83007,55 @@ Task description:
|
|
|
82687
83007
|
});
|
|
82688
83008
|
}
|
|
82689
83009
|
return {
|
|
83010
|
+
source: "claude",
|
|
82690
83011
|
version: typeof raw.version === "number" && Number.isFinite(raw.version) ? raw.version : 1,
|
|
82691
83012
|
allowCustomAnswer: raw.allowCustomAnswer === true,
|
|
82692
83013
|
questions
|
|
82693
83014
|
};
|
|
82694
83015
|
}
|
|
83016
|
+
function parseCodexRequestUserInputPermissionMeta(codex) {
|
|
83017
|
+
const raw = codex.requestUserInput;
|
|
83018
|
+
if (!isRecord$4(raw)) return null;
|
|
83019
|
+
const rawQuestions = raw.questions;
|
|
83020
|
+
if (!Array.isArray(rawQuestions) || rawQuestions.length === 0) return null;
|
|
83021
|
+
const questions = [];
|
|
83022
|
+
for (const rawQuestion of rawQuestions) {
|
|
83023
|
+
if (!isRecord$4(rawQuestion)) return null;
|
|
83024
|
+
if (typeof rawQuestion.id !== "string") return null;
|
|
83025
|
+
if (typeof rawQuestion.question !== "string") return null;
|
|
83026
|
+
if (typeof rawQuestion.header !== "string") return null;
|
|
83027
|
+
const rawOptions = rawQuestion.options;
|
|
83028
|
+
const options = [];
|
|
83029
|
+
if (rawOptions !== void 0) {
|
|
83030
|
+
if (!Array.isArray(rawOptions)) return null;
|
|
83031
|
+
for (const rawOption of rawOptions) {
|
|
83032
|
+
if (!isRecord$4(rawOption)) return null;
|
|
83033
|
+
if (typeof rawOption.label !== "string") return null;
|
|
83034
|
+
options.push({
|
|
83035
|
+
label: rawOption.label,
|
|
83036
|
+
...typeof rawOption.description === "string" ? {
|
|
83037
|
+
description: rawOption.description
|
|
83038
|
+
} : {}
|
|
83039
|
+
});
|
|
83040
|
+
}
|
|
83041
|
+
}
|
|
83042
|
+
questions.push({
|
|
83043
|
+
id: rawQuestion.id,
|
|
83044
|
+
question: rawQuestion.question,
|
|
83045
|
+
header: rawQuestion.header,
|
|
83046
|
+
options,
|
|
83047
|
+
multiSelect: false,
|
|
83048
|
+
allowCustomAnswer: getBooleanField(rawQuestion, "isOther", "is_other"),
|
|
83049
|
+
isSecret: getBooleanField(rawQuestion, "isSecret", "is_secret")
|
|
83050
|
+
});
|
|
83051
|
+
}
|
|
83052
|
+
return {
|
|
83053
|
+
source: "codex",
|
|
83054
|
+
version: 1,
|
|
83055
|
+
allowCustomAnswer: questions.some((question) => question.allowCustomAnswer === true),
|
|
83056
|
+
questions
|
|
83057
|
+
};
|
|
83058
|
+
}
|
|
82695
83059
|
function isAskUserQuestionPermissionMeta(meta) {
|
|
82696
83060
|
return parseAskUserQuestionPermissionMeta(meta) !== null;
|
|
82697
83061
|
}
|
|
@@ -85425,6 +85789,26 @@ ${tailedOutput}` : null;
|
|
|
85425
85789
|
};
|
|
85426
85790
|
const isPreviewTunnelCreateResponse = (value) => isRecord$3(value) && isString$2(value.tunnelId) && isString$2(value.publicUrl) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number" && (value.resourceLimits === void 0 || isPreviewResourceLimits(value.resourceLimits));
|
|
85427
85791
|
const isPreviewTunnelRefreshResponse = (value) => isRecord$3(value) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number";
|
|
85792
|
+
class InFlightDedupe {
|
|
85793
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
85794
|
+
async run(key2, factory) {
|
|
85795
|
+
const existing = this.inFlight.get(key2);
|
|
85796
|
+
if (existing) {
|
|
85797
|
+
return await existing;
|
|
85798
|
+
}
|
|
85799
|
+
let wrapped;
|
|
85800
|
+
wrapped = factory().finally(() => {
|
|
85801
|
+
if (this.inFlight.get(key2) === wrapped) {
|
|
85802
|
+
this.inFlight.delete(key2);
|
|
85803
|
+
}
|
|
85804
|
+
});
|
|
85805
|
+
this.inFlight.set(key2, wrapped);
|
|
85806
|
+
return await wrapped;
|
|
85807
|
+
}
|
|
85808
|
+
size() {
|
|
85809
|
+
return this.inFlight.size;
|
|
85810
|
+
}
|
|
85811
|
+
}
|
|
85428
85812
|
const LOCAL_PROBE_PORT$1 = 17789;
|
|
85429
85813
|
const LOCAL_SESSION_CONTROL_PORT = 17790;
|
|
85430
85814
|
const IMAGE_UPLOAD_PATH = "/image-upload";
|
|
@@ -92876,18 +93260,18 @@ ${val.stack}`;
|
|
|
92876
93260
|
};
|
|
92877
93261
|
}
|
|
92878
93262
|
function decodeMultipartMixed$1(boundary, data) {
|
|
92879
|
-
const
|
|
93263
|
+
const delimiter2 = new TextEncoder().encode(`--${boundary}`);
|
|
92880
93264
|
const closeDelimiter = new TextEncoder().encode(`--${boundary}--`);
|
|
92881
93265
|
const crlfCrlf = new TextEncoder().encode("\r\n\r\n");
|
|
92882
93266
|
const parts2 = [];
|
|
92883
93267
|
let pos = 0;
|
|
92884
|
-
const firstDelimPos = indexOf$1(data,
|
|
93268
|
+
const firstDelimPos = indexOf$1(data, delimiter2, pos);
|
|
92885
93269
|
if (firstDelimPos < 0) return parts2;
|
|
92886
|
-
pos = firstDelimPos +
|
|
93270
|
+
pos = firstDelimPos + delimiter2.byteLength;
|
|
92887
93271
|
if (pos < data.byteLength && data[pos] === 13) pos += 1;
|
|
92888
93272
|
if (pos < data.byteLength && data[pos] === 10) pos += 1;
|
|
92889
93273
|
while (pos < data.byteLength) {
|
|
92890
|
-
if (startsWith$1(data.subarray(pos), closeDelimiter.subarray(
|
|
93274
|
+
if (startsWith$1(data.subarray(pos), closeDelimiter.subarray(delimiter2.byteLength))) break;
|
|
92891
93275
|
const headerEnd = indexOf$1(data, crlfCrlf, pos);
|
|
92892
93276
|
if (headerEnd < 0) break;
|
|
92893
93277
|
const headerBytes = data.subarray(pos, headerEnd);
|
|
@@ -92900,7 +93284,7 @@ ${val.stack}`;
|
|
|
92900
93284
|
contentType = line3.slice(colon + 1).trim();
|
|
92901
93285
|
}
|
|
92902
93286
|
const bodyStart = headerEnd + crlfCrlf.byteLength;
|
|
92903
|
-
const nextDelimiter = indexOf$1(data,
|
|
93287
|
+
const nextDelimiter = indexOf$1(data, delimiter2, bodyStart);
|
|
92904
93288
|
if (nextDelimiter < 0) {
|
|
92905
93289
|
parts2.push({
|
|
92906
93290
|
contentType,
|
|
@@ -92914,7 +93298,7 @@ ${val.stack}`;
|
|
|
92914
93298
|
contentType,
|
|
92915
93299
|
body: data.subarray(bodyStart, bodyEnd)
|
|
92916
93300
|
});
|
|
92917
|
-
pos = nextDelimiter +
|
|
93301
|
+
pos = nextDelimiter + delimiter2.byteLength;
|
|
92918
93302
|
if (pos + 1 < data.byteLength && data[pos] === 45 && data[pos + 1] === 45) break;
|
|
92919
93303
|
if (pos < data.byteLength && data[pos] === 13) pos += 1;
|
|
92920
93304
|
if (pos < data.byteLength && data[pos] === 10) pos += 1;
|
|
@@ -111655,14 +112039,14 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
111655
112039
|
const split2 = text.split(new RegExp(`\\s*${escape$1(delim)}\\s*`));
|
|
111656
112040
|
return split2;
|
|
111657
112041
|
};
|
|
111658
|
-
const parsePrimitive = (text, path2, primitive,
|
|
112042
|
+
const parsePrimitive = (text, path2, primitive, delimiter2, split2) => {
|
|
111659
112043
|
if (!split2) {
|
|
111660
112044
|
return pipe$1(primitive.parse(text), mapBoth({
|
|
111661
112045
|
onFailure: prefixed(path2),
|
|
111662
112046
|
onSuccess: of$3
|
|
111663
112047
|
}));
|
|
111664
112048
|
}
|
|
111665
|
-
return pipe$1(splitPathString(text,
|
|
112049
|
+
return pipe$1(splitPathString(text, delimiter2), forEachSequential((char) => primitive.parse(char.trim())), mapError(prefixed(path2)));
|
|
111666
112050
|
};
|
|
111667
112051
|
const transpose = (array2) => {
|
|
111668
112052
|
return Object.keys(array2[0]).map((column) => array2.map((row) => row[column]));
|
|
@@ -118481,18 +118865,18 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
118481
118865
|
};
|
|
118482
118866
|
}
|
|
118483
118867
|
function decodeMultipartMixed(boundary, data) {
|
|
118484
|
-
const
|
|
118868
|
+
const delimiter2 = new TextEncoder().encode(`--${boundary}`);
|
|
118485
118869
|
const closeDelimiter = new TextEncoder().encode(`--${boundary}--`);
|
|
118486
118870
|
const crlfCrlf = new TextEncoder().encode("\r\n\r\n");
|
|
118487
118871
|
const parts2 = [];
|
|
118488
118872
|
let pos = 0;
|
|
118489
|
-
const firstDelimPos = indexOf(data,
|
|
118873
|
+
const firstDelimPos = indexOf(data, delimiter2, pos);
|
|
118490
118874
|
if (firstDelimPos < 0) return parts2;
|
|
118491
|
-
pos = firstDelimPos +
|
|
118875
|
+
pos = firstDelimPos + delimiter2.byteLength;
|
|
118492
118876
|
if (pos < data.byteLength && data[pos] === 13) pos += 1;
|
|
118493
118877
|
if (pos < data.byteLength && data[pos] === 10) pos += 1;
|
|
118494
118878
|
while (pos < data.byteLength) {
|
|
118495
|
-
if (startsWith(data.subarray(pos), closeDelimiter.subarray(
|
|
118879
|
+
if (startsWith(data.subarray(pos), closeDelimiter.subarray(delimiter2.byteLength))) break;
|
|
118496
118880
|
const headerEnd = indexOf(data, crlfCrlf, pos);
|
|
118497
118881
|
if (headerEnd < 0) break;
|
|
118498
118882
|
const headerBytes = data.subarray(pos, headerEnd);
|
|
@@ -118505,7 +118889,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
118505
118889
|
contentType = line3.slice(colon + 1).trim();
|
|
118506
118890
|
}
|
|
118507
118891
|
const bodyStart = headerEnd + crlfCrlf.byteLength;
|
|
118508
|
-
const nextDelimiter = indexOf(data,
|
|
118892
|
+
const nextDelimiter = indexOf(data, delimiter2, bodyStart);
|
|
118509
118893
|
if (nextDelimiter < 0) {
|
|
118510
118894
|
parts2.push({
|
|
118511
118895
|
contentType,
|
|
@@ -118519,7 +118903,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
118519
118903
|
contentType,
|
|
118520
118904
|
body: data.subarray(bodyStart, bodyEnd)
|
|
118521
118905
|
});
|
|
118522
|
-
pos = nextDelimiter +
|
|
118906
|
+
pos = nextDelimiter + delimiter2.byteLength;
|
|
118523
118907
|
if (pos + 1 < data.byteLength && data[pos] === 45 && data[pos + 1] === 45) break;
|
|
118524
118908
|
if (pos < data.byteLength && data[pos] === 13) pos += 1;
|
|
118525
118909
|
if (pos < data.byteLength && data[pos] === 10) pos += 1;
|
|
@@ -119728,6 +120112,11 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
119728
120112
|
const JSON_RPC_VERSION$1 = "2.0";
|
|
119729
120113
|
const LORO_STREAMS_RPC_VERSION = "1";
|
|
119730
120114
|
const LORO_STREAMS_RPC_RETENTION_SECONDS = 86400;
|
|
120115
|
+
const LORO_STREAMS_RPC_ERROR_CODES = {
|
|
120116
|
+
rpcVersionMismatch: "rpc_version_mismatch",
|
|
120117
|
+
methodUnavailable: "method_unavailable",
|
|
120118
|
+
internalError: "internal_error"
|
|
120119
|
+
};
|
|
119731
120120
|
const LORO_RPC_REQUEST_STREAM_SEGMENT = "rpc:req";
|
|
119732
120121
|
const getLoroMachineRpcRequestStreamId = (workspaceId, machineId) => `${workspaceId}:${LORO_RPC_REQUEST_STREAM_SEGMENT}:${machineId}`;
|
|
119733
120122
|
const normalizeLoroGatewayBaseUrl = (baseUrl) => {
|
|
@@ -119758,8 +120147,8 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
119758
120147
|
machineId: string$2().trim().min(1),
|
|
119759
120148
|
workspaceId: string$2().trim().min(1),
|
|
119760
120149
|
replyTo: string$2().trim().min(1),
|
|
119761
|
-
sentAt: number$3().
|
|
119762
|
-
expiresAt: number$3().
|
|
120150
|
+
sentAt: number$3().finite().nonnegative(),
|
|
120151
|
+
expiresAt: number$3().finite().positive()
|
|
119763
120152
|
}).strict();
|
|
119764
120153
|
const LoroMachineStatusRpcRequestSchema = BaseRpcRequestSchema.extend({
|
|
119765
120154
|
method: literal("machine/status"),
|
|
@@ -120052,19 +120441,11 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120052
120441
|
while (!this.stopped) {
|
|
120053
120442
|
try {
|
|
120054
120443
|
await (this.deps.streamClient.readJsonLive?.(this.requestStreamId, this.requestState, async (batch) => {
|
|
120055
|
-
this.
|
|
120056
|
-
this.requestState.cursor = batch.cursor;
|
|
120057
|
-
for (const raw of batch.messages) {
|
|
120058
|
-
await this.handleRawRequest(raw);
|
|
120059
|
-
}
|
|
120444
|
+
await this.handleRequestBatch(batch);
|
|
120060
120445
|
}, {
|
|
120061
120446
|
signal: this.stopController.signal
|
|
120062
120447
|
}) ?? readJsonLiveViaLongPollFallback(this.deps.streamClient, this.requestStreamId, this.requestState, async (batch) => {
|
|
120063
|
-
this.
|
|
120064
|
-
this.requestState.cursor = batch.cursor;
|
|
120065
|
-
for (const raw of batch.messages) {
|
|
120066
|
-
await this.handleRawRequest(raw);
|
|
120067
|
-
}
|
|
120448
|
+
await this.handleRequestBatch(batch);
|
|
120068
120449
|
}, {
|
|
120069
120450
|
signal: this.stopController.signal
|
|
120070
120451
|
}));
|
|
@@ -120098,6 +120479,13 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120098
120479
|
}
|
|
120099
120480
|
}
|
|
120100
120481
|
}
|
|
120482
|
+
async handleRequestBatch(batch) {
|
|
120483
|
+
this.requestState.nextOffset = batch.nextOffset ?? this.requestState.nextOffset;
|
|
120484
|
+
this.requestState.cursor = batch.cursor;
|
|
120485
|
+
for (const raw of batch.messages) {
|
|
120486
|
+
await this.handleRawRequest(raw);
|
|
120487
|
+
}
|
|
120488
|
+
}
|
|
120101
120489
|
async handleRawRequest(raw) {
|
|
120102
120490
|
const parsed = LoroStreamsRpcRequestSchema.safeParse(raw);
|
|
120103
120491
|
if (!parsed.success) {
|
|
@@ -120114,7 +120502,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120114
120502
|
}
|
|
120115
120503
|
if (request.rpcVersion !== (this.deps.rpcVersion ?? LORO_STREAMS_RPC_VERSION)) {
|
|
120116
120504
|
await this.appendErrorResponse(request.replyTo, request.id, request.method, {
|
|
120117
|
-
code:
|
|
120505
|
+
code: LORO_STREAMS_RPC_ERROR_CODES.rpcVersionMismatch,
|
|
120118
120506
|
message: `Expected rpcVersion=${this.deps.rpcVersion ?? LORO_STREAMS_RPC_VERSION}, got ${request.rpcVersion}`
|
|
120119
120507
|
});
|
|
120120
120508
|
return;
|
|
@@ -120138,7 +120526,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120138
120526
|
case "session/preview-create": {
|
|
120139
120527
|
if (!this.deps.createSessionPreview) {
|
|
120140
120528
|
await this.appendErrorResponse(request.replyTo, request.id, request.method, {
|
|
120141
|
-
code:
|
|
120529
|
+
code: LORO_STREAMS_RPC_ERROR_CODES.methodUnavailable,
|
|
120142
120530
|
message: "Session preview creation is not available on this machine."
|
|
120143
120531
|
});
|
|
120144
120532
|
return;
|
|
@@ -120154,7 +120542,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120154
120542
|
case "session/preview-revoke": {
|
|
120155
120543
|
if (!this.deps.revokeSessionPreview) {
|
|
120156
120544
|
await this.appendErrorResponse(request.replyTo, request.id, request.method, {
|
|
120157
|
-
code:
|
|
120545
|
+
code: LORO_STREAMS_RPC_ERROR_CODES.methodUnavailable,
|
|
120158
120546
|
message: "Session preview revocation is not available on this machine."
|
|
120159
120547
|
});
|
|
120160
120548
|
return;
|
|
@@ -120170,7 +120558,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120170
120558
|
case "local-project/git-state": {
|
|
120171
120559
|
if (!this.deps.getLocalProjectGitState) {
|
|
120172
120560
|
await this.appendErrorResponse(request.replyTo, request.id, request.method, {
|
|
120173
|
-
code:
|
|
120561
|
+
code: LORO_STREAMS_RPC_ERROR_CODES.methodUnavailable,
|
|
120174
120562
|
message: "Local project Git state is not available on this machine."
|
|
120175
120563
|
});
|
|
120176
120564
|
return;
|
|
@@ -120185,7 +120573,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120185
120573
|
case "local-project/control": {
|
|
120186
120574
|
if (!this.deps.dispatchLocalProjectControl) {
|
|
120187
120575
|
await this.appendErrorResponse(request.replyTo, request.id, request.method, {
|
|
120188
|
-
code:
|
|
120576
|
+
code: LORO_STREAMS_RPC_ERROR_CODES.methodUnavailable,
|
|
120189
120577
|
message: "Local project control is not available on this machine."
|
|
120190
120578
|
});
|
|
120191
120579
|
return;
|
|
@@ -120198,7 +120586,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120198
120586
|
} catch (error2) {
|
|
120199
120587
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
120200
120588
|
await this.appendErrorResponse(request.replyTo, request.id, request.method, {
|
|
120201
|
-
code:
|
|
120589
|
+
code: LORO_STREAMS_RPC_ERROR_CODES.internalError,
|
|
120202
120590
|
message
|
|
120203
120591
|
});
|
|
120204
120592
|
}
|
|
@@ -120255,6 +120643,8 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120255
120643
|
return raw;
|
|
120256
120644
|
}
|
|
120257
120645
|
};
|
|
120646
|
+
const DEFAULT_GIT_COMMAND_TIMEOUT_MS = 5e3;
|
|
120647
|
+
const GIT_CHECKOUT_TIMEOUT_MS = 3e4;
|
|
120258
120648
|
function tryRealpath(inputPath) {
|
|
120259
120649
|
try {
|
|
120260
120650
|
if (typeof fs$6.realpathSync.native === "function") {
|
|
@@ -120297,7 +120687,8 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120297
120687
|
const hash2 = createHash("sha256").update(normalizedRootPath).digest("hex").slice(0, 24);
|
|
120298
120688
|
return `local-project-${hash2}`;
|
|
120299
120689
|
}
|
|
120300
|
-
function runGitCommand$1(rootPath, args2) {
|
|
120690
|
+
function runGitCommand$1(rootPath, args2, options = {}) {
|
|
120691
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_GIT_COMMAND_TIMEOUT_MS;
|
|
120301
120692
|
try {
|
|
120302
120693
|
const result = spawn.sync("git", args2, {
|
|
120303
120694
|
cwd: rootPath,
|
|
@@ -120306,13 +120697,30 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120306
120697
|
"ignore",
|
|
120307
120698
|
"pipe",
|
|
120308
120699
|
"pipe"
|
|
120309
|
-
]
|
|
120700
|
+
],
|
|
120701
|
+
timeout: timeoutMs,
|
|
120702
|
+
killSignal: "SIGTERM",
|
|
120703
|
+
env: {
|
|
120704
|
+
...process.env,
|
|
120705
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
120706
|
+
GIT_OPTIONAL_LOCKS: "0"
|
|
120707
|
+
}
|
|
120310
120708
|
});
|
|
120311
|
-
|
|
120709
|
+
if (result.error) {
|
|
120710
|
+
const message = result.error.message || `Git command timed out after ${timeoutMs}ms: git ${args2.join(" ")}`;
|
|
120711
|
+
const commandResult2 = {
|
|
120712
|
+
status: null,
|
|
120713
|
+
stdout: String(result.stdout ?? ""),
|
|
120714
|
+
stderr: message
|
|
120715
|
+
};
|
|
120716
|
+
return commandResult2;
|
|
120717
|
+
}
|
|
120718
|
+
const commandResult = {
|
|
120312
120719
|
status: result.status ?? null,
|
|
120313
120720
|
stdout: String(result.stdout ?? ""),
|
|
120314
120721
|
stderr: String(result.stderr ?? "")
|
|
120315
120722
|
};
|
|
120723
|
+
return commandResult;
|
|
120316
120724
|
} catch (error2) {
|
|
120317
120725
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
120318
120726
|
return {
|
|
@@ -120523,7 +120931,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120523
120931
|
const statusResult = runGitCommand$1(rootPath, [
|
|
120524
120932
|
"status",
|
|
120525
120933
|
"--porcelain=v1",
|
|
120526
|
-
"--untracked-files=
|
|
120934
|
+
"--untracked-files=normal"
|
|
120527
120935
|
]);
|
|
120528
120936
|
if (statusResult.status !== 0) {
|
|
120529
120937
|
const reason = statusResult.stderr.trim() || statusResult.stdout.trim() || "unknown error";
|
|
@@ -120604,7 +121012,9 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
120604
121012
|
const checkoutResult = runGitCommand$1(normalizedRootPath, [
|
|
120605
121013
|
"checkout",
|
|
120606
121014
|
normalizedBranchName
|
|
120607
|
-
]
|
|
121015
|
+
], {
|
|
121016
|
+
timeoutMs: GIT_CHECKOUT_TIMEOUT_MS
|
|
121017
|
+
});
|
|
120608
121018
|
if (checkoutResult.status !== 0) {
|
|
120609
121019
|
const reason = checkoutResult.stderr.trim() || checkoutResult.stdout.trim() || "unknown error";
|
|
120610
121020
|
throw new Error(`Failed to checkout git branch: ${reason}`);
|
|
@@ -122253,6 +122663,18 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122253
122663
|
const ThreadGoalClearedParamsSchema = object$1({
|
|
122254
122664
|
threadId: string$2()
|
|
122255
122665
|
});
|
|
122666
|
+
const CodexProposedPlanParamsSchema = object$1({
|
|
122667
|
+
schemaVersion: literal(1),
|
|
122668
|
+
sessionId: string$2(),
|
|
122669
|
+
turnId: string$2(),
|
|
122670
|
+
markdown: string$2(),
|
|
122671
|
+
status: _enum$1([
|
|
122672
|
+
"delta",
|
|
122673
|
+
"completed",
|
|
122674
|
+
"cleared"
|
|
122675
|
+
]),
|
|
122676
|
+
isLatest: boolean()
|
|
122677
|
+
});
|
|
122256
122678
|
const CODEX_IMAGE_GENERATION_TOOL_TITLE = "Image generation";
|
|
122257
122679
|
const CODEX_IMAGE_GENERATION_REVISED_PROMPT_PREFIX = "Revised prompt: ";
|
|
122258
122680
|
function extractCodexImageGenerationFields(content) {
|
|
@@ -122547,7 +122969,28 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122547
122969
|
this.options.onThreadGoalCleared?.(result.data.threadId);
|
|
122548
122970
|
break;
|
|
122549
122971
|
}
|
|
122972
|
+
case "acp_ext:codex_proposed_plan": {
|
|
122973
|
+
this.tryHandleCodexProposedPlanExtension(resolvedMethod, params);
|
|
122974
|
+
break;
|
|
122975
|
+
}
|
|
122976
|
+
default:
|
|
122977
|
+
this.logger.debug(`[${this.options.sessionId}] Ignoring extension message ${resolvedMethod}`);
|
|
122978
|
+
}
|
|
122979
|
+
}
|
|
122980
|
+
tryHandleCodexProposedPlanExtension(method, params) {
|
|
122981
|
+
if (!this.options.onCodexProposedPlan) return;
|
|
122982
|
+
const result = CodexProposedPlanParamsSchema.safeParse(params);
|
|
122983
|
+
if (!result.success) {
|
|
122984
|
+
this.logger.debug(`[${this.options.sessionId}] Dropping invalid Codex proposed plan update from ${method}: ${result.error.message}`);
|
|
122985
|
+
return;
|
|
122550
122986
|
}
|
|
122987
|
+
this.options.onCodexProposedPlan({
|
|
122988
|
+
type: "proposed_plan",
|
|
122989
|
+
turnId: result.data.turnId,
|
|
122990
|
+
markdown: result.data.markdown,
|
|
122991
|
+
status: result.data.status,
|
|
122992
|
+
isLatest: result.data.isLatest
|
|
122993
|
+
});
|
|
122551
122994
|
}
|
|
122552
122995
|
isCodexAgent() {
|
|
122553
122996
|
return this.options.agentConfig?.agentType === "codex";
|
|
@@ -122575,6 +123018,9 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122575
123018
|
_meta: {
|
|
122576
123019
|
claudeCode: {
|
|
122577
123020
|
askUserQuestion: true
|
|
123021
|
+
},
|
|
123022
|
+
codex: {
|
|
123023
|
+
requestUserInput: true
|
|
122578
123024
|
}
|
|
122579
123025
|
}
|
|
122580
123026
|
}
|
|
@@ -122909,7 +123355,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122909
123355
|
},
|
|
122910
123356
|
codex: {
|
|
122911
123357
|
packageName: "acp-extension-codex",
|
|
122912
|
-
version: "0.14.
|
|
123358
|
+
version: "0.14.5",
|
|
122913
123359
|
binName: "acp-extension-codex",
|
|
122914
123360
|
args: [
|
|
122915
123361
|
"-c",
|
|
@@ -122921,6 +123367,11 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
122921
123367
|
};
|
|
122922
123368
|
const OFFICIAL_NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
122923
123369
|
const NPX_CACHE_MODE_ARG = "--prefer-online";
|
|
123370
|
+
const DEFAULT_ACP_PATH_RELATIVE_DIRS = [
|
|
123371
|
+
".local/bin",
|
|
123372
|
+
"bin",
|
|
123373
|
+
".claude/local"
|
|
123374
|
+
];
|
|
122924
123375
|
const registryAgentsById = Object.fromEntries(REGISTRY_ACP_AGENTS.map((agent) => [
|
|
122925
123376
|
agent.id,
|
|
122926
123377
|
agent
|
|
@@ -123084,6 +123535,60 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
123084
123535
|
}
|
|
123085
123536
|
throw new Error(`Unsupported ACP cliType: ${input2.cliType}`);
|
|
123086
123537
|
}
|
|
123538
|
+
function resolveACPProcessLaunch(input2) {
|
|
123539
|
+
const setting = resolveACPSetting(input2);
|
|
123540
|
+
return {
|
|
123541
|
+
command: setting.exec.command,
|
|
123542
|
+
args: [
|
|
123543
|
+
...setting.exec.args,
|
|
123544
|
+
...input2.extraArgs ?? []
|
|
123545
|
+
],
|
|
123546
|
+
env: setting.exec.env
|
|
123547
|
+
};
|
|
123548
|
+
}
|
|
123549
|
+
function mergeACPProcessEnv(launch, baseEnv) {
|
|
123550
|
+
return launch.env ? {
|
|
123551
|
+
...baseEnv,
|
|
123552
|
+
...launch.env
|
|
123553
|
+
} : baseEnv;
|
|
123554
|
+
}
|
|
123555
|
+
function getPathEnvKey(env2) {
|
|
123556
|
+
if (process.platform !== "win32") {
|
|
123557
|
+
return "PATH";
|
|
123558
|
+
}
|
|
123559
|
+
return Object.keys(env2).find((key2) => key2.toLowerCase() === "path") ?? "Path";
|
|
123560
|
+
}
|
|
123561
|
+
function normalizePathEntry(entry2) {
|
|
123562
|
+
const normalized = normalize$2(entry2);
|
|
123563
|
+
return normalized.length > 1 ? normalized.replace(/[\\/]+$/, "") : normalized;
|
|
123564
|
+
}
|
|
123565
|
+
function getDefaultAcpPathEntries(homeDir = homedir()) {
|
|
123566
|
+
if (!homeDir) {
|
|
123567
|
+
return [];
|
|
123568
|
+
}
|
|
123569
|
+
return DEFAULT_ACP_PATH_RELATIVE_DIRS.map((relativeDir) => join$2(homeDir, relativeDir));
|
|
123570
|
+
}
|
|
123571
|
+
function withDefaultAcpPathEntries(env2) {
|
|
123572
|
+
const defaultEntries = getDefaultAcpPathEntries();
|
|
123573
|
+
if (defaultEntries.length === 0) {
|
|
123574
|
+
return env2;
|
|
123575
|
+
}
|
|
123576
|
+
const pathKey2 = getPathEnvKey(env2);
|
|
123577
|
+
const currentParts = (env2[pathKey2] ?? "").split(delimiter).filter(Boolean);
|
|
123578
|
+
const defaultEntrySet = new Set(defaultEntries.map(normalizePathEntry));
|
|
123579
|
+
const currentWithoutDefaults = currentParts.filter((entry2) => !defaultEntrySet.has(normalizePathEntry(entry2)));
|
|
123580
|
+
const nextPath = [
|
|
123581
|
+
...defaultEntries,
|
|
123582
|
+
...currentWithoutDefaults
|
|
123583
|
+
].join(delimiter);
|
|
123584
|
+
if (env2[pathKey2] === nextPath) {
|
|
123585
|
+
return env2;
|
|
123586
|
+
}
|
|
123587
|
+
return {
|
|
123588
|
+
...env2,
|
|
123589
|
+
[pathKey2]: nextPath
|
|
123590
|
+
};
|
|
123591
|
+
}
|
|
123087
123592
|
function createStdinWritableStream(stdin) {
|
|
123088
123593
|
stdin.on("error", (err2) => {
|
|
123089
123594
|
if (err2.code !== "EPIPE") {
|
|
@@ -123272,6 +123777,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
123272
123777
|
onRateLimitUpdate: options.onRateLimitUpdate,
|
|
123273
123778
|
onThreadGoalUpdated: options.onThreadGoalUpdated,
|
|
123274
123779
|
onThreadGoalCleared: options.onThreadGoalCleared,
|
|
123780
|
+
onCodexProposedPlan: options.onCodexProposedPlan,
|
|
123275
123781
|
onCodexImageGenerationBegin: options.onCodexImageGenerationBegin,
|
|
123276
123782
|
onCodexImageGenerationEnd: options.onCodexImageGenerationEnd
|
|
123277
123783
|
});
|
|
@@ -123333,12 +123839,12 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
123333
123839
|
await waitForChildProcessExit$1(child, exitTimeoutMs);
|
|
123334
123840
|
}
|
|
123335
123841
|
const spawnAcpProcess = (options) => {
|
|
123336
|
-
const
|
|
123842
|
+
const launch = resolveACPProcessLaunch({
|
|
123337
123843
|
cliType: options.cliType,
|
|
123338
123844
|
agentType: options.agentType
|
|
123339
123845
|
});
|
|
123340
|
-
const command2 = options.command ??
|
|
123341
|
-
const args2 = options.args ??
|
|
123846
|
+
const command2 = options.command ?? launch.command;
|
|
123847
|
+
const args2 = options.args ?? launch.args;
|
|
123342
123848
|
const spawnFn = options.spawnImpl ?? spawn;
|
|
123343
123849
|
return spawnFn(command2, args2, {
|
|
123344
123850
|
cwd: options.workdir,
|
|
@@ -123352,24 +123858,18 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
123352
123858
|
});
|
|
123353
123859
|
};
|
|
123354
123860
|
const startLocalAcpAgent = async (options) => {
|
|
123355
|
-
const
|
|
123861
|
+
const launch = resolveACPProcessLaunch({
|
|
123356
123862
|
cliType: options.cliType,
|
|
123357
|
-
agentType: options.agentType
|
|
123863
|
+
agentType: options.agentType,
|
|
123864
|
+
extraArgs: options.extraArgs
|
|
123358
123865
|
});
|
|
123359
|
-
const args2 = [
|
|
123360
|
-
...setting.exec.args,
|
|
123361
|
-
...options.extraArgs ?? []
|
|
123362
|
-
];
|
|
123363
123866
|
const baseEnv = options.env ?? process.env;
|
|
123364
123867
|
const shouldUseWorkdirCodexHome = options.cliType === "builtin" && options.agentType === "codex" && !baseEnv.CODEX_HOME && (baseEnv.LODY_E2E === "1" || baseEnv.LODY_TITLE_AGENT === "1");
|
|
123365
123868
|
const env2 = shouldUseWorkdirCodexHome ? {
|
|
123366
123869
|
...baseEnv,
|
|
123367
123870
|
CODEX_HOME: path__default.join(options.workdir, ".codex")
|
|
123368
123871
|
} : baseEnv;
|
|
123369
|
-
const envWithAcpStartup =
|
|
123370
|
-
...env2,
|
|
123371
|
-
...setting.exec.env
|
|
123372
|
-
} : env2;
|
|
123872
|
+
const envWithAcpStartup = withDefaultAcpPathEntries(mergeACPProcessEnv(launch, env2));
|
|
123373
123873
|
const keepCodexHome = env2.LODY_KEEP_CODEX_HOME === "1";
|
|
123374
123874
|
const defaultCodexHome = path__default.join(os__default.homedir(), ".codex");
|
|
123375
123875
|
const defaultAuthPath = path__default.join(defaultCodexHome, "auth.json");
|
|
@@ -123392,7 +123892,8 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
123392
123892
|
agentType: options.agentType,
|
|
123393
123893
|
workdir: options.workdir,
|
|
123394
123894
|
env: envWithAcpStartup,
|
|
123395
|
-
|
|
123895
|
+
command: launch.command,
|
|
123896
|
+
args: launch.args,
|
|
123396
123897
|
spawnImpl: options.spawnImpl
|
|
123397
123898
|
});
|
|
123398
123899
|
options.logger.debug(`[acp-startup] spawned ACP process (cliType=${options.cliType} agentType=${options.agentType} workdir=${options.workdir})`);
|
|
@@ -123425,8 +123926,8 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
123425
123926
|
}
|
|
123426
123927
|
}, {
|
|
123427
123928
|
sessionId: "acp-startup",
|
|
123428
|
-
command:
|
|
123429
|
-
args:
|
|
123929
|
+
command: launch.command,
|
|
123930
|
+
args: launch.args,
|
|
123430
123931
|
getStderrTail: () => stderrTail
|
|
123431
123932
|
});
|
|
123432
123933
|
if (shouldUseWorkdirCodexHome && env2.CODEX_HOME && !keepCodexHome) {
|
|
@@ -124144,7 +124645,8 @@ const normalizeRepoPath = (rawPath) => {
|
|
|
124144
124645
|
|
|
124145
124646
|
const main = async () => {
|
|
124146
124647
|
const action = process.argv[2];
|
|
124147
|
-
|
|
124648
|
+
const isRejectAction = action === 'erase' || action === 'reject';
|
|
124649
|
+
if (action && action !== 'get' && !isRejectAction) {
|
|
124148
124650
|
debug('skip', { reason: 'unsupported_action', action });
|
|
124149
124651
|
return;
|
|
124150
124652
|
}
|
|
@@ -124183,23 +124685,18 @@ const main = async () => {
|
|
|
124183
124685
|
return;
|
|
124184
124686
|
}
|
|
124185
124687
|
|
|
124186
|
-
|
|
124187
|
-
* Attempt to fetch credentials from a broker URL.
|
|
124188
|
-
* Returns { success: true, json } on success, { success: false, error } on connection error,
|
|
124189
|
-
* or { success: false } on other failures.
|
|
124190
|
-
*/
|
|
124191
|
-
const tryFetchFromBroker = async (baseUrl, token) => {
|
|
124688
|
+
const tryBrokerRequest = async (baseUrl, token, endpoint, body) => {
|
|
124192
124689
|
const controller = new AbortController();
|
|
124193
124690
|
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
124194
124691
|
try {
|
|
124195
|
-
debug('fetch', { repoFullName, baseUrl });
|
|
124196
|
-
const res = await fetchImpl(\`\${baseUrl}
|
|
124692
|
+
debug('fetch', { repoFullName, baseUrl, endpoint });
|
|
124693
|
+
const res = await fetchImpl(\`\${baseUrl}\${endpoint}\`, {
|
|
124197
124694
|
method: 'POST',
|
|
124198
124695
|
headers: {
|
|
124199
124696
|
'Content-Type': 'application/json',
|
|
124200
124697
|
Authorization: \`Bearer \${token}\`,
|
|
124201
124698
|
},
|
|
124202
|
-
body: JSON.stringify(
|
|
124699
|
+
body: JSON.stringify(body),
|
|
124203
124700
|
signal: controller.signal,
|
|
124204
124701
|
});
|
|
124205
124702
|
|
|
@@ -124214,11 +124711,6 @@ const main = async () => {
|
|
|
124214
124711
|
return { success: false };
|
|
124215
124712
|
}
|
|
124216
124713
|
|
|
124217
|
-
if (!json || typeof json.username !== 'string' || typeof json.password !== 'string') {
|
|
124218
|
-
return { success: false };
|
|
124219
|
-
}
|
|
124220
|
-
if (!json.username || !json.password) return { success: false };
|
|
124221
|
-
|
|
124222
124714
|
return { success: true, json };
|
|
124223
124715
|
} catch (error) {
|
|
124224
124716
|
debug('fetch_error', { repoFullName, error: error && error.message });
|
|
@@ -124228,8 +124720,36 @@ const main = async () => {
|
|
|
124228
124720
|
}
|
|
124229
124721
|
};
|
|
124230
124722
|
|
|
124723
|
+
/**
|
|
124724
|
+
* Attempt to fetch credentials from a broker URL.
|
|
124725
|
+
* Returns { success: true, json } on success, { success: false, error } on connection error,
|
|
124726
|
+
* or { success: false } on other failures.
|
|
124727
|
+
*/
|
|
124728
|
+
const tryFetchFromBroker = async (baseUrl, token) => {
|
|
124729
|
+
const result = await tryBrokerRequest(baseUrl, token, '/git-credential', { repoFullName });
|
|
124730
|
+
if (!result.success) return result;
|
|
124731
|
+
|
|
124732
|
+
const json = result.json;
|
|
124733
|
+
if (!json || typeof json.username !== 'string' || typeof json.password !== 'string') {
|
|
124734
|
+
return { success: false };
|
|
124735
|
+
}
|
|
124736
|
+
if (!json.username || !json.password) return { success: false };
|
|
124737
|
+
|
|
124738
|
+
return result;
|
|
124739
|
+
};
|
|
124740
|
+
|
|
124741
|
+
const tryRejectFromBroker = async (baseUrl, token) => {
|
|
124742
|
+
const invalidatedToken = typeof req.password === 'string' ? req.password : undefined;
|
|
124743
|
+
return tryBrokerRequest(baseUrl, token, '/git-credential/reject', {
|
|
124744
|
+
repoFullName,
|
|
124745
|
+
...(invalidatedToken ? { invalidatedToken } : {}),
|
|
124746
|
+
});
|
|
124747
|
+
};
|
|
124748
|
+
|
|
124231
124749
|
const { url: baseUrl, token, source } = brokerConfig;
|
|
124232
|
-
let result =
|
|
124750
|
+
let result = isRejectAction
|
|
124751
|
+
? await tryRejectFromBroker(baseUrl, token)
|
|
124752
|
+
: await tryFetchFromBroker(baseUrl, token);
|
|
124233
124753
|
|
|
124234
124754
|
// If we had a connection error and we were using env vars, try the file fallback
|
|
124235
124755
|
// This handles the case where the broker restarted on a different port
|
|
@@ -124237,10 +124757,17 @@ const main = async () => {
|
|
|
124237
124757
|
const fileConfig = getBrokerConfigFromFile();
|
|
124238
124758
|
if (fileConfig && fileConfig.url !== baseUrl) {
|
|
124239
124759
|
debug('fallback', { from: baseUrl, to: fileConfig.url });
|
|
124240
|
-
result =
|
|
124760
|
+
result = isRejectAction
|
|
124761
|
+
? await tryRejectFromBroker(fileConfig.url, fileConfig.token)
|
|
124762
|
+
: await tryFetchFromBroker(fileConfig.url, fileConfig.token);
|
|
124241
124763
|
}
|
|
124242
124764
|
}
|
|
124243
124765
|
|
|
124766
|
+
if (isRejectAction) {
|
|
124767
|
+
debug(result.success ? 'reject_success' : 'reject_failed', { repoFullName });
|
|
124768
|
+
return;
|
|
124769
|
+
}
|
|
124770
|
+
|
|
124244
124771
|
if (!result.success || !result.json) {
|
|
124245
124772
|
return;
|
|
124246
124773
|
}
|
|
@@ -125624,6 +126151,9 @@ path=/${options.repoFullName}.git
|
|
|
125624
126151
|
acpFlushInFlight: null,
|
|
125625
126152
|
acpFlushTimer: null,
|
|
125626
126153
|
acpFlushCountInTurn: 0,
|
|
126154
|
+
codexProposedPlanBuffer: /* @__PURE__ */ new Map(),
|
|
126155
|
+
codexProposedPlanFlushInFlight: null,
|
|
126156
|
+
codexProposedPlanFlushTimer: null,
|
|
125627
126157
|
contextWindowUsageBuffer: null,
|
|
125628
126158
|
contextWindowUsageTimer: null,
|
|
125629
126159
|
pendingContextWindowHandlers: /* @__PURE__ */ new Set(),
|
|
@@ -125713,7 +126243,7 @@ path=/${options.repoFullName}.git
|
|
|
125713
126243
|
hasPendingTurnWork(sessionId) {
|
|
125714
126244
|
const state2 = this.sessions.get(sessionId);
|
|
125715
126245
|
if (!state2) return false;
|
|
125716
|
-
return state2.turn.phase !== "idle" || state2.acpUpdateBuffer.length > 0 || state2.acpFlushInFlight !== null || state2.acpFlushTimer !== null || state2.contextWindowUsageBuffer !== null || state2.contextWindowUsageTimer !== null || state2.pendingContextWindowHandlers.size > 0 || state2.pendingThreadGoalHandlers.size > 0 || state2.codexImageGenerationUploads.size > 0 || state2.pendingUnread;
|
|
126246
|
+
return state2.turn.phase !== "idle" || state2.acpUpdateBuffer.length > 0 || state2.acpFlushInFlight !== null || state2.acpFlushTimer !== null || state2.codexProposedPlanBuffer.size > 0 || state2.codexProposedPlanFlushInFlight !== null || state2.codexProposedPlanFlushTimer !== null || state2.contextWindowUsageBuffer !== null || state2.contextWindowUsageTimer !== null || state2.pendingContextWindowHandlers.size > 0 || state2.pendingThreadGoalHandlers.size > 0 || state2.codexImageGenerationUploads.size > 0 || state2.pendingUnread;
|
|
125717
126247
|
}
|
|
125718
126248
|
clearTurnState(sessionId) {
|
|
125719
126249
|
const state2 = this.sessions.get(sessionId);
|
|
@@ -125729,6 +126259,11 @@ path=/${options.repoFullName}.git
|
|
|
125729
126259
|
state2.acpFlushTimer = null;
|
|
125730
126260
|
}
|
|
125731
126261
|
state2.acpFlushCountInTurn = 0;
|
|
126262
|
+
state2.codexProposedPlanBuffer.clear();
|
|
126263
|
+
if (state2.codexProposedPlanFlushTimer) {
|
|
126264
|
+
clearTimeout(state2.codexProposedPlanFlushTimer);
|
|
126265
|
+
state2.codexProposedPlanFlushTimer = null;
|
|
126266
|
+
}
|
|
125732
126267
|
if (state2.contextWindowUsageTimer) {
|
|
125733
126268
|
clearTimeout(state2.contextWindowUsageTimer);
|
|
125734
126269
|
state2.contextWindowUsageTimer = null;
|
|
@@ -125747,6 +126282,9 @@ path=/${options.repoFullName}.git
|
|
|
125747
126282
|
if (state2.acpFlushTimer) {
|
|
125748
126283
|
clearTimeout(state2.acpFlushTimer);
|
|
125749
126284
|
}
|
|
126285
|
+
if (state2.codexProposedPlanFlushTimer) {
|
|
126286
|
+
clearTimeout(state2.codexProposedPlanFlushTimer);
|
|
126287
|
+
}
|
|
125750
126288
|
this.sessions.delete(sessionId);
|
|
125751
126289
|
}
|
|
125752
126290
|
}
|
|
@@ -126711,6 +127249,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
126711
127249
|
canceledTurnBySession = /* @__PURE__ */ new Map();
|
|
126712
127250
|
currentTurnBySession = /* @__PURE__ */ new Map();
|
|
126713
127251
|
turnRuntimeBySession = /* @__PURE__ */ new Map();
|
|
127252
|
+
inFlightAcpRefresh = new InFlightDedupe();
|
|
126714
127253
|
getExecutionSnapshot(sessionId) {
|
|
126715
127254
|
const runtime = this.turnRuntimeBySession.get(sessionId);
|
|
126716
127255
|
const currentTurnId = this.currentTurnBySession.get(sessionId);
|
|
@@ -128296,7 +128835,11 @@ $mem | ConvertTo-Json -Compress
|
|
|
128296
128835
|
error: `Machine mismatch: expected ${this.deps.machineId}, got ${message.machineId}`
|
|
128297
128836
|
};
|
|
128298
128837
|
}
|
|
128838
|
+
const dedupeKey = computeAcpRefreshDedupeKey(message.cliType, message.agentType, message.env);
|
|
128299
128839
|
this.deps.logger.debug(`[acp-capabilities] Refresh requested (cliType=${message.cliType} agentType=${message.agentType})`);
|
|
128840
|
+
return await this.inFlightAcpRefresh.run(dedupeKey, () => this.executeAcpRefresh(message));
|
|
128841
|
+
}
|
|
128842
|
+
async executeAcpRefresh(message) {
|
|
128300
128843
|
try {
|
|
128301
128844
|
const { modes, models, configOptions, availableCommands } = await this.deps.fetchAcpCapabilities(message.cliType, message.agentType, message.env);
|
|
128302
128845
|
await this.deps.workspaceDocument.updateAcpCapabilities(this.deps.machineId, message.cliType, message.agentType, modes, models, configOptions, availableCommands, getAcpCapabilitySourceVersion({
|
|
@@ -128333,6 +128876,11 @@ $mem | ConvertTo-Json -Compress
|
|
|
128333
128876
|
}
|
|
128334
128877
|
}
|
|
128335
128878
|
}
|
|
128879
|
+
const computeAcpRefreshDedupeKey = (cliType, agentType, env2) => {
|
|
128880
|
+
const sortedKeys = env2 ? Object.keys(env2).sort() : [];
|
|
128881
|
+
const envSerialized = sortedKeys.map((k) => `${k}=${env2[k]}`).join("");
|
|
128882
|
+
return `${cliType}\0${agentType}\0${envSerialized}`;
|
|
128883
|
+
};
|
|
128336
128884
|
class SessionUserResolver {
|
|
128337
128885
|
constructor(logger2, workspaceId) {
|
|
128338
128886
|
this.logger = logger2;
|
|
@@ -131638,17 +132186,24 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
131638
132186
|
function getProviderLabel$1(provider2) {
|
|
131639
132187
|
return getLocalProjectHistoryProviderKey(provider2);
|
|
131640
132188
|
}
|
|
132189
|
+
function resolveHistoryACPProcessLaunch(args2) {
|
|
132190
|
+
const launch = resolveACPProcessLaunch(args2.provider);
|
|
132191
|
+
return {
|
|
132192
|
+
...launch,
|
|
132193
|
+
env: mergeACPProcessEnv(launch, args2.env ?? process.env)
|
|
132194
|
+
};
|
|
132195
|
+
}
|
|
131641
132196
|
async function createHistoryAcpConnection(args2) {
|
|
131642
|
-
const
|
|
131643
|
-
|
|
131644
|
-
|
|
131645
|
-
...setting.exec.env
|
|
131646
|
-
} : process.env;
|
|
132197
|
+
const launch = resolveHistoryACPProcessLaunch({
|
|
132198
|
+
provider: args2.provider
|
|
132199
|
+
});
|
|
131647
132200
|
const agentProcess = spawnAcpProcess({
|
|
131648
132201
|
cliType: args2.provider.cliType,
|
|
131649
132202
|
agentType: args2.provider.agentType,
|
|
131650
132203
|
workdir: args2.workdir,
|
|
131651
|
-
env:
|
|
132204
|
+
env: launch.env,
|
|
132205
|
+
command: launch.command,
|
|
132206
|
+
args: launch.args
|
|
131652
132207
|
});
|
|
131653
132208
|
agentProcess.stderr?.setEncoding("utf8");
|
|
131654
132209
|
agentProcess.stderr?.on("data", (chunk) => {
|
|
@@ -132539,6 +133094,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
132539
133094
|
streamClient: jsonStreamClient,
|
|
132540
133095
|
rpcVersion: LORO_STREAMS_RPC_VERSION,
|
|
132541
133096
|
retentionSeconds: LORO_STREAMS_RPC_RETENTION_SECONDS,
|
|
133097
|
+
now: getServerNow,
|
|
132542
133098
|
getMachineStatus: async () => await this.executionService.getMachineStatus({
|
|
132543
133099
|
type: "machine/status",
|
|
132544
133100
|
machineId: this.machineId,
|
|
@@ -132635,6 +133191,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
132635
133191
|
usageTrackingService;
|
|
132636
133192
|
static ACP_INITIAL_UPDATE_BATCH_WINDOW_MS = 10;
|
|
132637
133193
|
static ACP_SUBSEQUENT_UPDATE_BATCH_WINDOW_MS = 100;
|
|
133194
|
+
static CODEX_PROPOSED_PLAN_UPDATE_BATCH_WINDOW_MS = 100;
|
|
132638
133195
|
static CONTEXT_WINDOW_USAGE_THROTTLE_MS = 400;
|
|
132639
133196
|
permissionRequestStartTimes = /* @__PURE__ */ new Map();
|
|
132640
133197
|
machineHeartbeatTimer = null;
|
|
@@ -133038,6 +133595,125 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
133038
133595
|
this.logger.debug(`[${sessionId}] Failed to persist thread goal clear: ${formatErrorMessage(error2)}`);
|
|
133039
133596
|
}
|
|
133040
133597
|
}
|
|
133598
|
+
enqueueCodexProposedPlanUpdate(sessionId, plan) {
|
|
133599
|
+
const state2 = this.store.get(sessionId);
|
|
133600
|
+
const targetEntryId = this.store.getTurnId(sessionId);
|
|
133601
|
+
const existing = state2.codexProposedPlanBuffer.get(plan.turnId);
|
|
133602
|
+
if (existing && existing.targetEntryId === targetEntryId && existing.plan.markdown === plan.markdown && existing.plan.status === plan.status && existing.plan.isLatest === plan.isLatest) {
|
|
133603
|
+
return;
|
|
133604
|
+
}
|
|
133605
|
+
state2.codexProposedPlanBuffer.set(plan.turnId, {
|
|
133606
|
+
plan,
|
|
133607
|
+
...targetEntryId ? {
|
|
133608
|
+
targetEntryId
|
|
133609
|
+
} : {}
|
|
133610
|
+
});
|
|
133611
|
+
this.scheduleCodexProposedPlanFlush(sessionId);
|
|
133612
|
+
}
|
|
133613
|
+
clearScheduledCodexProposedPlanFlush(sessionId) {
|
|
133614
|
+
const state2 = this.store.get(sessionId);
|
|
133615
|
+
if (!state2.codexProposedPlanFlushTimer) {
|
|
133616
|
+
return;
|
|
133617
|
+
}
|
|
133618
|
+
clearTimeout(state2.codexProposedPlanFlushTimer);
|
|
133619
|
+
state2.codexProposedPlanFlushTimer = null;
|
|
133620
|
+
}
|
|
133621
|
+
scheduleCodexProposedPlanFlush(sessionId) {
|
|
133622
|
+
const state2 = this.store.get(sessionId);
|
|
133623
|
+
if (state2.codexProposedPlanFlushInFlight || state2.codexProposedPlanFlushTimer) {
|
|
133624
|
+
return;
|
|
133625
|
+
}
|
|
133626
|
+
const timer2 = setTimeout(() => {
|
|
133627
|
+
state2.codexProposedPlanFlushTimer = null;
|
|
133628
|
+
void this.startCodexProposedPlanFlush(sessionId);
|
|
133629
|
+
}, MessageHandler.CODEX_PROPOSED_PLAN_UPDATE_BATCH_WINDOW_MS);
|
|
133630
|
+
timer2.unref?.();
|
|
133631
|
+
state2.codexProposedPlanFlushTimer = timer2;
|
|
133632
|
+
}
|
|
133633
|
+
startCodexProposedPlanFlush(sessionId) {
|
|
133634
|
+
const state2 = this.store.get(sessionId);
|
|
133635
|
+
if (state2.codexProposedPlanFlushInFlight) {
|
|
133636
|
+
return state2.codexProposedPlanFlushInFlight;
|
|
133637
|
+
}
|
|
133638
|
+
const flushPromise = this.flushCodexProposedPlanUpdates(sessionId).catch((error2) => {
|
|
133639
|
+
this.logger.error(`[${sessionId}] Failed to flush Codex proposed plan updates: ${formatErrorMessage(error2, {
|
|
133640
|
+
includeStack: true
|
|
133641
|
+
})}`);
|
|
133642
|
+
}).finally(() => {
|
|
133643
|
+
state2.codexProposedPlanFlushInFlight = null;
|
|
133644
|
+
if (state2.codexProposedPlanBuffer.size > 0) {
|
|
133645
|
+
this.scheduleCodexProposedPlanFlush(sessionId);
|
|
133646
|
+
}
|
|
133647
|
+
});
|
|
133648
|
+
state2.codexProposedPlanFlushInFlight = flushPromise;
|
|
133649
|
+
return flushPromise;
|
|
133650
|
+
}
|
|
133651
|
+
async flushCodexProposedPlanUpdatesNow(sessionId) {
|
|
133652
|
+
const state2 = this.store.get(sessionId);
|
|
133653
|
+
this.clearScheduledCodexProposedPlanFlush(sessionId);
|
|
133654
|
+
while (true) {
|
|
133655
|
+
if (!state2.codexProposedPlanFlushInFlight) {
|
|
133656
|
+
if (state2.codexProposedPlanBuffer.size === 0) {
|
|
133657
|
+
return;
|
|
133658
|
+
}
|
|
133659
|
+
void this.startCodexProposedPlanFlush(sessionId);
|
|
133660
|
+
}
|
|
133661
|
+
const inFlight = state2.codexProposedPlanFlushInFlight;
|
|
133662
|
+
if (!inFlight) {
|
|
133663
|
+
return;
|
|
133664
|
+
}
|
|
133665
|
+
await inFlight;
|
|
133666
|
+
this.clearScheduledCodexProposedPlanFlush(sessionId);
|
|
133667
|
+
if (state2.codexProposedPlanBuffer.size === 0 && !state2.codexProposedPlanFlushInFlight) {
|
|
133668
|
+
return;
|
|
133669
|
+
}
|
|
133670
|
+
}
|
|
133671
|
+
}
|
|
133672
|
+
async flushCodexProposedPlanUpdates(sessionId) {
|
|
133673
|
+
const state2 = this.store.get(sessionId);
|
|
133674
|
+
this.clearScheduledCodexProposedPlanFlush(sessionId);
|
|
133675
|
+
if (state2.codexProposedPlanBuffer.size === 0) {
|
|
133676
|
+
return;
|
|
133677
|
+
}
|
|
133678
|
+
const snapshots = [
|
|
133679
|
+
...state2.codexProposedPlanBuffer.values()
|
|
133680
|
+
];
|
|
133681
|
+
state2.codexProposedPlanBuffer.clear();
|
|
133682
|
+
const groups = /* @__PURE__ */ new Map();
|
|
133683
|
+
for (const snapshot of snapshots) {
|
|
133684
|
+
const key2 = snapshot.targetEntryId ?? "";
|
|
133685
|
+
const group = groups.get(key2);
|
|
133686
|
+
if (group) {
|
|
133687
|
+
group.plans.push(snapshot.plan);
|
|
133688
|
+
} else {
|
|
133689
|
+
groups.set(key2, {
|
|
133690
|
+
targetEntryId: snapshot.targetEntryId,
|
|
133691
|
+
plans: [
|
|
133692
|
+
snapshot.plan
|
|
133693
|
+
]
|
|
133694
|
+
});
|
|
133695
|
+
}
|
|
133696
|
+
}
|
|
133697
|
+
const sessionDoc = await this.workspaceDocument.getOrCreateSessionDoc(sessionId);
|
|
133698
|
+
await sessionDoc.updateHistory((history) => {
|
|
133699
|
+
let next = history;
|
|
133700
|
+
for (const group of groups.values()) {
|
|
133701
|
+
next = applyMessageContentsBatch(next, group.plans, {
|
|
133702
|
+
...group.targetEntryId ? {
|
|
133703
|
+
targetAssistantEntryId: group.targetEntryId
|
|
133704
|
+
} : {},
|
|
133705
|
+
createId: () => group.targetEntryId ?? v4(),
|
|
133706
|
+
now: () => new Date(getServerNow()).toISOString()
|
|
133707
|
+
});
|
|
133708
|
+
}
|
|
133709
|
+
return next;
|
|
133710
|
+
});
|
|
133711
|
+
if (state2.turn.phase === "idle") {
|
|
133712
|
+
await sessionDoc.setLastMessageAt();
|
|
133713
|
+
} else {
|
|
133714
|
+
state2.pendingUnread = true;
|
|
133715
|
+
}
|
|
133716
|
+
}
|
|
133041
133717
|
async persistContextWindowUsage(sessionId, usage) {
|
|
133042
133718
|
try {
|
|
133043
133719
|
const sessionDoc = await this.workspaceDocument.getOrCreateSessionDoc(sessionId);
|
|
@@ -133473,13 +134149,14 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
133473
134149
|
return failure("local_project_not_found", `Local project not found: ${args2.localProjectId}`);
|
|
133474
134150
|
}
|
|
133475
134151
|
try {
|
|
134152
|
+
const state2 = getLocalProjectGitStateAtRootPath(rootPath);
|
|
133476
134153
|
return {
|
|
133477
134154
|
type: "local-project/git-state_response",
|
|
133478
134155
|
machineId: this.machineId,
|
|
133479
134156
|
workspaceId: this.workspaceId,
|
|
133480
134157
|
localProjectId: args2.localProjectId,
|
|
133481
134158
|
success: true,
|
|
133482
|
-
state:
|
|
134159
|
+
state: state2,
|
|
133483
134160
|
observedAtMs: getServerNow()
|
|
133484
134161
|
};
|
|
133485
134162
|
} catch (error2) {
|
|
@@ -133579,6 +134256,9 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
133579
134256
|
this.sessionManager.on("onThreadGoalCleared", (sessionId, threadId2) => {
|
|
133580
134257
|
this.enqueueThreadGoalHistoryPersist(sessionId, () => this.persistThreadGoalClear(sessionId, threadId2));
|
|
133581
134258
|
});
|
|
134259
|
+
this.sessionManager.on("onCodexProposedPlan", (sessionId, plan) => {
|
|
134260
|
+
this.enqueueCodexProposedPlanUpdate(sessionId, plan);
|
|
134261
|
+
});
|
|
133582
134262
|
this.sessionManager.on("onCodexImageGenerationBegin", (sessionId, event) => {
|
|
133583
134263
|
this.handleCodexImageGenerationBegin(sessionId, event);
|
|
133584
134264
|
});
|
|
@@ -134254,6 +134934,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
134254
134934
|
await this.flushSessionContextWindowUsage(sessionId);
|
|
134255
134935
|
await this.flushACPUpdatesNow(sessionId);
|
|
134256
134936
|
await this.flushThreadGoalHistoryPersists(sessionId);
|
|
134937
|
+
await this.flushCodexProposedPlanUpdatesNow(sessionId);
|
|
134257
134938
|
await this.flushCodexGeneratedImageUploads(sessionId);
|
|
134258
134939
|
if (state2.pendingUnread) {
|
|
134259
134940
|
state2.pendingUnread = false;
|
|
@@ -136089,12 +136770,17 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136089
136770
|
this.stopAutoRefresh();
|
|
136090
136771
|
this.states.clear();
|
|
136091
136772
|
}
|
|
136092
|
-
invalidate(repoFullName) {
|
|
136773
|
+
invalidate(repoFullName, options) {
|
|
136093
136774
|
try {
|
|
136094
136775
|
const repoKeyPrefix = `${normalizeGitHubRepo(repoFullName).toLowerCase()}:`;
|
|
136095
136776
|
const states = Array.from(this.states.entries()).filter(([key2]) => key2.startsWith(repoKeyPrefix));
|
|
136096
136777
|
for (const [repoKey, state2] of states) {
|
|
136097
136778
|
this.logger.debug(`[github-token] Invalidating cached token for repo: ${repoKey}`);
|
|
136779
|
+
if (options?.invalidatedToken && state2.operation === "write") {
|
|
136780
|
+
state2.invalidatedPersonalToken = options.invalidatedToken;
|
|
136781
|
+
} else if (options?.markPersonalTokenInvalid && state2.operation === "write" && state2.tokenSource === "personal" && state2.token) {
|
|
136782
|
+
state2.invalidatedPersonalToken = state2.token;
|
|
136783
|
+
}
|
|
136098
136784
|
state2.token = null;
|
|
136099
136785
|
state2.expiresAtMs = null;
|
|
136100
136786
|
state2.tokenSource = null;
|
|
@@ -136110,6 +136796,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136110
136796
|
state2.token = null;
|
|
136111
136797
|
state2.expiresAtMs = null;
|
|
136112
136798
|
state2.tokenSource = null;
|
|
136799
|
+
state2.invalidatedPersonalToken = null;
|
|
136113
136800
|
state2.inFlight = void 0;
|
|
136114
136801
|
}
|
|
136115
136802
|
}
|
|
@@ -136123,7 +136810,8 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136123
136810
|
operation,
|
|
136124
136811
|
token: null,
|
|
136125
136812
|
expiresAtMs: null,
|
|
136126
|
-
tokenSource: null
|
|
136813
|
+
tokenSource: null,
|
|
136814
|
+
invalidatedPersonalToken: null
|
|
136127
136815
|
};
|
|
136128
136816
|
this.states.set(repoKey, state2);
|
|
136129
136817
|
return state2;
|
|
@@ -136144,7 +136832,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136144
136832
|
this.applyTokenResult(state2, result);
|
|
136145
136833
|
return;
|
|
136146
136834
|
}
|
|
136147
|
-
state2.inFlight = this.fetchToken(state2.repoFullName, state2.operation);
|
|
136835
|
+
state2.inFlight = this.fetchToken(state2.repoFullName, state2.operation, state2.invalidatedPersonalToken ?? void 0);
|
|
136148
136836
|
try {
|
|
136149
136837
|
const result = await state2.inFlight;
|
|
136150
136838
|
this.applyTokenResult(state2, result);
|
|
@@ -136177,12 +136865,15 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136177
136865
|
this.refreshAllInFlight = null;
|
|
136178
136866
|
}
|
|
136179
136867
|
}
|
|
136180
|
-
async fetchToken(repoFullName, operation) {
|
|
136868
|
+
async fetchToken(repoFullName, operation, invalidatedPersonalToken) {
|
|
136181
136869
|
const raw = await this.client.action(api.github.getOperationAccessTokenByRepoNameForCli, {
|
|
136182
136870
|
repoFullName,
|
|
136183
136871
|
cliToken: this.cliToken,
|
|
136184
136872
|
workspaceId: this.workspaceId,
|
|
136185
|
-
operation
|
|
136873
|
+
operation,
|
|
136874
|
+
...operation === "write" && invalidatedPersonalToken ? {
|
|
136875
|
+
invalidatedPersonalToken
|
|
136876
|
+
} : {}
|
|
136186
136877
|
});
|
|
136187
136878
|
const result = GitHubTokenResponseSchema.parse(raw);
|
|
136188
136879
|
if (!result.success) {
|
|
@@ -136195,9 +136886,14 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136195
136886
|
};
|
|
136196
136887
|
}
|
|
136197
136888
|
applyTokenResult(state2, result) {
|
|
136889
|
+
const tokenSource = result.tokenSource ?? "app";
|
|
136890
|
+
if (state2.invalidatedPersonalToken && tokenSource === "personal" && result.token === state2.invalidatedPersonalToken) {
|
|
136891
|
+
throw new GitHubTokenFetchError("token_generation_failed", `Backend returned an invalidated personal GitHub token for repository "${state2.repoFullName}".`);
|
|
136892
|
+
}
|
|
136198
136893
|
const parsedMs = result.expiresAt ? Date.parse(result.expiresAt) : NaN;
|
|
136199
136894
|
state2.token = result.token;
|
|
136200
|
-
state2.tokenSource =
|
|
136895
|
+
state2.tokenSource = tokenSource;
|
|
136896
|
+
state2.invalidatedPersonalToken = null;
|
|
136201
136897
|
if (Number.isFinite(parsedMs)) {
|
|
136202
136898
|
state2.expiresAtMs = parsedMs;
|
|
136203
136899
|
} else if (state2.tokenSource === "personal") {
|
|
@@ -136221,7 +136917,12 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136221
136917
|
}));
|
|
136222
136918
|
return;
|
|
136223
136919
|
}
|
|
136224
|
-
if (req.method !== "POST" ||
|
|
136920
|
+
if (req.method !== "POST" || ![
|
|
136921
|
+
"/git-credential",
|
|
136922
|
+
"/github-token",
|
|
136923
|
+
"/git-credential/reject",
|
|
136924
|
+
"/github-token/reject"
|
|
136925
|
+
].includes(req.url ?? "")) {
|
|
136225
136926
|
res.writeHead(404, {
|
|
136226
136927
|
"Content-Type": "application/json"
|
|
136227
136928
|
});
|
|
@@ -136255,8 +136956,25 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136255
136956
|
}));
|
|
136256
136957
|
return;
|
|
136257
136958
|
}
|
|
136959
|
+
if (req.url === "/git-credential/reject" || req.url === "/github-token/reject") {
|
|
136960
|
+
const invalidatedToken = obj && typeof obj.invalidatedToken === "string" ? obj.invalidatedToken : void 0;
|
|
136961
|
+
options.tokenManager.invalidate(repoFullName, {
|
|
136962
|
+
...invalidatedToken ? {
|
|
136963
|
+
invalidatedToken
|
|
136964
|
+
} : {
|
|
136965
|
+
markPersonalTokenInvalid: true
|
|
136966
|
+
}
|
|
136967
|
+
});
|
|
136968
|
+
res.writeHead(200, {
|
|
136969
|
+
"Content-Type": "application/json"
|
|
136970
|
+
});
|
|
136971
|
+
res.end(JSON.stringify({
|
|
136972
|
+
ok: true
|
|
136973
|
+
}));
|
|
136974
|
+
return;
|
|
136975
|
+
}
|
|
136258
136976
|
const tokenValue = await options.tokenManager.getTokenForRepo(repoFullName, {
|
|
136259
|
-
operation: "
|
|
136977
|
+
operation: "write"
|
|
136260
136978
|
});
|
|
136261
136979
|
if (!tokenValue) {
|
|
136262
136980
|
res.writeHead(404, {
|
|
@@ -136589,11 +137307,11 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136589
137307
|
return null;
|
|
136590
137308
|
}
|
|
136591
137309
|
if (!githubRepo) {
|
|
136592
|
-
logger2.debug("[gh-token] No GitHub repo context \u2014 cannot fetch
|
|
137310
|
+
logger2.debug("[gh-token] No GitHub repo context \u2014 cannot fetch managed token");
|
|
136593
137311
|
return null;
|
|
136594
137312
|
}
|
|
136595
137313
|
if (!tokenManager) {
|
|
136596
|
-
logger2.debug("[gh-token] No token manager available \u2014 cannot fetch
|
|
137314
|
+
logger2.debug("[gh-token] No token manager available \u2014 cannot fetch managed token");
|
|
136597
137315
|
return null;
|
|
136598
137316
|
}
|
|
136599
137317
|
if (managedRepoToken) {
|
|
@@ -136612,10 +137330,10 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136612
137330
|
const token2 = await tokenManager.getTokenForRepo(githubRepo, {
|
|
136613
137331
|
operation: "write"
|
|
136614
137332
|
});
|
|
136615
|
-
logger2.debug(`[gh-token] Fetched
|
|
137333
|
+
logger2.debug(`[gh-token] Fetched managed write-operation token for ${githubRepo}`);
|
|
136616
137334
|
return token2;
|
|
136617
137335
|
} catch (error2) {
|
|
136618
|
-
logger2.debug(`[gh-token] Failed to fetch
|
|
137336
|
+
logger2.debug(`[gh-token] Failed to fetch managed write-operation token for ${githubRepo}: ${formatErrorMessage(error2)}`);
|
|
136619
137337
|
return null;
|
|
136620
137338
|
}
|
|
136621
137339
|
}
|
|
@@ -136657,9 +137375,17 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136657
137375
|
mode: mode2
|
|
136658
137376
|
});
|
|
136659
137377
|
};
|
|
136660
|
-
const
|
|
137378
|
+
const GH_SHIM_POSIX_BASENAME = "gh";
|
|
137379
|
+
const GH_SHIM_WINDOWS_BASENAME = "gh.cmd";
|
|
136661
137380
|
const REAL_GH_PATH_PLACEHOLDER = "__LODY_REAL_GH_PATH__";
|
|
137381
|
+
const NODE_EXEC_PATH_PLACEHOLDER = "__LODY_NODE_EXEC_PATH__";
|
|
136662
137382
|
const MANAGED_TOKEN_MARKER_ENV = LODY_MANAGED_GH_TOKEN_SHA256_ENV;
|
|
137383
|
+
const getWindowsExecutableCandidateNames = (name2) => [
|
|
137384
|
+
".exe",
|
|
137385
|
+
".cmd",
|
|
137386
|
+
".bat",
|
|
137387
|
+
".com"
|
|
137388
|
+
].map((ext2) => `${name2}${ext2}`).concat(name2);
|
|
136663
137389
|
const normalizeComparablePath = (value) => {
|
|
136664
137390
|
const resolved = path__default.resolve(value);
|
|
136665
137391
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
@@ -136676,6 +137402,9 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136676
137402
|
if (!statSync(filePath).isFile()) {
|
|
136677
137403
|
return false;
|
|
136678
137404
|
}
|
|
137405
|
+
if (process.platform === "win32") {
|
|
137406
|
+
return true;
|
|
137407
|
+
}
|
|
136679
137408
|
accessSync(filePath, constants$4.X_OK);
|
|
136680
137409
|
return true;
|
|
136681
137410
|
} catch {
|
|
@@ -136689,10 +137418,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
136689
137418
|
}
|
|
136690
137419
|
const excludedComparablePath = toComparablePath(excludedPath);
|
|
136691
137420
|
const excludedComparableDir = toComparablePath(path__default.dirname(excludedPath));
|
|
136692
|
-
const candidateNames = process.platform === "win32" ? [
|
|
136693
|
-
`${name2}.exe`,
|
|
136694
|
-
name2
|
|
136695
|
-
] : [
|
|
137421
|
+
const candidateNames = process.platform === "win32" ? getWindowsExecutableCandidateNames(name2) : [
|
|
136696
137422
|
name2
|
|
136697
137423
|
];
|
|
136698
137424
|
for (const dir of pathEnv.split(path__default.delimiter)) {
|
|
@@ -136729,6 +137455,7 @@ const REAL_GH_PATH = '${REAL_GH_PATH_PLACEHOLDER}';
|
|
|
136729
137455
|
const SHIM_PATH = __filename;
|
|
136730
137456
|
const SHIM_DIR = path.dirname(SHIM_PATH);
|
|
136731
137457
|
const MANAGED_TOKEN_MARKER_ENV = '${MANAGED_TOKEN_MARKER_ENV}';
|
|
137458
|
+
const WINDOWS_EXECUTABLE_CANDIDATE_NAMES = ['gh.exe', 'gh.cmd', 'gh.bat', 'gh.com', 'gh'];
|
|
136732
137459
|
|
|
136733
137460
|
const normalizeComparablePath = (value) => {
|
|
136734
137461
|
const resolved = path.resolve(String(value || ''));
|
|
@@ -136748,6 +137475,7 @@ const isExecutableFile = (filePath) => {
|
|
|
136748
137475
|
if (!filePath) return false;
|
|
136749
137476
|
try {
|
|
136750
137477
|
if (!fs.statSync(filePath).isFile()) return false;
|
|
137478
|
+
if (process.platform === 'win32') return true;
|
|
136751
137479
|
fs.accessSync(filePath, fs.constants.X_OK);
|
|
136752
137480
|
return true;
|
|
136753
137481
|
} catch {
|
|
@@ -136761,7 +137489,8 @@ const resolveGhFromPath = () => {
|
|
|
136761
137489
|
|
|
136762
137490
|
const shimComparablePath = toComparablePath(SHIM_PATH);
|
|
136763
137491
|
const shimComparableDir = toComparablePath(SHIM_DIR);
|
|
136764
|
-
const candidateNames =
|
|
137492
|
+
const candidateNames =
|
|
137493
|
+
process.platform === 'win32' ? WINDOWS_EXECUTABLE_CANDIDATE_NAMES : ['gh'];
|
|
136765
137494
|
|
|
136766
137495
|
for (const dir of pathEnv.split(path.delimiter)) {
|
|
136767
137496
|
if (!dir) continue;
|
|
@@ -136785,6 +137514,32 @@ const resolveRealGhCommand = () => {
|
|
|
136785
137514
|
return resolveGhFromPath();
|
|
136786
137515
|
};
|
|
136787
137516
|
|
|
137517
|
+
const quoteCmdArg = (arg) => {
|
|
137518
|
+
const value = String(arg || '');
|
|
137519
|
+
if (value === '') return '""';
|
|
137520
|
+
if (!/[\\s"]/u.test(value)) return value;
|
|
137521
|
+
return '"' + value.replace(/"/g, '""') + '"';
|
|
137522
|
+
};
|
|
137523
|
+
|
|
137524
|
+
const buildWindowsSpawnSpec = (command, args) => {
|
|
137525
|
+
const lower = String(command || '').toLowerCase();
|
|
137526
|
+
if (process.platform === 'win32' && (lower.endsWith('.cmd') || lower.endsWith('.bat'))) {
|
|
137527
|
+
const cmdline = [quoteCmdArg(command), ...args.map(quoteCmdArg)].join(' ');
|
|
137528
|
+
return { command: 'cmd.exe', args: ['/d', '/s', '/c', cmdline] };
|
|
137529
|
+
}
|
|
137530
|
+
return { command, args };
|
|
137531
|
+
};
|
|
137532
|
+
|
|
137533
|
+
const spawnGh = (command, args, options) => {
|
|
137534
|
+
const spec = buildWindowsSpawnSpec(command, args);
|
|
137535
|
+
return spawn(spec.command, spec.args, options);
|
|
137536
|
+
};
|
|
137537
|
+
|
|
137538
|
+
const spawnSyncGh = (command, args, options) => {
|
|
137539
|
+
const spec = buildWindowsSpawnSpec(command, args);
|
|
137540
|
+
return spawnSync(spec.command, spec.args, options);
|
|
137541
|
+
};
|
|
137542
|
+
|
|
136788
137543
|
const fingerprintToken = (token) => crypto.createHash('sha256').update(token).digest('hex');
|
|
136789
137544
|
|
|
136790
137545
|
const isManagedTokenValue = (token, marker) => {
|
|
@@ -136832,7 +137587,7 @@ const buildGhAuthEnv = (env) => {
|
|
|
136832
137587
|
const isGhCliAuthed = (ghPath) => {
|
|
136833
137588
|
if (!ghPath) return false;
|
|
136834
137589
|
try {
|
|
136835
|
-
const result =
|
|
137590
|
+
const result = spawnSyncGh(ghPath, ['auth', 'status'], {
|
|
136836
137591
|
env: buildGhAuthEnv(process.env),
|
|
136837
137592
|
stdio: ['ignore', 'ignore', 'ignore'],
|
|
136838
137593
|
timeout: 5000,
|
|
@@ -136932,30 +137687,23 @@ const isConnectionError = (error) => {
|
|
|
136932
137687
|
return message.includes('econnrefused') || message.includes('enotfound') || message.includes('fetch failed');
|
|
136933
137688
|
};
|
|
136934
137689
|
|
|
136935
|
-
const
|
|
137690
|
+
const doBrokerRequest = async (baseUrl, brokerToken, endpoint, body, timeoutMs) => {
|
|
136936
137691
|
const fetchImpl = globalThis.fetch;
|
|
136937
|
-
if (typeof fetchImpl !== 'function') return {
|
|
137692
|
+
if (typeof fetchImpl !== 'function') return { unavailable: true };
|
|
136938
137693
|
|
|
136939
137694
|
const controller = new AbortController();
|
|
136940
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
137695
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
136941
137696
|
try {
|
|
136942
|
-
const res = await fetchImpl(baseUrl +
|
|
137697
|
+
const res = await fetchImpl(baseUrl + endpoint, {
|
|
136943
137698
|
method: 'POST',
|
|
136944
137699
|
headers: {
|
|
136945
137700
|
'Content-Type': 'application/json',
|
|
136946
137701
|
Authorization: 'Bearer ' + brokerToken,
|
|
136947
137702
|
},
|
|
136948
|
-
body: JSON.stringify(
|
|
137703
|
+
body: JSON.stringify(body),
|
|
136949
137704
|
signal: controller.signal,
|
|
136950
137705
|
});
|
|
136951
|
-
|
|
136952
|
-
return { result: null };
|
|
136953
|
-
}
|
|
136954
|
-
const json = await res.json().catch(() => null);
|
|
136955
|
-
if (!json || typeof json.token !== 'string' || !json.token) {
|
|
136956
|
-
return { result: null };
|
|
136957
|
-
}
|
|
136958
|
-
return { result: { token: json.token } };
|
|
137706
|
+
return { res };
|
|
136959
137707
|
} catch (error) {
|
|
136960
137708
|
return { error };
|
|
136961
137709
|
} finally {
|
|
@@ -136963,51 +137711,105 @@ const doFetchFromBroker = async (baseUrl, brokerToken, repoFullName) => {
|
|
|
136963
137711
|
}
|
|
136964
137712
|
};
|
|
136965
137713
|
|
|
136966
|
-
const
|
|
137714
|
+
const doFetchFromBroker = async (baseUrl, brokerToken, repoFullName) => {
|
|
137715
|
+
const reply = await doBrokerRequest(
|
|
137716
|
+
baseUrl,
|
|
137717
|
+
brokerToken,
|
|
137718
|
+
'/github-token',
|
|
137719
|
+
{ repoFullName },
|
|
137720
|
+
10000
|
|
137721
|
+
);
|
|
137722
|
+
if (reply.unavailable) return { result: null };
|
|
137723
|
+
if (reply.error) return { error: reply.error };
|
|
137724
|
+
if (!reply.res.ok) return { result: null };
|
|
137725
|
+
const json = await reply.res.json().catch(() => null);
|
|
137726
|
+
if (!json || typeof json.token !== 'string' || !json.token) {
|
|
137727
|
+
return { result: null };
|
|
137728
|
+
}
|
|
137729
|
+
return { result: { token: json.token } };
|
|
137730
|
+
};
|
|
137731
|
+
|
|
137732
|
+
const doRejectToBroker = async (baseUrl, brokerToken, repoFullName, invalidatedToken) => {
|
|
137733
|
+
// Short timeout: the gh shim awaits this before exiting, so a slow broker would stall
|
|
137734
|
+
// the user. The next gh invocation will re-trigger reject if delivery here fails.
|
|
137735
|
+
const reply = await doBrokerRequest(
|
|
137736
|
+
baseUrl,
|
|
137737
|
+
brokerToken,
|
|
137738
|
+
'/github-token/reject',
|
|
137739
|
+
{ repoFullName, ...(invalidatedToken ? { invalidatedToken } : {}) },
|
|
137740
|
+
2000
|
|
137741
|
+
);
|
|
137742
|
+
if (reply.unavailable) return { result: false };
|
|
137743
|
+
if (reply.error) return { error: reply.error };
|
|
137744
|
+
return { result: reply.res.ok };
|
|
137745
|
+
};
|
|
137746
|
+
|
|
137747
|
+
const callBrokerWithFallback = async (action) => {
|
|
136967
137748
|
const brokerConfig = getBrokerConfig();
|
|
136968
137749
|
if (!brokerConfig) return null;
|
|
136969
137750
|
|
|
136970
137751
|
const { url, token, source } = brokerConfig;
|
|
136971
|
-
const first = await
|
|
136972
|
-
if (first.result !== undefined)
|
|
136973
|
-
return first.result;
|
|
136974
|
-
}
|
|
137752
|
+
const first = await action(url, token);
|
|
137753
|
+
if (first.result !== undefined) return first;
|
|
136975
137754
|
|
|
136976
137755
|
if (first.error && source === 'env' && isConnectionError(first.error)) {
|
|
136977
137756
|
const fileConfig = getBrokerConfigFromFile();
|
|
136978
137757
|
if (fileConfig && fileConfig.url !== url) {
|
|
136979
|
-
|
|
136980
|
-
if (fallback.result !== undefined) {
|
|
136981
|
-
return fallback.result;
|
|
136982
|
-
}
|
|
137758
|
+
return await action(fileConfig.url, fileConfig.token);
|
|
136983
137759
|
}
|
|
136984
137760
|
}
|
|
137761
|
+
return first;
|
|
137762
|
+
};
|
|
136985
137763
|
|
|
136986
|
-
|
|
137764
|
+
const fetchTokenFromBroker = async (repoFullName) => {
|
|
137765
|
+
const reply = await callBrokerWithFallback((url, token) =>
|
|
137766
|
+
doFetchFromBroker(url, token, repoFullName)
|
|
137767
|
+
);
|
|
137768
|
+
return reply && reply.result ? reply.result : null;
|
|
137769
|
+
};
|
|
137770
|
+
|
|
137771
|
+
const rejectTokenToBroker = async (repoFullName, invalidatedToken) => {
|
|
137772
|
+
await callBrokerWithFallback((url, token) =>
|
|
137773
|
+
doRejectToBroker(url, token, repoFullName, invalidatedToken)
|
|
137774
|
+
);
|
|
137775
|
+
};
|
|
137776
|
+
|
|
137777
|
+
const GH_AUTH_FAILURE_PHRASES = [
|
|
137778
|
+
'http 401',
|
|
137779
|
+
'401 unauthorized',
|
|
137780
|
+
'bad credentials',
|
|
137781
|
+
'requires authentication',
|
|
137782
|
+
'authentication failed',
|
|
137783
|
+
];
|
|
137784
|
+
|
|
137785
|
+
const isGhAuthFailureOutput = (stderrText) => {
|
|
137786
|
+
const value = String(stderrText || '').toLowerCase();
|
|
137787
|
+
return GH_AUTH_FAILURE_PHRASES.some((phrase) => value.includes(phrase));
|
|
136987
137788
|
};
|
|
136988
137789
|
|
|
136989
137790
|
const buildGhEnv = async (ghCommand) => {
|
|
136990
137791
|
const env = { ...process.env };
|
|
136991
137792
|
if (hasUserProvidedEnvToken(env)) {
|
|
136992
137793
|
clearManagedTokenEnv(env);
|
|
136993
|
-
return env;
|
|
137794
|
+
return { env };
|
|
136994
137795
|
}
|
|
136995
137796
|
|
|
136996
137797
|
if (isGhCliAuthed(ghCommand)) {
|
|
136997
137798
|
clearManagedTokenEnv(env);
|
|
136998
|
-
return env;
|
|
137799
|
+
return { env };
|
|
136999
137800
|
}
|
|
137000
137801
|
|
|
137001
137802
|
const repoFullName = readRepoFullName();
|
|
137002
137803
|
if (!repoFullName) {
|
|
137003
|
-
return env;
|
|
137804
|
+
return { env };
|
|
137004
137805
|
}
|
|
137005
137806
|
|
|
137006
137807
|
const result = await fetchTokenFromBroker(repoFullName);
|
|
137007
137808
|
if (result && result.token) {
|
|
137008
137809
|
injectGhToken(env, result.token);
|
|
137810
|
+
return { env, managed: { token: result.token, repoFullName } };
|
|
137009
137811
|
}
|
|
137010
|
-
return env;
|
|
137812
|
+
return { env };
|
|
137011
137813
|
};
|
|
137012
137814
|
|
|
137013
137815
|
const main = async () => {
|
|
@@ -137017,30 +137819,51 @@ const main = async () => {
|
|
|
137017
137819
|
process.exit(127);
|
|
137018
137820
|
}
|
|
137019
137821
|
|
|
137020
|
-
const
|
|
137021
|
-
|
|
137022
|
-
|
|
137822
|
+
const ghEnv = await buildGhEnv(ghCommand);
|
|
137823
|
+
const child = spawnGh(ghCommand, process.argv.slice(2), {
|
|
137824
|
+
stdio: ['inherit', 'inherit', 'pipe'],
|
|
137825
|
+
env: ghEnv.env,
|
|
137826
|
+
});
|
|
137827
|
+
let stderrText = '';
|
|
137828
|
+
child.stderr.on('data', (chunk) => {
|
|
137829
|
+
const text = String(chunk || '');
|
|
137830
|
+
process.stderr.write(chunk);
|
|
137831
|
+
if (stderrText.length < 20000) {
|
|
137832
|
+
stderrText += text.slice(0, 20000 - stderrText.length);
|
|
137833
|
+
}
|
|
137023
137834
|
});
|
|
137024
137835
|
|
|
137025
137836
|
child.on('error', () => process.exit(127));
|
|
137026
137837
|
child.on('close', (code, signal) => {
|
|
137027
|
-
|
|
137028
|
-
|
|
137029
|
-
|
|
137030
|
-
|
|
137031
|
-
|
|
137838
|
+
void (async () => {
|
|
137839
|
+
if (code && ghEnv.managed && isGhAuthFailureOutput(stderrText)) {
|
|
137840
|
+
await rejectTokenToBroker(ghEnv.managed.repoFullName, ghEnv.managed.token);
|
|
137841
|
+
}
|
|
137842
|
+
if (signal) {
|
|
137843
|
+
process.kill(process.pid, signal);
|
|
137844
|
+
return;
|
|
137845
|
+
}
|
|
137846
|
+
process.exit(code ?? 1);
|
|
137847
|
+
})();
|
|
137032
137848
|
});
|
|
137033
137849
|
};
|
|
137034
137850
|
|
|
137035
137851
|
main().catch(() => process.exit(1));
|
|
137852
|
+
`;
|
|
137853
|
+
const windowsLauncherSourceTemplate = `@echo off
|
|
137854
|
+
"${NODE_EXEC_PATH_PLACEHOLDER}" "%~dp0gh" %*
|
|
137036
137855
|
`;
|
|
137037
137856
|
const getGhShimHostBinDir = () => path__default.join(os__default.homedir(), ".lody", "bin");
|
|
137038
|
-
const
|
|
137857
|
+
const getGhShimHostNodeScriptPath = () => path__default.join(getGhShimHostBinDir(), GH_SHIM_POSIX_BASENAME);
|
|
137858
|
+
const getGhShimHostWindowsLauncherPath = () => path__default.join(getGhShimHostBinDir(), GH_SHIM_WINDOWS_BASENAME);
|
|
137859
|
+
const getGhShimHostPath = () => process.platform === "win32" ? getGhShimHostWindowsLauncherPath() : getGhShimHostNodeScriptPath();
|
|
137039
137860
|
const escapeForSingleQuotedString = (value) => value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
137861
|
+
const escapeForDoubleQuotedCmdString = (value) => value.replace(/"/g, '""');
|
|
137040
137862
|
const buildGhShimSource = (realGhPath) => {
|
|
137041
137863
|
const escapedRealPath = realGhPath ? escapeForSingleQuotedString(realGhPath) : "";
|
|
137042
137864
|
return wrapperSourceTemplate.split(REAL_GH_PATH_PLACEHOLDER).join(escapedRealPath);
|
|
137043
137865
|
};
|
|
137866
|
+
const buildWindowsLauncherSource = () => windowsLauncherSourceTemplate.split(NODE_EXEC_PATH_PLACEHOLDER).join(escapeForDoubleQuotedCmdString(process.execPath));
|
|
137044
137867
|
const resolveRealGhPath = () => resolveExecutableFromPath("gh", getGhShimHostPath());
|
|
137045
137868
|
const ensureParentDirForFile = (filePath) => {
|
|
137046
137869
|
const dir = path__default.dirname(filePath);
|
|
@@ -137082,19 +137905,35 @@ main().catch(() => process.exit(1));
|
|
|
137082
137905
|
}
|
|
137083
137906
|
};
|
|
137084
137907
|
const ensureGhShimScript = () => {
|
|
137085
|
-
const filePath = getGhShimHostPath();
|
|
137086
|
-
ensureParentDirForFile(filePath);
|
|
137087
|
-
ensureWritableShimTarget(filePath);
|
|
137088
137908
|
const source = buildGhShimSource(resolveRealGhPath());
|
|
137089
|
-
|
|
137090
|
-
|
|
137091
|
-
|
|
137092
|
-
|
|
137093
|
-
|
|
137094
|
-
|
|
137909
|
+
const shimTargets = process.platform === "win32" ? [
|
|
137910
|
+
{
|
|
137911
|
+
filePath: getGhShimHostNodeScriptPath(),
|
|
137912
|
+
content: source
|
|
137913
|
+
},
|
|
137914
|
+
{
|
|
137915
|
+
filePath: getGhShimHostWindowsLauncherPath(),
|
|
137916
|
+
content: buildWindowsLauncherSource()
|
|
137095
137917
|
}
|
|
137918
|
+
] : [
|
|
137919
|
+
{
|
|
137920
|
+
filePath: getGhShimHostNodeScriptPath(),
|
|
137921
|
+
content: source
|
|
137922
|
+
}
|
|
137923
|
+
];
|
|
137924
|
+
for (const { filePath, content } of shimTargets) {
|
|
137096
137925
|
ensureParentDirForFile(filePath);
|
|
137097
|
-
|
|
137926
|
+
ensureWritableShimTarget(filePath);
|
|
137927
|
+
try {
|
|
137928
|
+
writeIfChanged(filePath, content, 493);
|
|
137929
|
+
} catch (error2) {
|
|
137930
|
+
const code2 = error2 instanceof Error && "code" in error2 ? error2.code : void 0;
|
|
137931
|
+
if (code2 !== "ENOENT") {
|
|
137932
|
+
throw error2;
|
|
137933
|
+
}
|
|
137934
|
+
ensureParentDirForFile(filePath);
|
|
137935
|
+
writeIfChanged(filePath, content, 493);
|
|
137936
|
+
}
|
|
137098
137937
|
}
|
|
137099
137938
|
};
|
|
137100
137939
|
const prependGhShimBinDirToPath = (pathEnv) => {
|
|
@@ -142405,13 +143244,11 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
142405
143244
|
LODY_SESSION_ID: this.sessionId,
|
|
142406
143245
|
LODY_WORKSPACE_SESSION_ID: workspaceSessionId
|
|
142407
143246
|
};
|
|
142408
|
-
|
|
142409
|
-
|
|
142410
|
-
|
|
142411
|
-
|
|
142412
|
-
|
|
142413
|
-
}
|
|
142414
|
-
return merged;
|
|
143247
|
+
const agentEnv = this.config.agentCliType === "builtin" && this.config.agentType === "claude" ? scrubInheritedClaudeAuthEnv(merged, {
|
|
143248
|
+
...configEnv,
|
|
143249
|
+
...extraEnv
|
|
143250
|
+
}) : merged;
|
|
143251
|
+
return withDefaultAcpPathEntries(agentEnv);
|
|
142415
143252
|
}
|
|
142416
143253
|
async createAgent(callbacks) {
|
|
142417
143254
|
const env2 = this.buildShellEnv(callbacks.env);
|
|
@@ -142491,6 +143328,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
142491
143328
|
onRateLimitUpdate: callbacks.onRateLimitUpdate,
|
|
142492
143329
|
onThreadGoalUpdated: callbacks.onThreadGoalUpdated,
|
|
142493
143330
|
onThreadGoalCleared: callbacks.onThreadGoalCleared,
|
|
143331
|
+
onCodexProposedPlan: callbacks.onCodexProposedPlan,
|
|
142494
143332
|
onCodexImageGenerationBegin: callbacks.onCodexImageGenerationBegin,
|
|
142495
143333
|
onCodexImageGenerationEnd: callbacks.onCodexImageGenerationEnd,
|
|
142496
143334
|
sessionId: this.sessionId,
|
|
@@ -142719,7 +143557,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
142719
143557
|
const sessionId = config2.sessionId;
|
|
142720
143558
|
this.logger.debug(`[${sessionId}] Session workdir resolved: ${session.getWorkdir()}`);
|
|
142721
143559
|
let acpSessionId;
|
|
142722
|
-
const
|
|
143560
|
+
const launch = resolveACPProcessLaunch({
|
|
142723
143561
|
cliType: config2.agentCliType,
|
|
142724
143562
|
agentType: config2.agentType
|
|
142725
143563
|
});
|
|
@@ -142736,9 +143574,9 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
142736
143574
|
acpSessionId = await withSlowOperationWarning(session.createAgent({
|
|
142737
143575
|
cliType: config2.agentCliType,
|
|
142738
143576
|
agentType: config2.agentType,
|
|
142739
|
-
command:
|
|
142740
|
-
args:
|
|
142741
|
-
env:
|
|
143577
|
+
command: launch.command,
|
|
143578
|
+
args: launch.args,
|
|
143579
|
+
env: launch.env,
|
|
142742
143580
|
resumeSessionId: requestedResumeSessionId,
|
|
142743
143581
|
onStartupStage: (event) => {
|
|
142744
143582
|
if (event.type === "initialize_start") {
|
|
@@ -142787,6 +143625,9 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
142787
143625
|
onThreadGoalCleared: (threadId2) => {
|
|
142788
143626
|
this.emit("onThreadGoalCleared", sessionId, threadId2);
|
|
142789
143627
|
},
|
|
143628
|
+
onCodexProposedPlan: (plan) => {
|
|
143629
|
+
this.emit("onCodexProposedPlan", sessionId, plan);
|
|
143630
|
+
},
|
|
142790
143631
|
onCodexImageGenerationBegin: (event) => {
|
|
142791
143632
|
this.emit("onCodexImageGenerationBegin", sessionId, event);
|
|
142792
143633
|
},
|
|
@@ -142838,7 +143679,10 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
142838
143679
|
tokenManager?.retainRepoOwner(githubRepo);
|
|
142839
143680
|
if (tokenManager) {
|
|
142840
143681
|
try {
|
|
142841
|
-
|
|
143682
|
+
tokenManager.invalidate(githubRepo);
|
|
143683
|
+
await tokenManager.getTokenForRepo(githubRepo, {
|
|
143684
|
+
operation: "write"
|
|
143685
|
+
});
|
|
142842
143686
|
this.logger.debug(`[${config2.sessionId}] [github-token] Prefetch succeeded for ${githubRepo}`);
|
|
142843
143687
|
} catch (error2) {
|
|
142844
143688
|
this.logger.debug(`[${config2.sessionId}] [github-token] Prefetch failed for ${githubRepo}: ${formatErrorMessage(error2)}`);
|
|
@@ -142906,6 +143750,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
142906
143750
|
return;
|
|
142907
143751
|
}
|
|
142908
143752
|
try {
|
|
143753
|
+
tokenManager.invalidate(githubRepo);
|
|
142909
143754
|
const token2 = await tokenManager.getTokenForRepo(githubRepo, {
|
|
142910
143755
|
operation: "write"
|
|
142911
143756
|
});
|