lody 0.92.1 → 0.93.2
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/chunks/{acp-DBqkNziA.js → acp-DCoAUZc7.js} +1 -1
- package/dist/chunks/{directory-handle-Bp47LF5g.js → directory-handle-35P9qcGk.js} +1 -1
- package/dist/chunks/{index-Cy4lnlSp.js → index-Bxge7nr7.js} +396 -100
- package/dist/chunks/plan-mode-BLOER-fv.js +14 -0
- package/dist/chunks/{profile-DLuYzIs8.js → profile-Dv5auBPt.js} +7 -2
- package/dist/chunks/{review-viewer-DqtXyKjy.js → review-viewer-N1aeovLR.js} +7 -6
- package/dist/chunks/{runtime-manifest-DnyvD_EC.js → runtime-manifest-FeOT7MvW.js} +1 -1
- package/dist/chunks/{schemas-Du3qLZPS.js → schemas-C-NzK2uQ.js} +195 -155
- package/dist/claude-acp.js +2 -2
- package/dist/codex-acp.js +1 -1
- package/dist/deepseek-acp.js +26 -3
- package/dist/file-index-scan-worker.js +2 -2
- package/dist/grok-acp.js +219 -46
- package/dist/index.js +5912 -4316
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import { Writable, Readable } from "node:stream";
|
|
|
5
5
|
import { StringDecoder } from "node:string_decoder";
|
|
6
6
|
import fs__default from "node:fs";
|
|
7
7
|
import path__default from "node:path";
|
|
8
|
-
import Xt__default, { constants, readFile } from "node:fs/promises";
|
|
8
|
+
import Xt__default, { constants, readFile, realpath } from "node:fs/promises";
|
|
9
9
|
import { randomUUID, createHash } from "node:crypto";
|
|
10
10
|
import process$1 from "node:process";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
@@ -3418,7 +3418,7 @@ var require_main = __commonJS({
|
|
|
3418
3418
|
exports$1.createMessageConnection = createMessageConnection2;
|
|
3419
3419
|
var ril_1 = __importDefault(require_ril());
|
|
3420
3420
|
ril_1.default.install();
|
|
3421
|
-
var
|
|
3421
|
+
var path10 = __importStar(__require("path"));
|
|
3422
3422
|
var os2 = __importStar(__require("os"));
|
|
3423
3423
|
var fs8 = __importStar(__require("fs"));
|
|
3424
3424
|
var crypto_1 = __require("crypto");
|
|
@@ -3570,7 +3570,7 @@ var require_main = __commonJS({
|
|
|
3570
3570
|
throw new Error(`Unable to generate a random pipe name with ${randomLength} characters.`);
|
|
3571
3571
|
}
|
|
3572
3572
|
const randomSuffix = (0, crypto_1.randomBytes)(Math.floor(randomLength / 2)).toString("hex");
|
|
3573
|
-
return
|
|
3573
|
+
return path10.join(tmpDir, `lsp-${randomSuffix}.sock`);
|
|
3574
3574
|
}
|
|
3575
3575
|
function createClientPipeTransport(pipeName, encoding = "utf-8") {
|
|
3576
3576
|
let connectResolve;
|
|
@@ -4461,10 +4461,10 @@ function mergeDefs(...defs) {
|
|
|
4461
4461
|
function cloneDef(schema) {
|
|
4462
4462
|
return mergeDefs(schema._zod.def);
|
|
4463
4463
|
}
|
|
4464
|
-
function getElementAtPath(obj,
|
|
4465
|
-
if (!
|
|
4464
|
+
function getElementAtPath(obj, path10) {
|
|
4465
|
+
if (!path10)
|
|
4466
4466
|
return obj;
|
|
4467
|
-
return
|
|
4467
|
+
return path10.reduce((acc, key) => acc?.[key], obj);
|
|
4468
4468
|
}
|
|
4469
4469
|
function promiseAllObject(promisesObj) {
|
|
4470
4470
|
const keys = Object.keys(promisesObj);
|
|
@@ -4847,11 +4847,11 @@ function aborted(x, startIndex = 0) {
|
|
|
4847
4847
|
}
|
|
4848
4848
|
return false;
|
|
4849
4849
|
}
|
|
4850
|
-
function prefixIssues(
|
|
4850
|
+
function prefixIssues(path10, issues) {
|
|
4851
4851
|
return issues.map((iss) => {
|
|
4852
4852
|
var _a2;
|
|
4853
4853
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
4854
|
-
iss.path.unshift(
|
|
4854
|
+
iss.path.unshift(path10);
|
|
4855
4855
|
return iss;
|
|
4856
4856
|
});
|
|
4857
4857
|
}
|
|
@@ -5032,7 +5032,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
5032
5032
|
}
|
|
5033
5033
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
5034
5034
|
const result = { errors: [] };
|
|
5035
|
-
const processError = (error49,
|
|
5035
|
+
const processError = (error49, path10 = []) => {
|
|
5036
5036
|
var _a2, _b;
|
|
5037
5037
|
for (const issue2 of error49.issues) {
|
|
5038
5038
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -5042,7 +5042,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
5042
5042
|
} else if (issue2.code === "invalid_element") {
|
|
5043
5043
|
processError({ issues: issue2.issues }, issue2.path);
|
|
5044
5044
|
} else {
|
|
5045
|
-
const fullpath = [...
|
|
5045
|
+
const fullpath = [...path10, ...issue2.path];
|
|
5046
5046
|
if (fullpath.length === 0) {
|
|
5047
5047
|
result.errors.push(mapper(issue2));
|
|
5048
5048
|
continue;
|
|
@@ -5074,8 +5074,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
5074
5074
|
}
|
|
5075
5075
|
function toDotPath(_path) {
|
|
5076
5076
|
const segs = [];
|
|
5077
|
-
const
|
|
5078
|
-
for (const seg of
|
|
5077
|
+
const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5078
|
+
for (const seg of path10) {
|
|
5079
5079
|
if (typeof seg === "number")
|
|
5080
5080
|
segs.push(`[${seg}]`);
|
|
5081
5081
|
else if (typeof seg === "symbol")
|
|
@@ -16910,13 +16910,13 @@ function resolveRef(ref, ctx) {
|
|
|
16910
16910
|
if (!ref.startsWith("#")) {
|
|
16911
16911
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
16912
16912
|
}
|
|
16913
|
-
const
|
|
16914
|
-
if (
|
|
16913
|
+
const path10 = ref.slice(1).split("/").filter(Boolean);
|
|
16914
|
+
if (path10.length === 0) {
|
|
16915
16915
|
return ctx.rootSchema;
|
|
16916
16916
|
}
|
|
16917
16917
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
16918
|
-
if (
|
|
16919
|
-
const key =
|
|
16918
|
+
if (path10[0] === defsKey) {
|
|
16919
|
+
const key = path10[1];
|
|
16920
16920
|
if (!key || !ctx.defs[key]) {
|
|
16921
16921
|
throw new Error(`Reference not found: ${ref}`);
|
|
16922
16922
|
}
|
|
@@ -21033,7 +21033,32 @@ var LODY_EXTENSION_METHODS = {
|
|
|
21033
21033
|
var LODY_TOOL_NAMES = {
|
|
21034
21034
|
imageGeneration: "ImageGeneration"
|
|
21035
21035
|
};
|
|
21036
|
+
var LODY_PLAN_MODE_CONFIG_ID = "plan_mode";
|
|
21037
|
+
function createPlanModeConfigOption(currentValue) {
|
|
21038
|
+
return {
|
|
21039
|
+
id: LODY_PLAN_MODE_CONFIG_ID,
|
|
21040
|
+
name: "Plan",
|
|
21041
|
+
description: "Plan before implementing; permissions are controlled separately.",
|
|
21042
|
+
type: "boolean",
|
|
21043
|
+
currentValue
|
|
21044
|
+
};
|
|
21045
|
+
}
|
|
21046
|
+
var GOAL_EXTENSION_VERSION = 1;
|
|
21036
21047
|
var GOAL_CONTROL_METHOD = LODY_EXTENSION_METHODS.sessionGoal;
|
|
21048
|
+
function parseGoalPromptControl(meta3) {
|
|
21049
|
+
if (typeof meta3 !== "object" || meta3 === null) return null;
|
|
21050
|
+
const lody = meta3["lody"];
|
|
21051
|
+
if (typeof lody !== "object" || lody === null) return null;
|
|
21052
|
+
const control = lody["goalControl"];
|
|
21053
|
+
if (typeof control !== "object" || control === null) return null;
|
|
21054
|
+
const { version: version2, action, objective } = control;
|
|
21055
|
+
if (version2 !== GOAL_EXTENSION_VERSION) return null;
|
|
21056
|
+
if (action === "pause" || action === "resume" || action === "clear") {
|
|
21057
|
+
return { version: GOAL_EXTENSION_VERSION, action };
|
|
21058
|
+
}
|
|
21059
|
+
if (action !== "set") return null;
|
|
21060
|
+
return typeof objective === "string" && objective.trim().length > 0 ? { version: GOAL_EXTENSION_VERSION, action: "set", objective } : null;
|
|
21061
|
+
}
|
|
21037
21062
|
var ASYNC_TASK_STOP_METHOD = "_session/async_task/stop";
|
|
21038
21063
|
var AUTH_STATUS_UPDATE_METHOD = "_auth/status_update";
|
|
21039
21064
|
var AUTH_STATUS_META_KEY = "authStatus";
|
|
@@ -21185,9 +21210,17 @@ var CODEX_LODY_CAPABILITIES = {
|
|
|
21185
21210
|
},
|
|
21186
21211
|
tasks: { version: 1, background: true },
|
|
21187
21212
|
subagents: { version: 1, lifecycle: true },
|
|
21188
|
-
goal: {
|
|
21213
|
+
goal: {
|
|
21214
|
+
version: 1,
|
|
21215
|
+
actions: ["set", "pause", "resume", "clear"],
|
|
21216
|
+
// Status-only actions are safe mid-prompt; anything that starts work
|
|
21217
|
+
// needs the client's prompt to own the turns it produces.
|
|
21218
|
+
controlActions: ["pause", "clear"],
|
|
21219
|
+
promptActions: ["set", "pause", "resume", "clear"]
|
|
21220
|
+
},
|
|
21189
21221
|
compaction: { version: 1 },
|
|
21190
|
-
sessionHistory: { version: 1 }
|
|
21222
|
+
sessionHistory: { version: 1 },
|
|
21223
|
+
worktreeProject: { version: 1 }
|
|
21191
21224
|
};
|
|
21192
21225
|
function getLodyForkTurnId(meta3) {
|
|
21193
21226
|
if (typeof meta3 !== "object" || meta3 === null) return null;
|
|
@@ -22342,13 +22375,13 @@ function createTerminalCommandEvent(event, terminalId, cwd) {
|
|
|
22342
22375
|
}
|
|
22343
22376
|
};
|
|
22344
22377
|
}
|
|
22345
|
-
function createSearchTitle(query,
|
|
22346
|
-
if (query &&
|
|
22347
|
-
return `Search for '${query}' in ${
|
|
22378
|
+
function createSearchTitle(query, path10) {
|
|
22379
|
+
if (query && path10) {
|
|
22380
|
+
return `Search for '${query}' in ${path10}`;
|
|
22348
22381
|
} else if (query) {
|
|
22349
22382
|
return `Search for '${query}'`;
|
|
22350
|
-
} else if (
|
|
22351
|
-
return `Search in '${
|
|
22383
|
+
} else if (path10) {
|
|
22384
|
+
return `Search in '${path10}'`;
|
|
22352
22385
|
}
|
|
22353
22386
|
return "Search";
|
|
22354
22387
|
}
|
|
@@ -22576,12 +22609,12 @@ function revertPatch(unifiedDiff) {
|
|
|
22576
22609
|
if (!patch) return null;
|
|
22577
22610
|
return reversePatch(patch);
|
|
22578
22611
|
}
|
|
22579
|
-
function createUpdateDiffContent(
|
|
22612
|
+
function createUpdateDiffContent(path10, oldText, newText) {
|
|
22580
22613
|
return {
|
|
22581
22614
|
type: "diff",
|
|
22582
22615
|
oldText,
|
|
22583
22616
|
newText,
|
|
22584
|
-
path:
|
|
22617
|
+
path: path10,
|
|
22585
22618
|
_meta: {
|
|
22586
22619
|
kind: "update"
|
|
22587
22620
|
}
|
|
@@ -22798,16 +22831,16 @@ function clientSupportsAirCapability(capabilities, capability) {
|
|
|
22798
22831
|
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
22799
22832
|
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
22800
22833
|
}
|
|
22801
|
-
function normalizeAgentPath(
|
|
22802
|
-
const normalized =
|
|
22834
|
+
function normalizeAgentPath(path10) {
|
|
22835
|
+
const normalized = path10.trim().replace(/\/+$/, "");
|
|
22803
22836
|
return normalized || "/root";
|
|
22804
22837
|
}
|
|
22805
|
-
function isRootAgentPath(
|
|
22806
|
-
const normalized = normalizeAgentPath(
|
|
22838
|
+
function isRootAgentPath(path10) {
|
|
22839
|
+
const normalized = normalizeAgentPath(path10);
|
|
22807
22840
|
return normalized === "/root" || normalized === "root";
|
|
22808
22841
|
}
|
|
22809
|
-
function nameFromAgentPath(
|
|
22810
|
-
const normalized = normalizeAgentPath(
|
|
22842
|
+
function nameFromAgentPath(path10, fallback) {
|
|
22843
|
+
const normalized = normalizeAgentPath(path10);
|
|
22811
22844
|
const name = normalized.slice(normalized.lastIndexOf("/") + 1).trim();
|
|
22812
22845
|
if (!name) return fallback;
|
|
22813
22846
|
const words = name.replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
@@ -23040,11 +23073,11 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
|
23040
23073
|
const child = this.children.get(threadId);
|
|
23041
23074
|
return child && child.terminalState === void 0 ? [{ threadId, sessionId: child.sessionId }] : [];
|
|
23042
23075
|
}
|
|
23043
|
-
async materialize(childSessionId,
|
|
23076
|
+
async materialize(childSessionId, path10) {
|
|
23044
23077
|
if (this.children.has(childSessionId)) return;
|
|
23045
23078
|
const pending = this.pendingSpawns.get(childSessionId);
|
|
23046
|
-
const name = nameFromAgentPath(
|
|
23047
|
-
const inferredParent = this.parentForPath(
|
|
23079
|
+
const name = nameFromAgentPath(path10, fallbackName(childSessionId));
|
|
23080
|
+
const inferredParent = this.parentForPath(path10);
|
|
23048
23081
|
const parentThreadId = pending?.parentThreadId ?? inferredParent.threadId;
|
|
23049
23082
|
const parentSessionId = pending?.parentSessionId ?? inferredParent.sessionId;
|
|
23050
23083
|
const task = pending?.task ?? `Delegated task for ${name}`;
|
|
@@ -23061,7 +23094,7 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
|
23061
23094
|
sessionId: childSessionId,
|
|
23062
23095
|
name,
|
|
23063
23096
|
task,
|
|
23064
|
-
path: normalizeAgentPath(
|
|
23097
|
+
path: normalizeAgentPath(path10),
|
|
23065
23098
|
generation: 1
|
|
23066
23099
|
});
|
|
23067
23100
|
this.pendingSpawns.delete(childSessionId);
|
|
@@ -23152,8 +23185,8 @@ var CodexSubagentEventRouter = class _CodexSubagentEventRouter {
|
|
|
23152
23185
|
for (const waiter of this.waiters) waiter();
|
|
23153
23186
|
this.waiters.clear();
|
|
23154
23187
|
}
|
|
23155
|
-
parentForPath(
|
|
23156
|
-
const normalized = normalizeAgentPath(
|
|
23188
|
+
parentForPath(path10) {
|
|
23189
|
+
const normalized = normalizeAgentPath(path10);
|
|
23157
23190
|
const separator = normalized.lastIndexOf("/");
|
|
23158
23191
|
if (separator <= 0) return { threadId: this.rootSessionId, sessionId: this.rootSessionId };
|
|
23159
23192
|
const parentPath = normalized.slice(0, separator);
|
|
@@ -24866,7 +24899,7 @@ function permissionProfileContent(permissions) {
|
|
|
24866
24899
|
return lines.length > 0 ? [textContent(lines.join("\n"))] : [];
|
|
24867
24900
|
}
|
|
24868
24901
|
function locationsField(paths) {
|
|
24869
|
-
return paths.length > 0 ? { locations: paths.map((
|
|
24902
|
+
return paths.length > 0 ? { locations: paths.map((path10) => ({ path: path10 })) } : {};
|
|
24870
24903
|
}
|
|
24871
24904
|
function textContent(text) {
|
|
24872
24905
|
return { type: "content", content: { type: "text", text } };
|
|
@@ -25709,6 +25742,78 @@ function getCodexAuthMethods(clientCapabilities, env = process.env) {
|
|
|
25709
25742
|
function isCodexAuthRequest(request) {
|
|
25710
25743
|
return request.methodId === "api-key" || request.methodId === "chat-gpt" || request.methodId === "chat-gpt-device-code" || request.methodId === "gateway";
|
|
25711
25744
|
}
|
|
25745
|
+
function readWorktreeProject(meta3) {
|
|
25746
|
+
if (typeof meta3 !== "object" || meta3 === null) return void 0;
|
|
25747
|
+
const lody = meta3["lody"];
|
|
25748
|
+
if (typeof lody !== "object" || lody === null) return void 0;
|
|
25749
|
+
const value = lody["worktreeProject"];
|
|
25750
|
+
if (value === void 0) return void 0;
|
|
25751
|
+
if (typeof value === "object" && value !== null) {
|
|
25752
|
+
const project = value;
|
|
25753
|
+
if (project["version"] === 1 && typeof project["originProjectPath"] === "string" && path__default.isAbsolute(project["originProjectPath"]) && !project["originProjectPath"].includes("\0")) {
|
|
25754
|
+
return { version: 1, originProjectPath: project["originProjectPath"] };
|
|
25755
|
+
}
|
|
25756
|
+
}
|
|
25757
|
+
throw RequestError.invalidParams(void 0, "worktreeProject requires version 1 and an absolute originProjectPath");
|
|
25758
|
+
}
|
|
25759
|
+
var WorktreeProjects = class {
|
|
25760
|
+
constructor(client) {
|
|
25761
|
+
this.client = client;
|
|
25762
|
+
}
|
|
25763
|
+
client;
|
|
25764
|
+
async resolve(project) {
|
|
25765
|
+
if (!project) return void 0;
|
|
25766
|
+
const originProjectPath = await realpath(project.originProjectPath);
|
|
25767
|
+
const key = projectRootKey(originProjectPath);
|
|
25768
|
+
return this.findOrCreate(originProjectPath, key);
|
|
25769
|
+
}
|
|
25770
|
+
async assign(thread, project, preserveExisting) {
|
|
25771
|
+
if (!project || preserveExisting && thread.projectId) return;
|
|
25772
|
+
const projectId = await this.resolve(project);
|
|
25773
|
+
if (projectId && projectId !== thread.projectId) {
|
|
25774
|
+
await this.client.threadProjectUpdate({ threadId: thread.id, projectId });
|
|
25775
|
+
}
|
|
25776
|
+
}
|
|
25777
|
+
async findOrCreate(originProjectPath, key) {
|
|
25778
|
+
let cursor;
|
|
25779
|
+
const matches = /* @__PURE__ */ new Set();
|
|
25780
|
+
do {
|
|
25781
|
+
const page = await this.client.projectList({ limit: 100, ...cursor ? { cursor } : {} });
|
|
25782
|
+
for (const project of page.data) {
|
|
25783
|
+
for (const root of project.roots) {
|
|
25784
|
+
if (projectRootKey(root.path) === key || await this.matchesRoot(root.path, key)) {
|
|
25785
|
+
matches.add(project.id);
|
|
25786
|
+
break;
|
|
25787
|
+
}
|
|
25788
|
+
}
|
|
25789
|
+
}
|
|
25790
|
+
cursor = page.nextCursor ?? void 0;
|
|
25791
|
+
} while (cursor);
|
|
25792
|
+
if (matches.size > 1) {
|
|
25793
|
+
throw RequestError.invalidParams(void 0, "Multiple Codex projects use this root; consolidate the project assignments first");
|
|
25794
|
+
}
|
|
25795
|
+
const match = matches.values().next().value;
|
|
25796
|
+
if (match) return match;
|
|
25797
|
+
const idempotencyKey = `acp-project-v1:${createHash("sha256").update(key).digest("hex")}`;
|
|
25798
|
+
const response = await this.client.projectCreate({
|
|
25799
|
+
idempotencyKey,
|
|
25800
|
+
name: path__default.basename(originProjectPath) || originProjectPath,
|
|
25801
|
+
roots: [{ path: originProjectPath }]
|
|
25802
|
+
});
|
|
25803
|
+
return response.project.id;
|
|
25804
|
+
}
|
|
25805
|
+
async matchesRoot(storedPath, key) {
|
|
25806
|
+
try {
|
|
25807
|
+
return projectRootKey(await realpath(storedPath)) === key;
|
|
25808
|
+
} catch {
|
|
25809
|
+
return false;
|
|
25810
|
+
}
|
|
25811
|
+
}
|
|
25812
|
+
};
|
|
25813
|
+
function projectRootKey(originProjectPath) {
|
|
25814
|
+
const normalized = path__default.resolve(originProjectPath);
|
|
25815
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
25816
|
+
}
|
|
25712
25817
|
var isDockerCached;
|
|
25713
25818
|
function hasDockerEnv() {
|
|
25714
25819
|
try {
|
|
@@ -25864,16 +25969,16 @@ var wslDefaultBrowser = async () => {
|
|
|
25864
25969
|
});
|
|
25865
25970
|
return stdout.trim();
|
|
25866
25971
|
};
|
|
25867
|
-
var isUrl = (
|
|
25972
|
+
var isUrl = (path10) => /^[a-z]+:\/\//i.test(path10);
|
|
25868
25973
|
var convertWslPathToWindows = async (paths) => {
|
|
25869
25974
|
const isBatch = Array.isArray(paths);
|
|
25870
25975
|
const pathArray = isBatch ? paths : [paths];
|
|
25871
25976
|
const indicesToConvert = [];
|
|
25872
25977
|
const pathsToConvert = [];
|
|
25873
|
-
for (const [index,
|
|
25874
|
-
if (!isUrl(
|
|
25978
|
+
for (const [index, path10] of pathArray.entries()) {
|
|
25979
|
+
if (!isUrl(path10)) {
|
|
25875
25980
|
indicesToConvert.push(index);
|
|
25876
|
-
pathsToConvert.push(
|
|
25981
|
+
pathsToConvert.push(path10);
|
|
25877
25982
|
}
|
|
25878
25983
|
}
|
|
25879
25984
|
const results = [...pathArray];
|
|
@@ -26476,7 +26581,7 @@ var package_default = {
|
|
|
26476
26581
|
publishConfig: {
|
|
26477
26582
|
access: "public"
|
|
26478
26583
|
},
|
|
26479
|
-
version: "1.10.
|
|
26584
|
+
version: "1.10.1",
|
|
26480
26585
|
description: "An ACP-compatible coding agent powered by Codex",
|
|
26481
26586
|
main: "dist/index.js",
|
|
26482
26587
|
bin: {
|
|
@@ -26546,29 +26651,17 @@ var package_default = {
|
|
|
26546
26651
|
dependencies: {
|
|
26547
26652
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
26548
26653
|
"@openai/codex": "^0.153.4",
|
|
26549
|
-
"acp-extension-core": "0.1.
|
|
26654
|
+
"acp-extension-core": "0.1.4",
|
|
26550
26655
|
diff: "^9.0.0",
|
|
26551
26656
|
open: "^11.0.1",
|
|
26552
26657
|
"vscode-jsonrpc": "^9.0.1",
|
|
26553
26658
|
zod: "^4.0.0"
|
|
26554
26659
|
}
|
|
26555
26660
|
};
|
|
26556
|
-
var COLLABORATION_MODE_CONFIG_ID = "collaboration_mode";
|
|
26557
26661
|
var DEFAULT_COLLABORATION_MODE = "default";
|
|
26558
26662
|
var PLAN_COLLABORATION_MODE = "plan";
|
|
26559
26663
|
function createCollaborationModeConfigOption(currentValue) {
|
|
26560
|
-
return
|
|
26561
|
-
id: COLLABORATION_MODE_CONFIG_ID,
|
|
26562
|
-
name: "Collaboration mode",
|
|
26563
|
-
description: "How Codex collaborates for subsequent turns",
|
|
26564
|
-
category: "collaboration_mode",
|
|
26565
|
-
type: "select",
|
|
26566
|
-
currentValue,
|
|
26567
|
-
options: [
|
|
26568
|
-
{ value: DEFAULT_COLLABORATION_MODE, name: "Default" },
|
|
26569
|
-
{ value: PLAN_COLLABORATION_MODE, name: "Plan", description: "Plan before making changes" }
|
|
26570
|
-
]
|
|
26571
|
-
};
|
|
26664
|
+
return createPlanModeConfigOption(currentValue === PLAN_COLLABORATION_MODE);
|
|
26572
26665
|
}
|
|
26573
26666
|
function parseCollaborationMode(value) {
|
|
26574
26667
|
if (value === DEFAULT_COLLABORATION_MODE) return DEFAULT_COLLABORATION_MODE;
|
|
@@ -27034,6 +27127,7 @@ var CodexSubagentSubscriptions = class {
|
|
|
27034
27127
|
}
|
|
27035
27128
|
};
|
|
27036
27129
|
async function forkSession(request, additionalDirectories, dependencies) {
|
|
27130
|
+
const project = readWorktreeProject(request._meta);
|
|
27037
27131
|
await dependencies.refreshSkills(request.cwd, additionalDirectories);
|
|
27038
27132
|
const lastTurnId = await resolveForkTurnId(request, dependencies.codexClient);
|
|
27039
27133
|
const response = await dependencies.codexClient.threadFork({
|
|
@@ -27047,7 +27141,12 @@ async function forkSession(request, additionalDirectories, dependencies) {
|
|
|
27047
27141
|
modelProvider: await dependencies.getResumeModelProvider(),
|
|
27048
27142
|
threadId: request.sessionId
|
|
27049
27143
|
});
|
|
27050
|
-
|
|
27144
|
+
try {
|
|
27145
|
+
await dependencies.assignProject(response.thread, project);
|
|
27146
|
+
} catch (error48) {
|
|
27147
|
+
await dependencies.codexClient.threadUnsubscribe({ threadId: response.thread.id });
|
|
27148
|
+
throw error48;
|
|
27149
|
+
}
|
|
27051
27150
|
const models = await dependencies.fetchAvailableModels();
|
|
27052
27151
|
return {
|
|
27053
27152
|
sessionId: response.thread.id,
|
|
@@ -27139,10 +27238,12 @@ var CodexAcpClient = class {
|
|
|
27139
27238
|
pendingAccountUpdated = null;
|
|
27140
27239
|
sessionNotificationQueues = /* @__PURE__ */ new Map();
|
|
27141
27240
|
subagents;
|
|
27241
|
+
worktreeProjects;
|
|
27142
27242
|
skillExtraRoots = [];
|
|
27143
27243
|
configPath = null;
|
|
27144
27244
|
constructor(codexClient, codexConfig, modelProvider) {
|
|
27145
27245
|
this.codexClient = codexClient;
|
|
27246
|
+
this.worktreeProjects = new WorktreeProjects(codexClient);
|
|
27146
27247
|
this.config = codexConfig ?? {};
|
|
27147
27248
|
this.modelProvider = modelProvider ?? null;
|
|
27148
27249
|
this.gatewayConfig = null;
|
|
@@ -27493,6 +27594,7 @@ var CodexAcpClient = class {
|
|
|
27493
27594
|
return settingsModelProvider?.config?.model_provider ?? null;
|
|
27494
27595
|
}
|
|
27495
27596
|
async resumeSession(request, onSubscribed) {
|
|
27597
|
+
const project = readWorktreeProject(request._meta);
|
|
27496
27598
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
27497
27599
|
await this.refreshSkills(request.cwd, additionalDirectories);
|
|
27498
27600
|
const response = await this.codexClient.threadResume({
|
|
@@ -27502,6 +27604,7 @@ var CodexAcpClient = class {
|
|
|
27502
27604
|
threadId: request.sessionId
|
|
27503
27605
|
});
|
|
27504
27606
|
onSubscribed?.(request.sessionId);
|
|
27607
|
+
await this.worktreeProjects.assign(response.thread, project, true);
|
|
27505
27608
|
const codexModels = await this.fetchAvailableModels();
|
|
27506
27609
|
const currentModelId = this.createModelId(codexModels, response.model, response.reasoningEffort).toString();
|
|
27507
27610
|
return {
|
|
@@ -27518,6 +27621,7 @@ var CodexAcpClient = class {
|
|
|
27518
27621
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
27519
27622
|
return await forkSession(request, additionalDirectories, {
|
|
27520
27623
|
codexClient: this.codexClient,
|
|
27624
|
+
assignProject: (thread, project) => this.worktreeProjects.assign(thread, project, false),
|
|
27521
27625
|
refreshSkills: (cwd, directories) => this.refreshSkills(cwd, directories),
|
|
27522
27626
|
createSessionConfig: (cwd, directories, mcpServers) => this.createSessionConfig(cwd, directories, mcpServers),
|
|
27523
27627
|
getResumeModelProvider: () => this.getResumeModelProvider(),
|
|
@@ -27527,6 +27631,7 @@ var CodexAcpClient = class {
|
|
|
27527
27631
|
});
|
|
27528
27632
|
}
|
|
27529
27633
|
async loadSession(request, onSubscribed) {
|
|
27634
|
+
const project = readWorktreeProject(request._meta);
|
|
27530
27635
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
27531
27636
|
await this.refreshSkills(request.cwd, additionalDirectories);
|
|
27532
27637
|
const response = await this.codexClient.threadResume({
|
|
@@ -27536,6 +27641,7 @@ var CodexAcpClient = class {
|
|
|
27536
27641
|
threadId: request.sessionId
|
|
27537
27642
|
});
|
|
27538
27643
|
onSubscribed?.();
|
|
27644
|
+
await this.worktreeProjects.assign(response.thread, project, true);
|
|
27539
27645
|
const historyResponse = await this.codexClient.threadRead({
|
|
27540
27646
|
threadId: response.thread.id,
|
|
27541
27647
|
includeTurns: true
|
|
@@ -27557,9 +27663,12 @@ var CodexAcpClient = class {
|
|
|
27557
27663
|
return await this.readSessionHistory(sessionId);
|
|
27558
27664
|
}
|
|
27559
27665
|
async newSession(request, onSubscribed) {
|
|
27666
|
+
const project = readWorktreeProject(request._meta);
|
|
27560
27667
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
27561
27668
|
await this.refreshSkills(request.cwd, additionalDirectories);
|
|
27669
|
+
const projectId = await this.worktreeProjects.resolve(project);
|
|
27562
27670
|
const response = await this.codexClient.threadStart({
|
|
27671
|
+
...projectId ? { projectId } : {},
|
|
27563
27672
|
config: await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers),
|
|
27564
27673
|
modelProvider: this.getModelProvider(),
|
|
27565
27674
|
cwd: request.cwd
|
|
@@ -27789,6 +27898,14 @@ var CodexAcpClient = class {
|
|
|
27789
27898
|
await queue;
|
|
27790
27899
|
}
|
|
27791
27900
|
}
|
|
27901
|
+
onConnectionClosed(callback) {
|
|
27902
|
+
const close = this.codexClient.connection.onClose(callback);
|
|
27903
|
+
const dispose = this.codexClient.connection.onDispose(callback);
|
|
27904
|
+
return () => {
|
|
27905
|
+
close.dispose();
|
|
27906
|
+
dispose.dispose();
|
|
27907
|
+
};
|
|
27908
|
+
}
|
|
27792
27909
|
enqueueSessionNotification(sessionId, operation) {
|
|
27793
27910
|
const run = async () => {
|
|
27794
27911
|
try {
|
|
@@ -28192,8 +28309,8 @@ function formatUriAsLink(name, uri) {
|
|
|
28192
28309
|
return `[@${name}](${uri})`;
|
|
28193
28310
|
}
|
|
28194
28311
|
if (uri.startsWith("file://")) {
|
|
28195
|
-
const
|
|
28196
|
-
const fileName =
|
|
28312
|
+
const path10 = uri.replace("file://", "");
|
|
28313
|
+
const fileName = path10.split("/").pop() ?? path10;
|
|
28197
28314
|
return `[@${fileName}](${uri})`;
|
|
28198
28315
|
}
|
|
28199
28316
|
return uri;
|
|
@@ -28655,6 +28772,15 @@ var CodexAppServerClient = class {
|
|
|
28655
28772
|
threadStaleTurns.add(turnId);
|
|
28656
28773
|
this.staleTurnIds.set(threadId, threadStaleTurns);
|
|
28657
28774
|
}
|
|
28775
|
+
async projectList(params) {
|
|
28776
|
+
return await this.sendRequest({ method: "project/list", params });
|
|
28777
|
+
}
|
|
28778
|
+
async projectCreate(params) {
|
|
28779
|
+
return await this.sendRequest({ method: "project/create", params });
|
|
28780
|
+
}
|
|
28781
|
+
async threadProjectUpdate(params) {
|
|
28782
|
+
await this.sendRequest({ method: "thread/metadata/update", params });
|
|
28783
|
+
}
|
|
28658
28784
|
async threadStart(params) {
|
|
28659
28785
|
return await this.sendRequest({ method: "thread/start", params });
|
|
28660
28786
|
}
|
|
@@ -29193,12 +29319,13 @@ function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEff
|
|
|
29193
29319
|
}))
|
|
29194
29320
|
};
|
|
29195
29321
|
}
|
|
29322
|
+
var GOAL_OBJECTIVE_MAX_LENGTH = 4e3;
|
|
29196
29323
|
var GOAL_CONTINUATION_PROMPT = [{
|
|
29197
29324
|
type: "text",
|
|
29198
29325
|
text: "Continue working toward the active goal."
|
|
29199
29326
|
}];
|
|
29200
29327
|
function resolveGoalCommandHandleResult(turnCompleted) {
|
|
29201
|
-
if (turnCompleted
|
|
29328
|
+
if (turnCompleted !== null) {
|
|
29202
29329
|
return { handled: true, turnCompleted };
|
|
29203
29330
|
}
|
|
29204
29331
|
return { handled: false, prompt: GOAL_CONTINUATION_PROMPT };
|
|
@@ -29281,9 +29408,9 @@ var CodexCommands = class {
|
|
|
29281
29408
|
_meta: {
|
|
29282
29409
|
commandAction: {
|
|
29283
29410
|
kind: "setConfigOption",
|
|
29284
|
-
configId:
|
|
29285
|
-
value:
|
|
29286
|
-
resetValue:
|
|
29411
|
+
configId: LODY_PLAN_MODE_CONFIG_ID,
|
|
29412
|
+
value: true,
|
|
29413
|
+
resetValue: false,
|
|
29287
29414
|
presentation: "state"
|
|
29288
29415
|
}
|
|
29289
29416
|
}
|
|
@@ -29372,8 +29499,8 @@ var CodexCommands = class {
|
|
|
29372
29499
|
await this.sendCommandUsageMessage(commandName, "no arguments", sessionId);
|
|
29373
29500
|
return { handled: true };
|
|
29374
29501
|
}
|
|
29375
|
-
const mode = sessionState.collaborationMode
|
|
29376
|
-
await options.setConfigOption?.(
|
|
29502
|
+
const mode = sessionState.collaborationMode !== PLAN_COLLABORATION_MODE;
|
|
29503
|
+
await options.setConfigOption?.(LODY_PLAN_MODE_CONFIG_ID, mode);
|
|
29377
29504
|
return { handled: options.setConfigOption !== void 0 };
|
|
29378
29505
|
}
|
|
29379
29506
|
case "compact": {
|
|
@@ -29476,35 +29603,56 @@ var CodexCommands = class {
|
|
|
29476
29603
|
await this.sendCommandUsageMessage("goal", "[<objective>|clear|pause|resume]", sessionId);
|
|
29477
29604
|
return { handled: true };
|
|
29478
29605
|
}
|
|
29479
|
-
|
|
29480
|
-
|
|
29481
|
-
|
|
29482
|
-
|
|
29483
|
-
|
|
29484
|
-
options
|
|
29485
|
-
|
|
29486
|
-
sessionId,
|
|
29487
|
-
(turnId) => {
|
|
29488
|
-
this.handleCommandTurnStarted(sessionState, options, turnId, sessionId);
|
|
29489
|
-
}
|
|
29490
|
-
)));
|
|
29491
|
-
case "clear":
|
|
29492
|
-
await this.runWithProcessCheck(() => this.codexAcpClient.clearGoal(sessionId));
|
|
29493
|
-
return { handled: true };
|
|
29606
|
+
const named = argument.toLowerCase();
|
|
29607
|
+
if (named === "pause" || named === "resume" || named === "clear") {
|
|
29608
|
+
return await this.runGoalPromptControl(
|
|
29609
|
+
sessionState,
|
|
29610
|
+
{ version: GOAL_EXTENSION_VERSION, action: named },
|
|
29611
|
+
options
|
|
29612
|
+
);
|
|
29494
29613
|
}
|
|
29495
|
-
if (argument.length >
|
|
29614
|
+
if (argument.length > GOAL_OBJECTIVE_MAX_LENGTH) {
|
|
29496
29615
|
const session = new ACPSessionConnection(this.connection, sessionId);
|
|
29497
|
-
await session.update(createAgentTextMessageChunk(
|
|
29616
|
+
await session.update(createAgentTextMessageChunk(
|
|
29617
|
+
`Command "/goal" requires goal text of at most ${GOAL_OBJECTIVE_MAX_LENGTH} characters.`
|
|
29618
|
+
));
|
|
29498
29619
|
return { handled: true };
|
|
29499
29620
|
}
|
|
29621
|
+
return await this.runGoalPromptControl(
|
|
29622
|
+
sessionState,
|
|
29623
|
+
{ version: GOAL_EXTENSION_VERSION, action: "set", objective: argument },
|
|
29624
|
+
options
|
|
29625
|
+
);
|
|
29626
|
+
}
|
|
29627
|
+
/**
|
|
29628
|
+
* Run a goal action inside whatever prompt is already executing. `/goal …`
|
|
29629
|
+
* and a prompt carrying `_meta.lody.goalControl` are the same operation
|
|
29630
|
+
* reaching the same place: the caller's prompt owns any turn the action
|
|
29631
|
+
* starts, so neither has to start one behind the client's back.
|
|
29632
|
+
*/
|
|
29633
|
+
async runGoalPromptControl(sessionState, control, options = {}) {
|
|
29634
|
+
const sessionId = sessionState.sessionId;
|
|
29635
|
+
if (control.action === "pause") {
|
|
29636
|
+
await this.runWithProcessCheck(() => this.codexAcpClient.setGoalStatus(sessionId, "paused"));
|
|
29637
|
+
return { handled: true };
|
|
29638
|
+
}
|
|
29639
|
+
if (control.action === "clear") {
|
|
29640
|
+
await this.runWithProcessCheck(() => this.codexAcpClient.clearGoal(sessionId));
|
|
29641
|
+
return { handled: true };
|
|
29642
|
+
}
|
|
29643
|
+
if (control.action === "set" && control.objective.trim().length > GOAL_OBJECTIVE_MAX_LENGTH) {
|
|
29644
|
+
throw RequestError.invalidParams(
|
|
29645
|
+
void 0,
|
|
29646
|
+
`A goal objective may be at most ${GOAL_OBJECTIVE_MAX_LENGTH} characters`
|
|
29647
|
+
);
|
|
29648
|
+
}
|
|
29500
29649
|
options.onTurnStartPending?.();
|
|
29501
|
-
|
|
29502
|
-
sessionId
|
|
29503
|
-
|
|
29504
|
-
|
|
29505
|
-
|
|
29506
|
-
|
|
29507
|
-
)));
|
|
29650
|
+
const onTurnStarted = (turnId) => {
|
|
29651
|
+
this.handleCommandTurnStarted(sessionState, options, turnId, sessionId);
|
|
29652
|
+
};
|
|
29653
|
+
return this.createGoalCommandResult(await this.runWithProcessCheck(
|
|
29654
|
+
() => control.action === "set" ? this.codexAcpClient.setGoal(sessionId, control.objective.trim(), onTurnStarted) : this.codexAcpClient.resumeGoal(sessionId, onTurnStarted)
|
|
29655
|
+
));
|
|
29508
29656
|
}
|
|
29509
29657
|
handleCommandTurnStarted(sessionState, options, turnId, threadId) {
|
|
29510
29658
|
if (options.onTurnStarted) {
|
|
@@ -29697,6 +29845,77 @@ var CodexCommands = class {
|
|
|
29697
29845
|
return count.toString();
|
|
29698
29846
|
}
|
|
29699
29847
|
};
|
|
29848
|
+
var GoalPromptLifecycle = class {
|
|
29849
|
+
constructor(sessionId, goalActive) {
|
|
29850
|
+
this.sessionId = sessionId;
|
|
29851
|
+
this.goalActive = goalActive;
|
|
29852
|
+
}
|
|
29853
|
+
sessionId;
|
|
29854
|
+
goalActive;
|
|
29855
|
+
currentTurnId = null;
|
|
29856
|
+
completed = null;
|
|
29857
|
+
failure = null;
|
|
29858
|
+
waiter = null;
|
|
29859
|
+
cancelled = false;
|
|
29860
|
+
startTurn(turnId) {
|
|
29861
|
+
if (this.currentTurnId === turnId) return;
|
|
29862
|
+
this.currentTurnId = turnId;
|
|
29863
|
+
this.completed = null;
|
|
29864
|
+
}
|
|
29865
|
+
prepareTurn() {
|
|
29866
|
+
this.currentTurnId = null;
|
|
29867
|
+
this.completed = null;
|
|
29868
|
+
}
|
|
29869
|
+
/** A delayed turn/start response must not overwrite already-observed native work. */
|
|
29870
|
+
startSubmittedTurn(turnId) {
|
|
29871
|
+
if (this.currentTurnId !== null || this.completed !== null) return false;
|
|
29872
|
+
this.startTurn(turnId);
|
|
29873
|
+
return true;
|
|
29874
|
+
}
|
|
29875
|
+
observe(event) {
|
|
29876
|
+
if (event.method === "thread/goal/updated" && event.params.threadId === this.sessionId) {
|
|
29877
|
+
this.goalActive = event.params.goal.status === "active";
|
|
29878
|
+
} else if (event.method === "thread/goal/cleared" && event.params.threadId === this.sessionId) {
|
|
29879
|
+
this.goalActive = false;
|
|
29880
|
+
} else if (event.method === "turn/started" && event.params.threadId === this.sessionId) {
|
|
29881
|
+
this.startTurn(event.params.turn.id);
|
|
29882
|
+
} else if (event.method === "turn/completed" && event.params.threadId === this.sessionId) {
|
|
29883
|
+
this.recordCompletion(event.params);
|
|
29884
|
+
} else {
|
|
29885
|
+
return;
|
|
29886
|
+
}
|
|
29887
|
+
this.waiter?.();
|
|
29888
|
+
}
|
|
29889
|
+
recordCompletion(event) {
|
|
29890
|
+
this.completed = event;
|
|
29891
|
+
if (this.currentTurnId === event.turn.id) this.currentTurnId = null;
|
|
29892
|
+
}
|
|
29893
|
+
cancel() {
|
|
29894
|
+
this.cancelled = true;
|
|
29895
|
+
this.waiter?.();
|
|
29896
|
+
}
|
|
29897
|
+
fail(error48) {
|
|
29898
|
+
this.failure = error48;
|
|
29899
|
+
this.waiter?.();
|
|
29900
|
+
}
|
|
29901
|
+
async waitForCompletion(first) {
|
|
29902
|
+
if (first.threadId !== this.sessionId) return first;
|
|
29903
|
+
if (this.completed === null) this.recordCompletion(first);
|
|
29904
|
+
const result = await new Promise((resolve, reject) => {
|
|
29905
|
+
this.waiter = () => {
|
|
29906
|
+
if (this.failure) reject(this.failure);
|
|
29907
|
+
else if (this.cancelled && this.currentTurnId === null) resolve(null);
|
|
29908
|
+
else if (this.completed && this.currentTurnId === null && (!this.goalActive || this.completed.turn.status !== "completed")) {
|
|
29909
|
+
resolve(this.completed);
|
|
29910
|
+
}
|
|
29911
|
+
};
|
|
29912
|
+
this.waiter();
|
|
29913
|
+
}).finally(() => {
|
|
29914
|
+
this.waiter = null;
|
|
29915
|
+
});
|
|
29916
|
+
return result;
|
|
29917
|
+
}
|
|
29918
|
+
};
|
|
29700
29919
|
var SteeringQueue = class {
|
|
29701
29920
|
constructor(handle) {
|
|
29702
29921
|
this.handle = handle;
|
|
@@ -29978,8 +30197,8 @@ function imageBlocks(images) {
|
|
|
29978
30197
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
29979
30198
|
}
|
|
29980
30199
|
const record2 = asRecord2(image);
|
|
29981
|
-
const
|
|
29982
|
-
return
|
|
30200
|
+
const path10 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
30201
|
+
return path10 ? [{ type: "text", text: `[@image](${path10})` }] : [];
|
|
29983
30202
|
});
|
|
29984
30203
|
}
|
|
29985
30204
|
function contentBlocksFromResponseContent(content) {
|
|
@@ -32247,8 +32466,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32247
32466
|
case MODE_CONFIG_ID:
|
|
32248
32467
|
this.applyModeChange(sessionState, this.stringConfigValue(params));
|
|
32249
32468
|
break;
|
|
32250
|
-
case
|
|
32251
|
-
|
|
32469
|
+
case LODY_PLAN_MODE_CONFIG_ID:
|
|
32470
|
+
if (typeof params.value !== "boolean") throw RequestError.invalidParams();
|
|
32471
|
+
await this.applyCollaborationModeChange(sessionState, params.value ? PLAN_COLLABORATION_MODE : DEFAULT_COLLABORATION_MODE);
|
|
32252
32472
|
break;
|
|
32253
32473
|
case MODEL_CONFIG_ID:
|
|
32254
32474
|
this.applyModelChange(sessionState, this.stringConfigValue(params));
|
|
@@ -33147,8 +33367,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33147
33367
|
return `[@${name}](${uri})`;
|
|
33148
33368
|
}
|
|
33149
33369
|
if (uri.startsWith("file://")) {
|
|
33150
|
-
const
|
|
33151
|
-
const fileName =
|
|
33370
|
+
const path10 = uri.replace("file://", "");
|
|
33371
|
+
const fileName = path10.split("/").pop() ?? path10;
|
|
33152
33372
|
return `[@${fileName}](${uri})`;
|
|
33153
33373
|
}
|
|
33154
33374
|
return uri;
|
|
@@ -33294,6 +33514,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33294
33514
|
cancelSignal,
|
|
33295
33515
|
signal: abortController.signal,
|
|
33296
33516
|
currentTurn: null,
|
|
33517
|
+
hasCompletedTurn: false,
|
|
33297
33518
|
requestCancel: () => {
|
|
33298
33519
|
if (abortController.signal.aborted) {
|
|
33299
33520
|
return;
|
|
@@ -33488,12 +33709,19 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33488
33709
|
});
|
|
33489
33710
|
const sessionState = this.getSessionState(params.sessionId);
|
|
33490
33711
|
const agentFileChangeReportRequest = clientSupportsAgentFileChangeReports(this.clientCapabilities) ? parseAgentFileChangeReportRequest(params._meta) : null;
|
|
33712
|
+
const goalPromptControl = parseGoalPromptControl(params._meta);
|
|
33491
33713
|
let agentFileChangeReportTurnId = null;
|
|
33492
33714
|
let agentFileChangeReportUnavailableReason = "providerError";
|
|
33493
33715
|
let promptWasCancelled = false;
|
|
33494
33716
|
let recoverableSessionFailure = sessionState.sessionFailure;
|
|
33495
33717
|
sessionState.currentTurnId = null;
|
|
33496
33718
|
const activePrompt = this.trackActivePrompt(params.sessionId);
|
|
33719
|
+
const goalLifecycle = new GoalPromptLifecycle(params.sessionId, sessionState.currentGoal?.status === "active");
|
|
33720
|
+
const cancelGoalLifecycle = () => goalLifecycle.cancel();
|
|
33721
|
+
activePrompt.signal.addEventListener("abort", cancelGoalLifecycle);
|
|
33722
|
+
const disposeGoalConnection = this.codexAcpClient.onConnectionClosed(() => {
|
|
33723
|
+
goalLifecycle.fail(new Error("Codex connection closed during goal continuation"));
|
|
33724
|
+
});
|
|
33497
33725
|
let pendingTurnStart = null;
|
|
33498
33726
|
const ensurePendingTurnStart = () => {
|
|
33499
33727
|
if (pendingTurnStart === null) {
|
|
@@ -33549,6 +33777,23 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33549
33777
|
await this.codexAcpClient.subscribeToSessionEvents(
|
|
33550
33778
|
params.sessionId,
|
|
33551
33779
|
async (event) => {
|
|
33780
|
+
if (this.activePrompts.get(params.sessionId) === activePrompt) {
|
|
33781
|
+
goalLifecycle.observe(event);
|
|
33782
|
+
if (event.method === "turn/started" && event.params.threadId === params.sessionId) {
|
|
33783
|
+
const turn = { threadId: params.sessionId, turnId: event.params.turn.id };
|
|
33784
|
+
activePrompt.currentTurn = turn;
|
|
33785
|
+
if (this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
33786
|
+
this.interruptLateStartedTurn(turn);
|
|
33787
|
+
return;
|
|
33788
|
+
}
|
|
33789
|
+
recoverableSessionFailure = sessionState.sessionFailure;
|
|
33790
|
+
promptNotificationsActive = true;
|
|
33791
|
+
}
|
|
33792
|
+
if (event.method === "turn/completed" && event.params.threadId === params.sessionId && activePrompt.currentTurn?.turnId === event.params.turn.id) {
|
|
33793
|
+
activePrompt.currentTurn = null;
|
|
33794
|
+
activePrompt.hasCompletedTurn = true;
|
|
33795
|
+
}
|
|
33796
|
+
}
|
|
33552
33797
|
await this.handleSteerAppliedNotification(params.sessionId, event, activePrompt);
|
|
33553
33798
|
await observeInteraction(event);
|
|
33554
33799
|
if (!promptNotificationsActive) {
|
|
@@ -33570,13 +33815,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33570
33815
|
if (activePrompt.signal.aborted) {
|
|
33571
33816
|
return cancelledPromptResponse();
|
|
33572
33817
|
}
|
|
33573
|
-
const
|
|
33818
|
+
const commandOptions = {
|
|
33574
33819
|
onTurnStartPending: () => {
|
|
33575
33820
|
sessionState.lastTokenUsage = null;
|
|
33576
33821
|
ensurePendingTurnStart();
|
|
33577
33822
|
},
|
|
33578
33823
|
onTurnStarted: (turnId, threadId) => {
|
|
33579
33824
|
const turn = { threadId, turnId };
|
|
33825
|
+
if (threadId === params.sessionId) goalLifecycle.startTurn(turnId);
|
|
33580
33826
|
activePrompt.currentTurn = turn;
|
|
33581
33827
|
if (this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
33582
33828
|
this.interruptLateStartedTurn(turn);
|
|
@@ -33590,7 +33836,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33590
33836
|
await this.applySessionConfigOption(sessionState, {
|
|
33591
33837
|
sessionId: sessionState.sessionId,
|
|
33592
33838
|
configId,
|
|
33593
|
-
value
|
|
33839
|
+
...typeof value === "boolean" ? { type: "boolean", value } : { value }
|
|
33594
33840
|
});
|
|
33595
33841
|
const session = new ACPSessionConnection(this.connection, sessionState.sessionId);
|
|
33596
33842
|
await session.update({
|
|
@@ -33598,13 +33844,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33598
33844
|
configOptions: this.createSessionConfigOptions(sessionState)
|
|
33599
33845
|
});
|
|
33600
33846
|
}
|
|
33601
|
-
}
|
|
33847
|
+
};
|
|
33848
|
+
const commandPromise = goalPromptControl === null ? this.availableCommands.tryHandleCommand(params.prompt, sessionState, commandOptions) : this.availableCommands.runGoalPromptControl(sessionState, goalPromptControl, commandOptions);
|
|
33602
33849
|
void commandPromise.catch((err) => {
|
|
33603
33850
|
if (this.activePrompts.get(params.sessionId) !== activePrompt) {
|
|
33604
33851
|
logger.error(`Command for cancelled prompt ${params.sessionId} failed after prompt returned`, err);
|
|
33605
33852
|
}
|
|
33606
33853
|
});
|
|
33607
|
-
|
|
33854
|
+
let commandResult = await Promise.race([
|
|
33608
33855
|
commandPromise,
|
|
33609
33856
|
activePrompt.closeSignal,
|
|
33610
33857
|
this.cancelBeforeTurnStarted(activePrompt)
|
|
@@ -33613,6 +33860,16 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33613
33860
|
return cancelledPromptResponse();
|
|
33614
33861
|
}
|
|
33615
33862
|
if (commandResult.handled) {
|
|
33863
|
+
if (commandResult.turnCompleted) {
|
|
33864
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33865
|
+
const firstCommandTurn = commandResult.turnCompleted;
|
|
33866
|
+
const completed = await this.runWithProcessCheck(() => Promise.race([
|
|
33867
|
+
goalLifecycle.waitForCompletion(firstCommandTurn),
|
|
33868
|
+
activePrompt.closeSignal
|
|
33869
|
+
]));
|
|
33870
|
+
if (completed === null) return cancelledPromptResponse();
|
|
33871
|
+
commandResult = { ...commandResult, turnCompleted: completed };
|
|
33872
|
+
}
|
|
33616
33873
|
promptNotificationsActive = false;
|
|
33617
33874
|
logger.log("Prompt handled by a command");
|
|
33618
33875
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
@@ -33671,6 +33928,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33671
33928
|
);
|
|
33672
33929
|
sessionState.lastTokenUsage = null;
|
|
33673
33930
|
ensurePendingTurnStart();
|
|
33931
|
+
goalLifecycle.prepareTurn();
|
|
33674
33932
|
const sendPromptPromise = this.runWithProcessCheck(
|
|
33675
33933
|
() => this.codexAcpClient.sendPrompt(
|
|
33676
33934
|
effectiveParams,
|
|
@@ -33682,6 +33940,11 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33682
33940
|
sessionState.additionalDirectories,
|
|
33683
33941
|
(turnId) => {
|
|
33684
33942
|
const turn = { threadId: params.sessionId, turnId };
|
|
33943
|
+
if (!goalLifecycle.startSubmittedTurn(turnId)) {
|
|
33944
|
+
pendingTurnStart?.resolve(turnId);
|
|
33945
|
+
onTurnStarted?.();
|
|
33946
|
+
return;
|
|
33947
|
+
}
|
|
33685
33948
|
activePrompt.currentTurn = turn;
|
|
33686
33949
|
if (this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
33687
33950
|
this.interruptLateStartedTurn(turn);
|
|
@@ -33708,6 +33971,13 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33708
33971
|
return cancelledPromptResponse();
|
|
33709
33972
|
}
|
|
33710
33973
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33974
|
+
const firstPromptTurn = turnCompleted;
|
|
33975
|
+
turnCompleted = await this.runWithProcessCheck(() => Promise.race([
|
|
33976
|
+
goalLifecycle.waitForCompletion(firstPromptTurn),
|
|
33977
|
+
activePrompt.closeSignal
|
|
33978
|
+
]));
|
|
33979
|
+
if (turnCompleted === null) return cancelledPromptResponse();
|
|
33980
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33711
33981
|
if (turnCompleted.turn.status === "completed") {
|
|
33712
33982
|
await eventHandler.waitForNativeSubagents(activePrompt.signal);
|
|
33713
33983
|
if (activePrompt.signal.aborted) return cancelledPromptResponse();
|
|
@@ -33760,6 +34030,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33760
34030
|
};
|
|
33761
34031
|
activePrompt.currentTurn = null;
|
|
33762
34032
|
sessionState.currentTurnId = null;
|
|
34033
|
+
goalLifecycle.prepareTurn();
|
|
33763
34034
|
const implementationPromise = this.runWithProcessCheck(
|
|
33764
34035
|
() => this.codexAcpClient.sendPrompt(
|
|
33765
34036
|
implementationRequest,
|
|
@@ -33771,6 +34042,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33771
34042
|
sessionState.additionalDirectories,
|
|
33772
34043
|
(turnId) => {
|
|
33773
34044
|
const turn = { threadId: params.sessionId, turnId };
|
|
34045
|
+
if (!goalLifecycle.startSubmittedTurn(turnId)) return;
|
|
33774
34046
|
activePrompt.currentTurn = turn;
|
|
33775
34047
|
if (this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
33776
34048
|
this.interruptLateStartedTurn(turn);
|
|
@@ -33797,6 +34069,13 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33797
34069
|
return cancelledPromptResponse();
|
|
33798
34070
|
}
|
|
33799
34071
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
34072
|
+
const firstImplementationTurn = turnCompleted;
|
|
34073
|
+
turnCompleted = await this.runWithProcessCheck(() => Promise.race([
|
|
34074
|
+
goalLifecycle.waitForCompletion(firstImplementationTurn),
|
|
34075
|
+
activePrompt.closeSignal
|
|
34076
|
+
]));
|
|
34077
|
+
if (turnCompleted === null) return cancelledPromptResponse();
|
|
34078
|
+
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
33800
34079
|
if (turnCompleted.turn.status === "completed") {
|
|
33801
34080
|
await eventHandler.waitForNativeSubagents(activePrompt.signal);
|
|
33802
34081
|
if (activePrompt.signal.aborted) return cancelledPromptResponse();
|
|
@@ -33870,6 +34149,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33870
34149
|
}
|
|
33871
34150
|
throw err;
|
|
33872
34151
|
} finally {
|
|
34152
|
+
if ((promptWasCancelled || activePrompt.signal.aborted) && sessionState.currentGoal?.status === "active") {
|
|
34153
|
+
try {
|
|
34154
|
+
const goal = await this.runWithProcessCheck(() => this.codexAcpClient.setGoalStatus(params.sessionId, "paused"));
|
|
34155
|
+
await this.publishGoalSnapshot(sessionState, toThreadGoalSnapshot(goal), false);
|
|
34156
|
+
} catch (error48) {
|
|
34157
|
+
logger.error("Failed to pause goal after prompt cancellation", error48);
|
|
34158
|
+
}
|
|
34159
|
+
}
|
|
33873
34160
|
promptNotificationsActive = false;
|
|
33874
34161
|
try {
|
|
33875
34162
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
@@ -33890,6 +34177,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33890
34177
|
}
|
|
33891
34178
|
logger.log("Prompt completed", { sessionId: params.sessionId });
|
|
33892
34179
|
await eventHandler?.dispose();
|
|
34180
|
+
disposeGoalConnection();
|
|
34181
|
+
goalLifecycle.fail(new Error("ACP prompt closed"));
|
|
34182
|
+
activePrompt.signal.removeEventListener("abort", cancelGoalLifecycle);
|
|
33893
34183
|
disposePromptRequestCancellation();
|
|
33894
34184
|
sessionState.currentTurnId = null;
|
|
33895
34185
|
const registeredPendingTurnStart = this.pendingTurnStarts.get(params.sessionId);
|
|
@@ -33996,6 +34286,12 @@ ${stderr}` : "";
|
|
|
33996
34286
|
logger.log("Cancel request rejected: session not found", { sessionId: params.sessionId });
|
|
33997
34287
|
return;
|
|
33998
34288
|
}
|
|
34289
|
+
const activePrompt = this.activePrompts.get(params.sessionId);
|
|
34290
|
+
if (activePrompt?.hasCompletedTurn && activePrompt.currentTurn === null) {
|
|
34291
|
+
activePrompt.requestCancel();
|
|
34292
|
+
return;
|
|
34293
|
+
}
|
|
34294
|
+
if (activePrompt?.currentTurn) activePrompt.requestCancel();
|
|
33999
34295
|
await this.interruptSessionTurn(sessionState, "Cancel", false);
|
|
34000
34296
|
}
|
|
34001
34297
|
};
|