@alas-ide/codex-acp 2.5.0-alas.2 → 2.5.0-alas.3
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 +115 -19
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -40611,7 +40611,7 @@ var package_default = {
|
|
|
40611
40611
|
publishConfig: {
|
|
40612
40612
|
access: "public"
|
|
40613
40613
|
},
|
|
40614
|
-
version: "2.5.0-alas.
|
|
40614
|
+
version: "2.5.0-alas.3",
|
|
40615
40615
|
description: "",
|
|
40616
40616
|
main: "dist/index.js",
|
|
40617
40617
|
bin: {
|
|
@@ -40689,7 +40689,7 @@ var package_default = {
|
|
|
40689
40689
|
alasDownstream: {
|
|
40690
40690
|
upstreamVersion: "2.5.0",
|
|
40691
40691
|
upstreamCommit: "34e08970aa324a2be985f5080674d5aa91d7666f",
|
|
40692
|
-
sourceCommit: "
|
|
40692
|
+
sourceCommit: "de8d4c961871fc0584ca1bd89f31a8de95066c65"
|
|
40693
40693
|
}
|
|
40694
40694
|
};
|
|
40695
40695
|
|
|
@@ -40919,9 +40919,31 @@ var CodexSubagentSubscriptions = class {
|
|
|
40919
40919
|
|
|
40920
40920
|
// src/SessionFork.ts
|
|
40921
40921
|
import { createHash } from "node:crypto";
|
|
40922
|
+
var NEUTRAL_FORK_POINT_META_KEY = "forkPoint";
|
|
40923
|
+
var NEUTRAL_FORK_POINT_VERSION = 1;
|
|
40924
|
+
function neutralForkPointCapability() {
|
|
40925
|
+
return { version: NEUTRAL_FORK_POINT_VERSION, boundary: "turn" };
|
|
40926
|
+
}
|
|
40927
|
+
function clientRequestsNeutralForkPoint(capabilities) {
|
|
40928
|
+
const declared = capabilities?._meta?.[NEUTRAL_FORK_POINT_META_KEY];
|
|
40929
|
+
if (!isUnknownRecord(declared)) return false;
|
|
40930
|
+
const version2 = declared["version"];
|
|
40931
|
+
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= 1;
|
|
40932
|
+
}
|
|
40933
|
+
function hasNeutralForkPoint(meta3) {
|
|
40934
|
+
return meta3 != null && meta3[NEUTRAL_FORK_POINT_META_KEY] !== void 0;
|
|
40935
|
+
}
|
|
40936
|
+
function forkPointNotNegotiatedError() {
|
|
40937
|
+
return RequestError.invalidParams(
|
|
40938
|
+
{ [NEUTRAL_FORK_POINT_META_KEY]: { reason: "notNegotiated" } },
|
|
40939
|
+
"session/fork _meta.forkPoint needs initialize clientCapabilities._meta.forkPoint"
|
|
40940
|
+
);
|
|
40941
|
+
}
|
|
40922
40942
|
async function forkSession(request, additionalDirectories, dependencies, instructions) {
|
|
40943
|
+
const forkPoint = readForkPoint(request._meta);
|
|
40923
40944
|
await dependencies.refreshSkills(request.cwd, additionalDirectories);
|
|
40924
|
-
const
|
|
40945
|
+
const match = forkPoint ? await resolveForkPoint(request, forkPoint, dependencies.codexClient) : void 0;
|
|
40946
|
+
const lastTurnId = match?.turnId;
|
|
40925
40947
|
const sessionConfig = await dependencies.createSessionConfig(
|
|
40926
40948
|
request.cwd,
|
|
40927
40949
|
additionalDirectories,
|
|
@@ -40953,26 +40975,83 @@ async function forkSession(request, additionalDirectories, dependencies, instruc
|
|
|
40953
40975
|
currentServiceTier: response.serviceTier ?? null,
|
|
40954
40976
|
additionalDirectories,
|
|
40955
40977
|
skippedMcpServers: sessionConfig.skippedMcpServers,
|
|
40956
|
-
...instructions ? { instructions } : {}
|
|
40978
|
+
...instructions ? { instructions } : {},
|
|
40979
|
+
...forkPoint?.kind === "neutral" && match ? {
|
|
40980
|
+
forkPoint: {
|
|
40981
|
+
boundary: "turn",
|
|
40982
|
+
messageId: match.messageId,
|
|
40983
|
+
turnId: match.turnId,
|
|
40984
|
+
lastItemId: match.lastItemId,
|
|
40985
|
+
matchedBy: match.matchedBy
|
|
40986
|
+
}
|
|
40987
|
+
} : {}
|
|
40957
40988
|
};
|
|
40958
40989
|
}
|
|
40959
|
-
|
|
40960
|
-
|
|
40961
|
-
|
|
40990
|
+
function readForkPoint(meta3) {
|
|
40991
|
+
if (hasNeutralForkPoint(meta3)) return { kind: "neutral", ...readNeutralForkPoint(meta3[NEUTRAL_FORK_POINT_META_KEY]) };
|
|
40992
|
+
const air = readAirForkPoint(meta3);
|
|
40993
|
+
return air ? { kind: "air", ...air } : void 0;
|
|
40994
|
+
}
|
|
40995
|
+
async function resolveForkPoint(request, forkPoint, codexClient) {
|
|
40962
40996
|
const history = await codexClient.threadReadWithHistory(request.sessionId);
|
|
40963
|
-
const
|
|
40964
|
-
const
|
|
40965
|
-
|
|
40997
|
+
const turns = history.thread.turns;
|
|
40998
|
+
const matchById = (candidateId) => {
|
|
40999
|
+
const turn = turns.find((turn2) => turn2.items.some((item) => item.id === candidateId));
|
|
41000
|
+
return turn ? toMatch(turn, candidateId, "id") : void 0;
|
|
41001
|
+
};
|
|
41002
|
+
const candidateIds = forkPoint.kind === "air" ? airForkMessageIdCandidates(forkPoint.messageId) : [forkPoint.messageId];
|
|
41003
|
+
const idMatch = candidateIds.map(matchById).find((match) => match !== void 0);
|
|
41004
|
+
if (idMatch) return idMatch;
|
|
40966
41005
|
if (forkPoint.messageFingerprint) {
|
|
40967
|
-
const
|
|
40968
|
-
const
|
|
40969
|
-
|
|
41006
|
+
const renderCwd = history.thread.cwd ?? request.cwd;
|
|
41007
|
+
const clientText = forkPoint.kind === "neutral" ? (text) => renderFileCitations(text, renderCwd) : (text) => text;
|
|
41008
|
+
const matches = turns.flatMap((turn) => turn.items.filter((item) => item.type === "agentMessage" && fingerprintAgentMessage(clientText(item.text)) === forkPoint.messageFingerprint).map((item) => toMatch(turn, item.id, "fingerprint")));
|
|
41009
|
+
const fingerprintMatch = matches[forkPoint.messageOccurrence - 1];
|
|
41010
|
+
if (fingerprintMatch) return fingerprintMatch;
|
|
41011
|
+
}
|
|
41012
|
+
if (forkPoint.kind === "neutral") {
|
|
41013
|
+
throw RequestError.invalidParams(
|
|
41014
|
+
{ [NEUTRAL_FORK_POINT_META_KEY]: { messageId: forkPoint.messageId, reason: "notFound" } },
|
|
41015
|
+
`Fork point message ${forkPoint.messageId} was not found in session ${request.sessionId}`
|
|
41016
|
+
);
|
|
40970
41017
|
}
|
|
40971
41018
|
throw RequestError.invalidParams(
|
|
40972
41019
|
{ messageId: forkPoint.messageId },
|
|
40973
41020
|
`Fork point message ${forkPoint.messageId} was not found in session ${request.sessionId}`
|
|
40974
41021
|
);
|
|
40975
41022
|
}
|
|
41023
|
+
function toMatch(turn, messageId, matchedBy) {
|
|
41024
|
+
return { messageId, turnId: turn.id, lastItemId: turn.items.at(-1).id, matchedBy };
|
|
41025
|
+
}
|
|
41026
|
+
function readNeutralForkPoint(forkPoint) {
|
|
41027
|
+
const invalid = (field, message) => RequestError.invalidParams(
|
|
41028
|
+
{ [NEUTRAL_FORK_POINT_META_KEY]: { field } },
|
|
41029
|
+
`session/fork _meta.forkPoint: ${message}`
|
|
41030
|
+
);
|
|
41031
|
+
if (!isUnknownRecord(forkPoint)) throw invalid(NEUTRAL_FORK_POINT_META_KEY, "must be an object");
|
|
41032
|
+
const version2 = forkPoint["version"];
|
|
41033
|
+
if (version2 !== void 0 && version2 !== NEUTRAL_FORK_POINT_VERSION) {
|
|
41034
|
+
throw invalid("version", `version must be ${NEUTRAL_FORK_POINT_VERSION} when present`);
|
|
41035
|
+
}
|
|
41036
|
+
const messageId = forkPoint["messageId"];
|
|
41037
|
+
if (typeof messageId !== "string" || messageId.trim().length === 0) {
|
|
41038
|
+
throw invalid("messageId", "messageId must be a non-empty string");
|
|
41039
|
+
}
|
|
41040
|
+
const messageFingerprint = forkPoint["messageFingerprint"];
|
|
41041
|
+
if (messageFingerprint !== void 0 && (typeof messageFingerprint !== "string" || !SHA256_FINGERPRINT.test(messageFingerprint))) {
|
|
41042
|
+
throw invalid("messageFingerprint", "messageFingerprint must be sha256: and 64 lowercase hex digits");
|
|
41043
|
+
}
|
|
41044
|
+
const messageOccurrence = forkPoint["messageOccurrence"] ?? 1;
|
|
41045
|
+
if (!Number.isSafeInteger(messageOccurrence) || messageOccurrence < 1) {
|
|
41046
|
+
throw invalid("messageOccurrence", "messageOccurrence must be a positive integer");
|
|
41047
|
+
}
|
|
41048
|
+
return {
|
|
41049
|
+
messageId: messageId.trim(),
|
|
41050
|
+
...typeof messageFingerprint === "string" && { messageFingerprint },
|
|
41051
|
+
messageOccurrence
|
|
41052
|
+
};
|
|
41053
|
+
}
|
|
41054
|
+
var SHA256_FINGERPRINT = /^sha256:[0-9a-f]{64}$/;
|
|
40976
41055
|
function readAirForkPoint(meta3) {
|
|
40977
41056
|
const jetbrains = meta3?.["jetbrains"];
|
|
40978
41057
|
if (!isUnknownRecord(jetbrains)) return void 0;
|
|
@@ -40985,7 +41064,7 @@ function readAirForkPoint(meta3) {
|
|
|
40985
41064
|
throw RequestError.invalidParams(void 0, "AIR fork messageId must be a non-empty string");
|
|
40986
41065
|
}
|
|
40987
41066
|
const messageFingerprint = fork["messageFingerprint"];
|
|
40988
|
-
if (messageFingerprint !== void 0 && (typeof messageFingerprint !== "string" ||
|
|
41067
|
+
if (messageFingerprint !== void 0 && (typeof messageFingerprint !== "string" || !SHA256_FINGERPRINT.test(messageFingerprint))) {
|
|
40989
41068
|
throw RequestError.invalidParams(void 0, "AIR fork messageFingerprint must be a SHA-256 fingerprint");
|
|
40990
41069
|
}
|
|
40991
41070
|
const messageOccurrence = fork["messageOccurrence"] ?? 1;
|
|
@@ -52061,6 +52140,8 @@ var CodexAcpServer = class {
|
|
|
52061
52140
|
/** The capability choices of the client for tool call and plan reports. */
|
|
52062
52141
|
capabilities;
|
|
52063
52142
|
booleanConfigOptionsSupported;
|
|
52143
|
+
/** Whether the client opted into the client-neutral `session/fork` `_meta.forkPoint`. */
|
|
52144
|
+
neutralForkPointSupported = false;
|
|
52064
52145
|
/** Last `authStatus` pushed to the client; used to suppress duplicates. */
|
|
52065
52146
|
currentAuthStatus;
|
|
52066
52147
|
/**
|
|
@@ -52323,6 +52404,7 @@ var CodexAcpServer = class {
|
|
|
52323
52404
|
if (appServer) await appServer;
|
|
52324
52405
|
this.reportingConnection.reports.compareMeta = this.capabilities.airToolCallContract;
|
|
52325
52406
|
this.booleanConfigOptionsSupported = clientSupportsBooleanConfigOptions(_params.clientCapabilities);
|
|
52407
|
+
this.neutralForkPointSupported = clientRequestsNeutralForkPoint(_params.clientCapabilities);
|
|
52326
52408
|
this.sessionIndex.configure(_params.clientCapabilities);
|
|
52327
52409
|
this.hookReview.configure(_params.clientCapabilities?._meta?.["codexHooks"], this.capabilities.airClient);
|
|
52328
52410
|
await this.runWithProcessCheck(() => this.codexAcpClient.initialize(_params));
|
|
@@ -52382,6 +52464,7 @@ var CodexAcpServer = class {
|
|
|
52382
52464
|
if (appServer) await appServer;
|
|
52383
52465
|
this.reportingConnection.reports.compareMeta = this.capabilities.airToolCallContract;
|
|
52384
52466
|
this.booleanConfigOptionsSupported = true;
|
|
52467
|
+
this.neutralForkPointSupported = clientRequestsNeutralForkPoint(clientCapabilities);
|
|
52385
52468
|
this.sessionIndex.configure(clientCapabilities, { neutral: false });
|
|
52386
52469
|
await this.runWithProcessCheck(() => this.codexAcpClient.initialize({ clientInfo: params.info }));
|
|
52387
52470
|
this.sessionIndex.observe(this.codexAcpClient);
|
|
@@ -52466,6 +52549,10 @@ var CodexAcpServer = class {
|
|
|
52466
52549
|
"async-tasks": asyncTaskCapability()
|
|
52467
52550
|
} : {},
|
|
52468
52551
|
...this.hookReview.enabled ? { codexHooks: { version: 1, reviewToken: true } } : {},
|
|
52552
|
+
// The client-neutral fork point, see `docs/air-extensions.md`.
|
|
52553
|
+
...this.neutralForkPointSupported ? {
|
|
52554
|
+
[NEUTRAL_FORK_POINT_META_KEY]: neutralForkPointCapability()
|
|
52555
|
+
} : {},
|
|
52469
52556
|
// The session index for a client that opted in without AIR, see `docs/air-extensions.md`.
|
|
52470
52557
|
...neutralSessionIndex ? {
|
|
52471
52558
|
[NEUTRAL_SESSION_INDEX_META_KEY]: neutralSessionIndex
|
|
@@ -52759,7 +52846,7 @@ You have been logged out. Please try again.`);
|
|
|
52759
52846
|
this.sessionGenerations.set(sessionId, generation);
|
|
52760
52847
|
return generation;
|
|
52761
52848
|
}
|
|
52762
|
-
async tryCreateSession(request, operation = "sessionId" in request ? "resume" : "new") {
|
|
52849
|
+
async tryCreateSession(request, operation = "sessionId" in request ? "resume" : "new", onForked) {
|
|
52763
52850
|
clientSystemPromptText(request.systemPrompt);
|
|
52764
52851
|
const existingSessionRequest = request;
|
|
52765
52852
|
const previousInstructions = "sessionId" in request ? this.sessions.get(request.sessionId)?.instructions : void 0;
|
|
@@ -52810,6 +52897,7 @@ You have been logged out. Please try again.`);
|
|
|
52810
52897
|
previousInstructions
|
|
52811
52898
|
);
|
|
52812
52899
|
});
|
|
52900
|
+
onForked?.(sessionMetadata);
|
|
52813
52901
|
} else {
|
|
52814
52902
|
logger.log(`Create new session...`);
|
|
52815
52903
|
sessionMetadata = await this.runWithProcessCheck(() => {
|
|
@@ -53378,6 +53466,9 @@ You have been logged out. Please try again.`);
|
|
|
53378
53466
|
async forkSession(params) {
|
|
53379
53467
|
params = this.withV1SessionInstructionAppend(params);
|
|
53380
53468
|
clientSystemPromptText(params.systemPrompt);
|
|
53469
|
+
if (hasNeutralForkPoint(params._meta) && !this.neutralForkPointSupported) {
|
|
53470
|
+
throw forkPointNotNegotiatedError();
|
|
53471
|
+
}
|
|
53381
53472
|
this.assertInstructionsReady(params.sessionId);
|
|
53382
53473
|
return this.hookReview.run(
|
|
53383
53474
|
params.cwd,
|
|
@@ -53393,12 +53484,16 @@ You have been logged out. Please try again.`);
|
|
|
53393
53484
|
if (appServer) await appServer;
|
|
53394
53485
|
logger.log("Forking session...", { sessionId: params.sessionId });
|
|
53395
53486
|
try {
|
|
53396
|
-
|
|
53487
|
+
let forkPoint;
|
|
53488
|
+
const [sessionId, , modeState] = await this.tryCreateSession(params, "fork", (metadata) => {
|
|
53489
|
+
forkPoint = metadata.forkPoint;
|
|
53490
|
+
});
|
|
53397
53491
|
logger.log("Session forked", { sourceSessionId: params.sessionId, sessionId });
|
|
53398
53492
|
return {
|
|
53399
53493
|
sessionId,
|
|
53400
53494
|
modes: modeState,
|
|
53401
|
-
...this.createSessionConfigOptionsResponse(this.getSessionState(sessionId))
|
|
53495
|
+
...this.createSessionConfigOptionsResponse(this.getSessionState(sessionId)),
|
|
53496
|
+
...forkPoint ? { _meta: { [NEUTRAL_FORK_POINT_META_KEY]: forkPoint } } : {}
|
|
53402
53497
|
};
|
|
53403
53498
|
} catch (e) {
|
|
53404
53499
|
const error62 = e instanceof Error ? e : new Error(String(e));
|
|
@@ -53409,10 +53504,11 @@ You have been logged out. Please try again.`);
|
|
|
53409
53504
|
async forkSessionV2(params) {
|
|
53410
53505
|
const { systemPrompt, ...rest } = params;
|
|
53411
53506
|
const request = { ...rest, systemPrompt: toV1SystemPrompt(systemPrompt) };
|
|
53412
|
-
const { sessionId } = await this.forkSession(request);
|
|
53507
|
+
const { sessionId, _meta } = await this.forkSession(request);
|
|
53413
53508
|
return {
|
|
53414
53509
|
sessionId,
|
|
53415
|
-
...this.createSessionSetupResponseV2(this.getSessionState(sessionId))
|
|
53510
|
+
...this.createSessionSetupResponseV2(this.getSessionState(sessionId)),
|
|
53511
|
+
..._meta ? { _meta } : {}
|
|
53416
53512
|
};
|
|
53417
53513
|
}
|
|
53418
53514
|
async listSessions(params) {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.5.0-alas.
|
|
6
|
+
"version": "2.5.0-alas.3",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"bin": {
|
|
@@ -81,6 +81,6 @@
|
|
|
81
81
|
"alasDownstream": {
|
|
82
82
|
"upstreamVersion": "2.5.0",
|
|
83
83
|
"upstreamCommit": "34e08970aa324a2be985f5080674d5aa91d7666f",
|
|
84
|
-
"sourceCommit": "
|
|
84
|
+
"sourceCommit": "de8d4c961871fc0584ca1bd89f31a8de95066c65"
|
|
85
85
|
}
|
|
86
86
|
}
|