@p4code/cli 0.1.9 → 0.1.10
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/bin.mjs +1148 -999
- package/dist/client/assets/{DiffPanel-Bb72saoS.js → DiffPanel-BRroAgOK.js} +2 -2
- package/dist/client/assets/{FilePreviewPanel-6mJ-Vsub.js → FilePreviewPanel-Bdd2Ml_z.js} +2 -2
- package/dist/client/assets/{PreviewPanel-ogPpU8Ev.js → PreviewPanel-DoJd5FXR.js} +2 -2
- package/dist/client/assets/{angular-html-BIzUKsg7.js → angular-html-BA0WzHZ0.js} +2 -2
- package/dist/client/assets/{angular-ts-CSIA-4Zf.js → angular-ts-BehluKB7.js} +2 -2
- package/dist/client/assets/{apl-Du1uuPDy.js → apl-DPnuuIo7.js} +2 -2
- package/dist/client/assets/arrow-right-B_11zHBP.js +2 -0
- package/dist/client/assets/{astro-bVpCfC8I.js → astro-G6Zz-WSX.js} +2 -2
- package/dist/client/assets/{blade-KOd_hdA5.js → blade-c1NgE6B9.js} +2 -2
- package/dist/client/assets/{c-BUOUjYKH.js → c-BbDaxzL5.js} +2 -2
- package/dist/client/assets/{cobol-DVr6VPEj.js → cobol-DPWRf7_s.js} +2 -2
- package/dist/client/assets/{coffee-CaWTiLWu.js → coffee-kZI3-HKr.js} +2 -2
- package/dist/client/assets/{cpp-DOVxTtfq.js → cpp-DbB1uwNF.js} +2 -2
- package/dist/client/assets/{crystal-D_Q817Qu.js → crystal-C9rif4zq.js} +2 -2
- package/dist/client/assets/{css-Rez0Ry86.js → css-BzXrG2ii.js} +2 -2
- package/dist/client/assets/{edge-C5CKZJyo.js → edge-CIqg8jED.js} +2 -2
- package/dist/client/assets/{elixir-D_eVXxgH.js → elixir-L1xpfUlV.js} +2 -2
- package/dist/client/assets/{elm-BLkMkUJ0.js → elm-C4bqF3BU.js} +2 -2
- package/dist/client/assets/{erb-DGG0CxNR.js → erb-DQxpBRS7.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-D0gz9Nvl.js → fileCommentAnnotations-DXLRihuo.js} +2 -2
- package/dist/client/assets/{git-rebase-D7H5ArnN.js → git-rebase-DCFBvSos.js} +2 -2
- package/dist/client/assets/{glimmer-js-DOuFsyYy.js → glimmer-js-CMcw0KDm.js} +2 -2
- package/dist/client/assets/{glimmer-ts-C_dgMrVH.js → glimmer-ts-zKGsihEs.js} +2 -2
- package/dist/client/assets/{glsl-BJU0wvLz.js → glsl-C-DKYe1o.js} +2 -2
- package/dist/client/assets/{graphql-CXUg7dVm.js → graphql-D-Jaf-It.js} +2 -2
- package/dist/client/assets/{hack-DEwTpBBH.js → hack-Cy1Ek-eJ.js} +2 -2
- package/dist/client/assets/{haml-Br-Q1jfj.js → haml-DSBhTnP_.js} +2 -2
- package/dist/client/assets/{handlebars-U-qCMjLv.js → handlebars-BTjhBiVA.js} +2 -2
- package/dist/client/assets/{html-CBhkruiu.js → html-CuFf_rJP.js} +2 -2
- package/dist/client/assets/{html-derivative-CtOWonuc.js → html-derivative-B6vKETtb.js} +2 -2
- package/dist/client/assets/{http-B-anb7K2.js → http-TaTxS49l.js} +2 -2
- package/dist/client/assets/{hurl-UbSvk6zv.js → hurl-Jwth1u4b.js} +2 -2
- package/dist/client/assets/{index-CADZUNMb.js → index-WQyWsxuV.js} +200 -204
- package/dist/client/assets/index-nkPMSYxq.css +1 -0
- package/dist/client/assets/{java-d4Ae9Kq8.js → java-Ba5MdLVF.js} +2 -2
- package/dist/client/assets/{javascript-DENutVTd.js → javascript-_mHojD6_.js} +2 -2
- package/dist/client/assets/{jinja-Bugh_6jh.js → jinja-BhX9YpO0.js} +2 -2
- package/dist/client/assets/{jison-5v-Z1oHG.js → jison-S0Rrxw4o.js} +2 -2
- package/dist/client/assets/{json-BhFmIQh2.js → json-B-G4K1LM.js} +2 -2
- package/dist/client/assets/{jsx-ByAWu7n0.js → jsx-X6TBdO7T.js} +2 -2
- package/dist/client/assets/{julia-DE4JKJ_I.js → julia-He6A0R8c.js} +2 -2
- package/dist/client/assets/{just-Ck-bQzBW.js → just-CQ533yYC.js} +2 -2
- package/dist/client/assets/{latex-0aopGn_u.js → latex-BBBRtbj7.js} +2 -2
- package/dist/client/assets/{liquid-BOV6YY-4.js → liquid-CA9B-Q_J.js} +2 -2
- package/dist/client/assets/{lua-BS79SG5v.js → lua-DXLYC8yx.js} +2 -2
- package/dist/client/assets/{marko-CxCHVwvS.js → marko-BXfllCK7.js} +2 -2
- package/dist/client/assets/{mdc-D8ArMX_3.js → mdc-D13Xs_kf.js} +2 -2
- package/dist/client/assets/{nginx-54lPKP4l.js → nginx-HcisF7-i.js} +2 -2
- package/dist/client/assets/{nim-CQW1n-W6.js → nim-YbKRMFDo.js} +2 -2
- package/dist/client/assets/{perl-TGEf9BSy.js → perl-CV978rzN.js} +2 -2
- package/dist/client/assets/{php-CRSs0ljw.js → php-B8Rmr1r4.js} +2 -2
- package/dist/client/assets/{pug-B94qB-T3.js → pug-CI1Ka8om.js} +2 -2
- package/dist/client/assets/{qml-Ce-jpaqY.js → qml-CyQLZsMJ.js} +2 -2
- package/dist/client/assets/{r-Di-hq60i.js → r-C-0JMTYO.js} +2 -2
- package/dist/client/assets/{razor-VXC_c_VY.js → razor-BCppTDFk.js} +2 -2
- package/dist/client/assets/{regexp-DCuWLst8.js → regexp-DWt_neai.js} +2 -2
- package/dist/client/assets/{rst-CaleKCxt.js → rst-CDLeyhcr.js} +2 -2
- package/dist/client/assets/{ruby-BNvjj0Xx.js → ruby-Bq-7Grqk.js} +2 -2
- package/dist/client/assets/{sas-CN3Jyhxd.js → sas-Cn10Nqsd.js} +2 -2
- package/dist/client/assets/{scss-iGZoIRyN.js → scss-821PYndD.js} +2 -2
- package/dist/client/assets/{shellscript-B3Nk58br.js → shellscript-CGnWrTWh.js} +2 -2
- package/dist/client/assets/{shellsession-aV0EL5Me.js → shellsession-SoJX0uTA.js} +2 -2
- package/dist/client/assets/{soy-CK-MnjGK.js → soy-BDpemwx6.js} +2 -2
- package/dist/client/assets/{sql-WiqY-pg6.js → sql-BAre1tMG.js} +2 -2
- package/dist/client/assets/{stata-L2KCRIsj.js → stata-BVoUBbRH.js} +2 -2
- package/dist/client/assets/{surrealql-y8rFKpHp.js → surrealql-77kldaFv.js} +2 -2
- package/dist/client/assets/{svelte-BUjzGJjC.js → svelte-BrVa4Wrm.js} +2 -2
- package/dist/client/assets/{templ-Lwa6_2Pi.js → templ-DD-yE4Ei.js} +2 -2
- package/dist/client/assets/{tex-C6_2o8N6.js → tex-3Cd89BRS.js} +2 -2
- package/dist/client/assets/{textarea-C26NLrE0.js → textarea-DJbYd4DI.js} +2 -2
- package/dist/client/assets/{ts-tags-DHGXrdlY.js → ts-tags-CqnWMU9s.js} +2 -2
- package/dist/client/assets/{tsx-D7a2s_rX.js → tsx-C56Uu7is.js} +2 -2
- package/dist/client/assets/{twig-rodlH6R_.js → twig-2EWf2LgK.js} +2 -2
- package/dist/client/assets/{typescript-BSVnlc3E.js → typescript-DoXLYiyl.js} +2 -2
- package/dist/client/assets/{vue-CPqhBG4f.js → vue-DIv66ZbN.js} +2 -2
- package/dist/client/assets/{vue-html-DlcYUp9j.js → vue-html-DJnU3oci.js} +2 -2
- package/dist/client/assets/{vue-vine-C33vB5eU.js → vue-vine-CnFyQ4Cm.js} +2 -2
- package/dist/client/assets/{xml-Dk7HbObH.js → xml-DflQf7I-.js} +2 -2
- package/dist/client/assets/{xsl-Ce_0ufBe.js → xsl-DegV0fmP.js} +2 -2
- package/dist/client/assets/{yaml-hWCzaJrB.js → yaml-CQI6ctBx.js} +2 -2
- package/dist/client/index.html +3 -3
- package/package.json +1 -1
- package/dist/client/assets/arrow-right-qNd2lFlZ.js +0 -2
- package/dist/client/assets/index-CPnR_Tju.css +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -233,7 +233,7 @@ const make$73 = () => {
|
|
|
233
233
|
const layer$69 = Layer.sync(NetService, make$73);
|
|
234
234
|
//#endregion
|
|
235
235
|
//#region package.json
|
|
236
|
-
var version = "0.1.
|
|
236
|
+
var version = "0.1.10";
|
|
237
237
|
//#endregion
|
|
238
238
|
//#region src/config.ts
|
|
239
239
|
/**
|
|
@@ -5557,8 +5557,6 @@ const ClientSettingsSchema = Schema$1.Struct({
|
|
|
5557
5557
|
sidebarProjectSortOrder: SidebarProjectSortOrder.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_SIDEBAR_PROJECT_SORT_ORDER))),
|
|
5558
5558
|
sidebarThreadSortOrder: SidebarThreadSortOrder.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_SIDEBAR_THREAD_SORT_ORDER))),
|
|
5559
5559
|
sidebarThreadPreviewCount: SidebarThreadPreviewCount.pipe(Schema$1.withDecodingDefault(Effect.succeed(6))),
|
|
5560
|
-
sidebarV2Enabled: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(false))),
|
|
5561
|
-
sidebarV2ConfiguredByUser: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(false))),
|
|
5562
5560
|
timestampFormat: TimestampFormat.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_TIMESTAMP_FORMAT))),
|
|
5563
5561
|
wordWrap: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true)))
|
|
5564
5562
|
});
|
|
@@ -5905,8 +5903,6 @@ Schema$1.Struct({
|
|
|
5905
5903
|
sidebarProjectSortOrder: Schema$1.optionalKey(SidebarProjectSortOrder),
|
|
5906
5904
|
sidebarThreadSortOrder: Schema$1.optionalKey(SidebarThreadSortOrder),
|
|
5907
5905
|
sidebarThreadPreviewCount: Schema$1.optionalKey(SidebarThreadPreviewCount),
|
|
5908
|
-
sidebarV2Enabled: Schema$1.optionalKey(Schema$1.Boolean),
|
|
5909
|
-
sidebarV2ConfiguredByUser: Schema$1.optionalKey(Schema$1.Boolean),
|
|
5910
5906
|
timestampFormat: Schema$1.optionalKey(TimestampFormat),
|
|
5911
5907
|
wordWrap: Schema$1.optionalKey(Schema$1.Boolean)
|
|
5912
5908
|
});
|
|
@@ -28990,227 +28986,873 @@ const staticAndDevRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* (
|
|
|
28990
28986
|
contentType
|
|
28991
28987
|
});
|
|
28992
28988
|
}));
|
|
28993
|
-
|
|
28994
|
-
|
|
28995
|
-
|
|
28996
|
-
|
|
28997
|
-
|
|
28998
|
-
operation: CheckpointDiffOperation,
|
|
28999
|
-
threadId: ThreadId
|
|
29000
|
-
}) {
|
|
29001
|
-
get message() {
|
|
29002
|
-
const result = this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
|
|
29003
|
-
return `Checkpoint invariant violation in ${this.operation}: Computed ${result} result does not satisfy contract schema.`;
|
|
29004
|
-
}
|
|
29005
|
-
};
|
|
29006
|
-
/** Projection state no longer contains the requested checkpoint thread. */
|
|
29007
|
-
var CheckpointThreadNotFoundError = class extends Schema$1.TaggedErrorClass()("CheckpointThreadNotFoundError", {
|
|
29008
|
-
operation: CheckpointDiffOperation,
|
|
29009
|
-
threadId: ThreadId
|
|
29010
|
-
}) {
|
|
29011
|
-
get message() {
|
|
29012
|
-
return `Checkpoint invariant violation in ${this.operation}: Thread '${this.threadId}' not found.`;
|
|
29013
|
-
}
|
|
29014
|
-
};
|
|
29015
|
-
/** The checkpoint thread has no workspace path from which to compute a diff. */
|
|
29016
|
-
var CheckpointWorkspacePathMissingError = class extends Schema$1.TaggedErrorClass()("CheckpointWorkspacePathMissingError", {
|
|
29017
|
-
operation: CheckpointDiffOperation,
|
|
29018
|
-
threadId: ThreadId
|
|
29019
|
-
}) {
|
|
29020
|
-
get message() {
|
|
29021
|
-
const diff = this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
|
|
29022
|
-
return `Checkpoint invariant violation in ${this.operation}: Workspace path missing for thread '${this.threadId}' when computing ${diff}.`;
|
|
29023
|
-
}
|
|
29024
|
-
};
|
|
29025
|
-
/** The requested turn lies beyond the latest available checkpoint. */
|
|
29026
|
-
var CheckpointTurnRangeUnavailableError = class extends Schema$1.TaggedErrorClass()("CheckpointTurnRangeUnavailableError", {
|
|
29027
|
-
operation: CheckpointDiffOperation,
|
|
29028
|
-
threadId: ThreadId,
|
|
29029
|
-
requestedTurnCount: NonNegativeInt,
|
|
29030
|
-
availableTurnCount: NonNegativeInt
|
|
29031
|
-
}) {
|
|
29032
|
-
get message() {
|
|
29033
|
-
return `Checkpoint unavailable for thread ${this.threadId} turn ${this.requestedTurnCount}: Turn diff range exceeds current turn count: requested ${this.requestedTurnCount}, current ${this.availableTurnCount}.`;
|
|
28989
|
+
(() => {
|
|
28990
|
+
try {
|
|
28991
|
+
return process.env.NODE_ENV === "development";
|
|
28992
|
+
} catch {
|
|
28993
|
+
return false;
|
|
29034
28994
|
}
|
|
29035
|
-
};
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
|
|
28995
|
+
})();
|
|
28996
|
+
const COMMIT_METADATA_SPLIT = /(?=^From [a-f0-9]+ .+$)/m;
|
|
28997
|
+
const GIT_DIFF_FILE_BREAK_REGEX = /(?=^diff --git)/gm;
|
|
28998
|
+
const FILENAME_HEADER_REGEX = /^(---|\+\+\+)\s+([^\t\r\n]+)/;
|
|
28999
|
+
const FILENAME_HEADER_REGEX_GIT = /^(---|\+\+\+)\s+[ab]\/([^\t\r\n]+)/;
|
|
29000
|
+
const ALTERNATE_FILE_NAMES_GIT = /^diff --git (?:"a\/(.+?)"|a\/(.+?)) (?:"b\/(.+?)"|b\/(.+?))$/;
|
|
29001
|
+
const INDEX_LINE_METADATA = /^index ([0-9a-f]+)\.\.([0-9a-f]+)(?: (\d+))?$/i;
|
|
29002
|
+
Object.freeze({
|
|
29003
|
+
fromStart: 0,
|
|
29004
|
+
fromEnd: 0
|
|
29005
|
+
});
|
|
29006
|
+
//#endregion
|
|
29007
|
+
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/cleanLastNewline.js
|
|
29008
|
+
function cleanLastNewline(contents) {
|
|
29009
|
+
let end = contents.length;
|
|
29010
|
+
if (contents.charCodeAt(end - 1) === 10) {
|
|
29011
|
+
end--;
|
|
29012
|
+
if (contents.charCodeAt(end - 1) === 13) end--;
|
|
29045
29013
|
}
|
|
29046
|
-
|
|
29014
|
+
return contents.slice(0, end);
|
|
29015
|
+
}
|
|
29047
29016
|
//#endregion
|
|
29048
|
-
//#region
|
|
29049
|
-
const
|
|
29050
|
-
|
|
29051
|
-
|
|
29017
|
+
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/detachString.js
|
|
29018
|
+
const stringDetachEncoder = new TextEncoder();
|
|
29019
|
+
const stringDetachDecoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
29020
|
+
const SURROGATE_CODE_UNIT_PATTERN = /[\uD800-\uDFFF]/;
|
|
29021
|
+
const STRING_DETACH_INITIAL_BUFFER_SIZE = 1024;
|
|
29022
|
+
let stringDetachBuffer = new Uint8Array(STRING_DETACH_INITIAL_BUFFER_SIZE);
|
|
29023
|
+
function releaseStringDetachBuffer() {
|
|
29024
|
+
if (stringDetachBuffer.length !== STRING_DETACH_INITIAL_BUFFER_SIZE) stringDetachBuffer = new Uint8Array(STRING_DETACH_INITIAL_BUFFER_SIZE);
|
|
29052
29025
|
}
|
|
29053
|
-
function
|
|
29054
|
-
|
|
29055
|
-
if (
|
|
29056
|
-
|
|
29026
|
+
function detachString(value) {
|
|
29027
|
+
if (value.length === 0) return value;
|
|
29028
|
+
if (SURROGATE_CODE_UNIT_PATTERN.test(value)) return JSON.parse(JSON.stringify(value));
|
|
29029
|
+
const requiredByteLength = value.length * 3;
|
|
29030
|
+
if (stringDetachBuffer.length < requiredByteLength) stringDetachBuffer = new Uint8Array(requiredByteLength);
|
|
29031
|
+
const { written } = stringDetachEncoder.encodeInto(value, stringDetachBuffer);
|
|
29032
|
+
return stringDetachDecoder.decode(stringDetachBuffer.subarray(0, written));
|
|
29057
29033
|
}
|
|
29058
29034
|
//#endregion
|
|
29059
|
-
//#region
|
|
29060
|
-
function
|
|
29061
|
-
|
|
29062
|
-
|
|
29063
|
-
|
|
29064
|
-
|
|
29035
|
+
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/parsePatchFiles.js
|
|
29036
|
+
function processPatch(data, cacheKeyPrefix, throwOnError) {
|
|
29037
|
+
try {
|
|
29038
|
+
return _processPatch(data, cacheKeyPrefix, throwOnError);
|
|
29039
|
+
} finally {
|
|
29040
|
+
releaseStringDetachBuffer();
|
|
29065
29041
|
}
|
|
29066
|
-
return remoteNames;
|
|
29067
|
-
}
|
|
29068
|
-
function parseRemoteNames(stdout) {
|
|
29069
|
-
return parseRemoteNamesInGitOrder(stdout).toSorted((a, b) => b.length - a.length);
|
|
29070
29042
|
}
|
|
29071
|
-
function
|
|
29072
|
-
const
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
|
|
29077
|
-
|
|
29078
|
-
|
|
29079
|
-
|
|
29080
|
-
|
|
29081
|
-
|
|
29082
|
-
|
|
29083
|
-
|
|
29043
|
+
function _processPatch(data, cacheKeyPrefix, throwOnError = false) {
|
|
29044
|
+
const isGitDiff = isGitDiffPatch(data);
|
|
29045
|
+
const rawFiles = isGitDiff ? splitGitDiffFiles(data) : splitUnifiedDiffFiles(data);
|
|
29046
|
+
let patchMetadata;
|
|
29047
|
+
const files = [];
|
|
29048
|
+
for (const fileOrPatchMetadata of rawFiles) {
|
|
29049
|
+
if (isGitDiff && !GIT_DIFF_FILE_BREAK_REGEX.test(fileOrPatchMetadata)) {
|
|
29050
|
+
if (patchMetadata == null) patchMetadata = detachString(fileOrPatchMetadata);
|
|
29051
|
+
else if (throwOnError) throw Error("parsePatchContent: unknown file blob");
|
|
29052
|
+
else console.error("parsePatchContent: unknown file blob:", fileOrPatchMetadata);
|
|
29053
|
+
continue;
|
|
29054
|
+
} else if (!isGitDiff && !startsWithUnifiedDiffFileHeader(fileOrPatchMetadata)) {
|
|
29055
|
+
if (patchMetadata == null) patchMetadata = detachString(fileOrPatchMetadata);
|
|
29056
|
+
else if (throwOnError) throw Error("parsePatchContent: unknown file blob");
|
|
29057
|
+
else console.error("parsePatchContent: unknown file blob:", fileOrPatchMetadata);
|
|
29058
|
+
continue;
|
|
29059
|
+
}
|
|
29060
|
+
const currentFile = _processFile(fileOrPatchMetadata, {
|
|
29061
|
+
cacheKey: cacheKeyPrefix != null ? `${cacheKeyPrefix}-${files.length}` : void 0,
|
|
29062
|
+
isGitDiff,
|
|
29063
|
+
throwOnError
|
|
29064
|
+
});
|
|
29065
|
+
if (currentFile != null) files.push(currentFile);
|
|
29084
29066
|
}
|
|
29085
|
-
return null;
|
|
29086
|
-
}
|
|
29087
|
-
function extractBranchNameFromRemoteRef(ref, options) {
|
|
29088
|
-
const normalized = ref.trim();
|
|
29089
|
-
if (normalized.length === 0) return "";
|
|
29090
|
-
if (normalized.startsWith("refs/remotes/")) return extractBranchNameFromRemoteRef(normalized.slice(13), options);
|
|
29091
|
-
const parsedRemoteRef = parseRemoteRefWithRemoteNames(normalized, options?.remoteName ? [options.remoteName] : options?.remoteNames ?? []);
|
|
29092
|
-
if (parsedRemoteRef) return parsedRemoteRef.branchName;
|
|
29093
|
-
const firstSlash = normalized.indexOf("/");
|
|
29094
|
-
if (firstSlash === -1) return normalized;
|
|
29095
|
-
return normalized.slice(firstSlash + 1).trim();
|
|
29096
|
-
}
|
|
29097
|
-
//#endregion
|
|
29098
|
-
//#region src/vcs/GitVcsDriverCore.ts
|
|
29099
|
-
const DEFAULT_TIMEOUT_MS$5 = 3e4;
|
|
29100
|
-
const DEFAULT_MAX_OUTPUT_BYTES$1 = 1e6;
|
|
29101
|
-
const OUTPUT_TRUNCATED_MARKER$1 = "\n\n[truncated]";
|
|
29102
|
-
const PREPARED_COMMIT_PATCH_MAX_OUTPUT_BYTES = 49e3;
|
|
29103
|
-
const RANGE_COMMIT_SUMMARY_MAX_OUTPUT_BYTES = 19e3;
|
|
29104
|
-
const RANGE_DIFF_SUMMARY_MAX_OUTPUT_BYTES = 19e3;
|
|
29105
|
-
const RANGE_DIFF_PATCH_MAX_OUTPUT_BYTES = 59e3;
|
|
29106
|
-
const REVIEW_DIFF_PATCH_MAX_OUTPUT_BYTES = 12e4;
|
|
29107
|
-
const REVIEW_UNTRACKED_DIFF_MAX_OUTPUT_BYTES = 8e4;
|
|
29108
|
-
const WORKSPACE_FILES_MAX_OUTPUT_BYTES$1 = 12e4;
|
|
29109
|
-
const STATUS_UPSTREAM_REFRESH_INTERVAL = Duration.seconds(15);
|
|
29110
|
-
const STATUS_UPSTREAM_REFRESH_TIMEOUT = Duration.seconds(5);
|
|
29111
|
-
const STATUS_UPSTREAM_REFRESH_FAILURE_BASE_COOLDOWN = Duration.seconds(30);
|
|
29112
|
-
const STATUS_UPSTREAM_REFRESH_FAILURE_MAX_COOLDOWN = Duration.minutes(15);
|
|
29113
|
-
const STATUS_UPSTREAM_REFRESH_CACHE_CAPACITY = 2048;
|
|
29114
|
-
const REPOSITORY_PATHS_CACHE_CAPACITY = 2048;
|
|
29115
|
-
const REPOSITORY_PATHS_CACHE_TTL = Duration.minutes(10);
|
|
29116
|
-
const REPOSITORY_PATHS_REFRESH_COALESCE_TTL = Duration.seconds(5);
|
|
29117
|
-
const NON_REPOSITORY_PATHS_CACHE_TTL = Duration.seconds(1);
|
|
29118
|
-
const LIST_REFS_SNAPSHOT_CACHE_CAPACITY = 64;
|
|
29119
|
-
const LIST_REFS_SNAPSHOT_CACHE_TTL = Duration.minutes(2);
|
|
29120
|
-
const LIST_REFS_REFRESH_COALESCE_TTL = Duration.seconds(5);
|
|
29121
|
-
const LIST_REFS_REFRESH_FAILURE_COOLDOWN = Duration.seconds(30);
|
|
29122
|
-
const STATUS_UPSTREAM_REFRESH_ENV = Object.freeze({
|
|
29123
|
-
GCM_INTERACTIVE: "never",
|
|
29124
|
-
GIT_ASKPASS: "",
|
|
29125
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
29126
|
-
SSH_ASKPASS: "",
|
|
29127
|
-
SSH_ASKPASS_REQUIRE: "never"
|
|
29128
|
-
});
|
|
29129
|
-
const DEFAULT_BASE_BRANCH_CANDIDATES = ["main", "master"];
|
|
29130
|
-
const GIT_LIST_BRANCHES_DEFAULT_LIMIT = 100;
|
|
29131
|
-
const NON_REPOSITORY_STATUS_DETAILS = Object.freeze({
|
|
29132
|
-
isRepo: false,
|
|
29133
|
-
hasOriginRemote: false,
|
|
29134
|
-
isDefaultBranch: false,
|
|
29135
|
-
branch: null,
|
|
29136
|
-
upstreamRef: null,
|
|
29137
|
-
hasWorkingTreeChanges: false,
|
|
29138
|
-
workingTree: {
|
|
29139
|
-
files: [],
|
|
29140
|
-
insertions: 0,
|
|
29141
|
-
deletions: 0
|
|
29142
|
-
},
|
|
29143
|
-
hasUpstream: false,
|
|
29144
|
-
aheadCount: 0,
|
|
29145
|
-
behindCount: 0,
|
|
29146
|
-
aheadOfDefaultCount: 0
|
|
29147
|
-
});
|
|
29148
|
-
const NON_REPOSITORY_REMOTE_STATUS_DETAILS = Object.freeze({
|
|
29149
|
-
isRepo: false,
|
|
29150
|
-
isDefaultBranch: false,
|
|
29151
|
-
branch: null,
|
|
29152
|
-
upstreamRef: null,
|
|
29153
|
-
hasUpstream: false,
|
|
29154
|
-
aheadCount: 0,
|
|
29155
|
-
behindCount: 0,
|
|
29156
|
-
aheadOfDefaultCount: 0
|
|
29157
|
-
});
|
|
29158
|
-
var StatusRemoteRefreshCacheKey = class extends Data.Class {};
|
|
29159
|
-
function statusUpstreamRefreshFailureCooldown(consecutiveFailures) {
|
|
29160
|
-
const exponent = Math.max(0, consecutiveFailures - 1);
|
|
29161
|
-
const cooldownMs = Duration.toMillis(STATUS_UPSTREAM_REFRESH_FAILURE_BASE_COOLDOWN) * Math.pow(2, exponent);
|
|
29162
|
-
return Duration.min(Duration.millis(cooldownMs), STATUS_UPSTREAM_REFRESH_FAILURE_MAX_COOLDOWN);
|
|
29163
|
-
}
|
|
29164
|
-
var GitRefsSnapshotCacheKey = class extends Data.Class {};
|
|
29165
|
-
var GitRefsRefreshCacheKey = class extends Data.Class {};
|
|
29166
|
-
function parseBranchAb(value) {
|
|
29167
|
-
const match = value.match(/^\+(\d+)\s+-(\d+)$/);
|
|
29168
|
-
if (!match) return {
|
|
29169
|
-
ahead: 0,
|
|
29170
|
-
behind: 0
|
|
29171
|
-
};
|
|
29172
29067
|
return {
|
|
29173
|
-
|
|
29174
|
-
|
|
29068
|
+
patchMetadata,
|
|
29069
|
+
files
|
|
29175
29070
|
};
|
|
29176
29071
|
}
|
|
29177
|
-
function
|
|
29178
|
-
|
|
29179
|
-
|
|
29180
|
-
|
|
29181
|
-
|
|
29182
|
-
|
|
29183
|
-
|
|
29184
|
-
|
|
29185
|
-
const
|
|
29186
|
-
const
|
|
29187
|
-
|
|
29188
|
-
|
|
29189
|
-
|
|
29190
|
-
|
|
29191
|
-
|
|
29192
|
-
|
|
29072
|
+
function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREAK_REGEX.test(fileDiffString), oldFile, newFile, throwOnError = false } = {}) {
|
|
29073
|
+
let lastHunkEnd = 0;
|
|
29074
|
+
const hunks = splitAtLinePrefix(fileDiffString, "@@ ");
|
|
29075
|
+
let currentFile;
|
|
29076
|
+
const isPartial = oldFile == null || newFile == null;
|
|
29077
|
+
let deletionLineIndex = 0;
|
|
29078
|
+
let additionLineIndex = 0;
|
|
29079
|
+
for (const hunk of hunks) {
|
|
29080
|
+
const lines = splitWithNewlines(hunk);
|
|
29081
|
+
const firstLine = lines[0];
|
|
29082
|
+
if (firstLine == null) {
|
|
29083
|
+
if (throwOnError) throw Error("parsePatchContent: invalid hunk");
|
|
29084
|
+
else console.error("parsePatchContent: invalid hunk", hunk);
|
|
29085
|
+
continue;
|
|
29086
|
+
}
|
|
29087
|
+
const fileHeader = parseHunkHeader(firstLine);
|
|
29088
|
+
let additionLines = 0;
|
|
29089
|
+
let deletionLines = 0;
|
|
29090
|
+
if (fileHeader == null || currentFile == null) {
|
|
29091
|
+
if (currentFile != null) {
|
|
29092
|
+
if (throwOnError) throw Error("parsePatchContent: Invalid hunk");
|
|
29093
|
+
else console.error("parsePatchContent: Invalid hunk", hunk);
|
|
29094
|
+
continue;
|
|
29095
|
+
}
|
|
29096
|
+
currentFile = {
|
|
29097
|
+
name: "",
|
|
29098
|
+
type: "change",
|
|
29099
|
+
hunks: [],
|
|
29100
|
+
splitLineCount: 0,
|
|
29101
|
+
unifiedLineCount: 0,
|
|
29102
|
+
isPartial,
|
|
29103
|
+
additionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(newFile.contents) : [],
|
|
29104
|
+
deletionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(oldFile.contents) : [],
|
|
29105
|
+
cacheKey: maybeDetachOptionalString(cacheKey)
|
|
29106
|
+
};
|
|
29107
|
+
if (currentFile.additionLines.length === 1 && newFile?.contents === "") currentFile.additionLines.length = 0;
|
|
29108
|
+
if (currentFile.deletionLines.length === 1 && oldFile?.contents === "") currentFile.deletionLines.length = 0;
|
|
29109
|
+
for (const line of lines) {
|
|
29110
|
+
if (line.startsWith("diff --git")) {
|
|
29111
|
+
const filenameMatch$1 = line.trim().match(ALTERNATE_FILE_NAMES_GIT);
|
|
29112
|
+
const prevName = filenameMatch$1?.[1] ?? filenameMatch$1?.[2];
|
|
29113
|
+
const name = filenameMatch$1?.[3] ?? filenameMatch$1?.[4];
|
|
29114
|
+
if (prevName == null || name == null) {
|
|
29115
|
+
if (throwOnError) throw Error("parsePatchContent: invalid git diff header");
|
|
29116
|
+
else console.error("parsePatchContent: invalid git diff header", line);
|
|
29117
|
+
continue;
|
|
29118
|
+
}
|
|
29119
|
+
currentFile.name = detachString(name.trim());
|
|
29120
|
+
if (prevName !== name) currentFile.prevName = detachString(prevName.trim());
|
|
29121
|
+
continue;
|
|
29122
|
+
}
|
|
29123
|
+
const filenameMatch = line.startsWith("---") || line.startsWith("+++") ? line.match(isGitDiff ? FILENAME_HEADER_REGEX_GIT : FILENAME_HEADER_REGEX) : null;
|
|
29124
|
+
if (filenameMatch != null) {
|
|
29125
|
+
const [, type, fileName] = filenameMatch;
|
|
29126
|
+
if (type === "---" && fileName !== "/dev/null") {
|
|
29127
|
+
const detachedFileName = detachString(fileName.trim());
|
|
29128
|
+
currentFile.prevName = detachedFileName;
|
|
29129
|
+
currentFile.name = detachedFileName;
|
|
29130
|
+
} else if (type === "+++" && fileName !== "/dev/null") currentFile.name = detachString(fileName.trim());
|
|
29131
|
+
} else if (isGitDiff) {
|
|
29132
|
+
if (line.startsWith("new mode ")) currentFile.mode = detachString(line.slice(8).trim());
|
|
29133
|
+
if (line.startsWith("old mode ")) currentFile.prevMode = detachString(line.slice(8).trim());
|
|
29134
|
+
if (line.startsWith("new file mode")) {
|
|
29135
|
+
currentFile.type = "new";
|
|
29136
|
+
currentFile.mode = detachString(line.slice(13).trim());
|
|
29137
|
+
}
|
|
29138
|
+
if (line.startsWith("deleted file mode")) {
|
|
29139
|
+
currentFile.type = "deleted";
|
|
29140
|
+
currentFile.mode = detachString(line.slice(17).trim());
|
|
29141
|
+
}
|
|
29142
|
+
if (line.startsWith("similarity index")) if (line.startsWith("similarity index 100%")) currentFile.type = "rename-pure";
|
|
29143
|
+
else currentFile.type = "rename-changed";
|
|
29144
|
+
if (line.startsWith("index ")) {
|
|
29145
|
+
const [, prevObjectId, newObjectId, mode] = line.trim().match(INDEX_LINE_METADATA) ?? [];
|
|
29146
|
+
if (prevObjectId != null) currentFile.prevObjectId = detachString(prevObjectId);
|
|
29147
|
+
if (newObjectId != null) currentFile.newObjectId = detachString(newObjectId);
|
|
29148
|
+
if (mode != null) currentFile.mode = detachString(mode);
|
|
29149
|
+
}
|
|
29150
|
+
if (line.startsWith("rename from ")) currentFile.prevName = detachString(line.slice(12).trim());
|
|
29151
|
+
if (line.startsWith("rename to ")) currentFile.name = detachString(line.slice(10).trim());
|
|
29152
|
+
}
|
|
29153
|
+
}
|
|
29154
|
+
continue;
|
|
29155
|
+
}
|
|
29156
|
+
let currentContent;
|
|
29157
|
+
let lastLineType;
|
|
29158
|
+
while (lines.length > 0 && (lines[lines.length - 1] === "\n" || lines[lines.length - 1] === "\r" || lines[lines.length - 1] === "\r\n" || lines[lines.length - 1] === "")) lines.pop();
|
|
29159
|
+
const { additionStart, deletionStart } = fileHeader;
|
|
29160
|
+
deletionLineIndex = isPartial ? deletionLineIndex : deletionStart - 1;
|
|
29161
|
+
additionLineIndex = isPartial ? additionLineIndex : additionStart - 1;
|
|
29162
|
+
const hunkData = {
|
|
29163
|
+
collapsedBefore: 0,
|
|
29164
|
+
splitLineCount: 0,
|
|
29165
|
+
splitLineStart: 0,
|
|
29166
|
+
unifiedLineCount: 0,
|
|
29167
|
+
unifiedLineStart: 0,
|
|
29168
|
+
additionCount: fileHeader.additionCount,
|
|
29169
|
+
additionStart,
|
|
29170
|
+
additionLines,
|
|
29171
|
+
deletionCount: fileHeader.deletionCount,
|
|
29172
|
+
deletionStart,
|
|
29173
|
+
deletionLines,
|
|
29174
|
+
deletionLineIndex,
|
|
29175
|
+
additionLineIndex,
|
|
29176
|
+
hunkContent: [],
|
|
29177
|
+
hunkContext: maybeDetachOptionalString(fileHeader.hunkContext),
|
|
29178
|
+
hunkSpecs: detachString(firstLine),
|
|
29179
|
+
noEOFCRAdditions: false,
|
|
29180
|
+
noEOFCRDeletions: false
|
|
29181
|
+
};
|
|
29182
|
+
let parsedAdditionLines = 0;
|
|
29183
|
+
let parsedDeletionLines = 0;
|
|
29184
|
+
for (let lineIndex = 1; lineIndex < lines.length; lineIndex++) {
|
|
29185
|
+
const rawLine = lines[lineIndex];
|
|
29186
|
+
if (parsedAdditionLines >= hunkData.additionCount && parsedDeletionLines >= hunkData.deletionCount && !rawLine.startsWith("\\")) {
|
|
29187
|
+
if (throwOnError && isHunkBodyLine(rawLine) && !isFormatPatchVersionSeparator(rawLine)) throw Error("parsePatchContent: hunk has more lines than expected");
|
|
29188
|
+
break;
|
|
29189
|
+
}
|
|
29190
|
+
const firstChar = rawLine[0];
|
|
29191
|
+
if (firstChar !== "+" && firstChar !== "-" && firstChar !== " " && firstChar !== "\\") {
|
|
29192
|
+
if (throwOnError) throw Error("parsePatchContent: invalid hunk line");
|
|
29193
|
+
console.error(`parseLineType: Invalid firstChar: "${firstChar}", full line: "${rawLine}"`);
|
|
29194
|
+
console.error("processFile: invalid rawLine:", rawLine);
|
|
29195
|
+
continue;
|
|
29196
|
+
}
|
|
29197
|
+
const type = parseRawLineType(firstChar);
|
|
29198
|
+
if (type === "addition") {
|
|
29199
|
+
if (throwOnError && parsedAdditionLines >= hunkData.additionCount) throw Error("parsePatchContent: hunk has too many addition lines");
|
|
29200
|
+
const line = getParsedLineContent(rawLine);
|
|
29201
|
+
if (currentContent == null || currentContent.type !== "change") {
|
|
29202
|
+
currentContent = createContentGroup("change", deletionLineIndex, additionLineIndex);
|
|
29203
|
+
hunkData.hunkContent.push(currentContent);
|
|
29204
|
+
}
|
|
29205
|
+
additionLineIndex++;
|
|
29206
|
+
parsedAdditionLines++;
|
|
29207
|
+
if (isPartial) currentFile.additionLines.push(line);
|
|
29208
|
+
currentContent.additions++;
|
|
29209
|
+
additionLines++;
|
|
29210
|
+
lastLineType = "addition";
|
|
29211
|
+
} else if (type === "deletion") {
|
|
29212
|
+
if (throwOnError && parsedDeletionLines >= hunkData.deletionCount) throw Error("parsePatchContent: hunk has too many deletion lines");
|
|
29213
|
+
const line = getParsedLineContent(rawLine);
|
|
29214
|
+
if (currentContent == null || currentContent.type !== "change") {
|
|
29215
|
+
currentContent = createContentGroup("change", deletionLineIndex, additionLineIndex);
|
|
29216
|
+
hunkData.hunkContent.push(currentContent);
|
|
29217
|
+
}
|
|
29218
|
+
deletionLineIndex++;
|
|
29219
|
+
parsedDeletionLines++;
|
|
29220
|
+
if (isPartial) currentFile.deletionLines.push(line);
|
|
29221
|
+
currentContent.deletions++;
|
|
29222
|
+
deletionLines++;
|
|
29223
|
+
lastLineType = "deletion";
|
|
29224
|
+
} else if (type === "context") {
|
|
29225
|
+
if (throwOnError && (parsedDeletionLines >= hunkData.deletionCount || parsedAdditionLines >= hunkData.additionCount)) throw Error("parsePatchContent: hunk has too many context lines");
|
|
29226
|
+
const line = getParsedLineContent(rawLine);
|
|
29227
|
+
if (currentContent == null || currentContent.type !== "context") {
|
|
29228
|
+
currentContent = createContentGroup("context", deletionLineIndex, additionLineIndex);
|
|
29229
|
+
hunkData.hunkContent.push(currentContent);
|
|
29230
|
+
}
|
|
29231
|
+
additionLineIndex++;
|
|
29232
|
+
deletionLineIndex++;
|
|
29233
|
+
parsedAdditionLines++;
|
|
29234
|
+
parsedDeletionLines++;
|
|
29235
|
+
if (isPartial) {
|
|
29236
|
+
currentFile.deletionLines.push(line);
|
|
29237
|
+
currentFile.additionLines.push(line);
|
|
29238
|
+
}
|
|
29239
|
+
currentContent.lines++;
|
|
29240
|
+
lastLineType = "context";
|
|
29241
|
+
} else if (type === "metadata" && currentContent != null) {
|
|
29242
|
+
if (currentContent.type === "context") {
|
|
29243
|
+
hunkData.noEOFCRAdditions = true;
|
|
29244
|
+
hunkData.noEOFCRDeletions = true;
|
|
29245
|
+
} else if (lastLineType === "deletion") hunkData.noEOFCRDeletions = true;
|
|
29246
|
+
else if (lastLineType === "addition") hunkData.noEOFCRAdditions = true;
|
|
29247
|
+
if (isPartial && (lastLineType === "addition" || lastLineType === "context")) {
|
|
29248
|
+
const lastIndex = currentFile.additionLines.length - 1;
|
|
29249
|
+
if (lastIndex >= 0) currentFile.additionLines[lastIndex] = cleanLastNewline(currentFile.additionLines[lastIndex]);
|
|
29250
|
+
}
|
|
29251
|
+
if (isPartial && (lastLineType === "deletion" || lastLineType === "context")) {
|
|
29252
|
+
const lastIndex = currentFile.deletionLines.length - 1;
|
|
29253
|
+
if (lastIndex >= 0) currentFile.deletionLines[lastIndex] = cleanLastNewline(currentFile.deletionLines[lastIndex]);
|
|
29254
|
+
}
|
|
29255
|
+
}
|
|
29256
|
+
}
|
|
29257
|
+
if (throwOnError && (parsedAdditionLines !== hunkData.additionCount || parsedDeletionLines !== hunkData.deletionCount)) throw Error("parsePatchContent: hunk line count mismatch");
|
|
29258
|
+
hunkData.additionLines = additionLines;
|
|
29259
|
+
hunkData.deletionLines = deletionLines;
|
|
29260
|
+
hunkData.collapsedBefore = Math.max(hunkData.additionStart - 1 - lastHunkEnd, 0);
|
|
29261
|
+
currentFile.hunks.push(hunkData);
|
|
29262
|
+
lastHunkEnd = hunkData.additionStart + hunkData.additionCount - 1;
|
|
29263
|
+
for (const content of hunkData.hunkContent) if (content.type === "context") {
|
|
29264
|
+
hunkData.splitLineCount += content.lines;
|
|
29265
|
+
hunkData.unifiedLineCount += content.lines;
|
|
29266
|
+
} else {
|
|
29267
|
+
hunkData.splitLineCount += Math.max(content.additions, content.deletions);
|
|
29268
|
+
hunkData.unifiedLineCount += content.deletions + content.additions;
|
|
29269
|
+
}
|
|
29270
|
+
hunkData.splitLineStart = currentFile.splitLineCount + hunkData.collapsedBefore;
|
|
29271
|
+
hunkData.unifiedLineStart = currentFile.unifiedLineCount + hunkData.collapsedBefore;
|
|
29272
|
+
currentFile.splitLineCount += hunkData.collapsedBefore + hunkData.splitLineCount;
|
|
29273
|
+
currentFile.unifiedLineCount += hunkData.collapsedBefore + hunkData.unifiedLineCount;
|
|
29193
29274
|
}
|
|
29194
|
-
return
|
|
29195
|
-
|
|
29196
|
-
|
|
29197
|
-
|
|
29198
|
-
const
|
|
29199
|
-
|
|
29275
|
+
if (currentFile == null) return;
|
|
29276
|
+
if (throwOnError && isPartial && !isGitDiff && currentFile.hunks.length === 0) throw Error("parsePatchContent: unified file has no hunks");
|
|
29277
|
+
if (currentFile.hunks.length > 0 && !isPartial && currentFile.additionLines.length > 0 && currentFile.deletionLines.length > 0) {
|
|
29278
|
+
const lastHunk = currentFile.hunks[currentFile.hunks.length - 1];
|
|
29279
|
+
const lastHunkEnd$1 = lastHunk.additionStart + lastHunk.additionCount - 1;
|
|
29280
|
+
const totalFileLines = currentFile.additionLines.length;
|
|
29281
|
+
const collapsedAfter = Math.max(totalFileLines - lastHunkEnd$1, 0);
|
|
29282
|
+
currentFile.splitLineCount += collapsedAfter;
|
|
29283
|
+
currentFile.unifiedLineCount += collapsedAfter;
|
|
29200
29284
|
}
|
|
29201
|
-
if (!
|
|
29202
|
-
|
|
29203
|
-
|
|
29204
|
-
|
|
29205
|
-
|
|
29285
|
+
if (!isGitDiff) {
|
|
29286
|
+
if (currentFile.prevName != null && currentFile.name !== currentFile.prevName) if (currentFile.hunks.length > 0) currentFile.type = "rename-changed";
|
|
29287
|
+
else currentFile.type = "rename-pure";
|
|
29288
|
+
else if ((oldFile == null || oldFile.contents === "") && newFile != null && newFile.contents !== "") currentFile.type = "new";
|
|
29289
|
+
else if (oldFile != null && oldFile.contents !== "" && (newFile == null || newFile.contents === "")) currentFile.type = "deleted";
|
|
29206
29290
|
}
|
|
29207
|
-
|
|
29208
|
-
return
|
|
29291
|
+
if (currentFile.type !== "rename-pure" && currentFile.type !== "rename-changed") currentFile.prevName = void 0;
|
|
29292
|
+
return currentFile;
|
|
29209
29293
|
}
|
|
29210
|
-
|
|
29211
|
-
|
|
29212
|
-
|
|
29213
|
-
|
|
29294
|
+
/**
|
|
29295
|
+
* Parses a patch file string into an array of parsed patches.
|
|
29296
|
+
*
|
|
29297
|
+
* @param data - The raw patch file content (supports multi-commit patches)
|
|
29298
|
+
* @param cacheKeyPrefix - Optional prefix for generating cache keys. When provided,
|
|
29299
|
+
* each file in the patch will get a cache key in the format `prefix-patchIndex-fileIndex`.
|
|
29300
|
+
* This enables caching of rendered diff results in the worker pool.
|
|
29301
|
+
*/
|
|
29302
|
+
function parsePatchFiles(data, cacheKeyPrefix, throwOnError = false) {
|
|
29303
|
+
const patches = [];
|
|
29304
|
+
const rawPatches = hasCommitMetadataBoundary(data) ? data.split(COMMIT_METADATA_SPLIT) : [data];
|
|
29305
|
+
for (const patch of rawPatches) try {
|
|
29306
|
+
patches.push(processPatch(patch, cacheKeyPrefix != null ? `${cacheKeyPrefix}-${patches.length}` : void 0, throwOnError));
|
|
29307
|
+
} catch (error) {
|
|
29308
|
+
if (throwOnError) throw error;
|
|
29309
|
+
else console.error(error);
|
|
29310
|
+
}
|
|
29311
|
+
return patches;
|
|
29312
|
+
}
|
|
29313
|
+
function hasCommitMetadataBoundary(data) {
|
|
29314
|
+
return data.startsWith("From ") || data.includes("\nFrom ");
|
|
29315
|
+
}
|
|
29316
|
+
function splitFileContents(contents) {
|
|
29317
|
+
const lines = splitWithNewlines(contents);
|
|
29318
|
+
for (let index = 0; index < lines.length; index++) lines[index] = detachString(lines[index]);
|
|
29319
|
+
return lines;
|
|
29320
|
+
}
|
|
29321
|
+
function splitWithNewlines(contents) {
|
|
29322
|
+
if (contents.length === 0) return [""];
|
|
29323
|
+
const lines = [];
|
|
29324
|
+
let startIndex = 0;
|
|
29325
|
+
for (;;) {
|
|
29326
|
+
const newlineIndex = contents.indexOf("\n", startIndex);
|
|
29327
|
+
if (newlineIndex === -1) break;
|
|
29328
|
+
lines.push(contents.slice(startIndex, newlineIndex + 1));
|
|
29329
|
+
startIndex = newlineIndex + 1;
|
|
29330
|
+
}
|
|
29331
|
+
if (startIndex < contents.length) lines.push(contents.slice(startIndex));
|
|
29332
|
+
return lines;
|
|
29333
|
+
}
|
|
29334
|
+
function splitGitDiffFiles(contents) {
|
|
29335
|
+
return splitAtLinePrefix(contents, "diff --git");
|
|
29336
|
+
}
|
|
29337
|
+
function splitUnifiedDiffFiles(contents) {
|
|
29338
|
+
if (contents.length === 0) return [""];
|
|
29339
|
+
const parts = [];
|
|
29340
|
+
let partStartIndex = 0;
|
|
29341
|
+
let lineStartIndex = 0;
|
|
29342
|
+
let remainingDeletionLines = 0;
|
|
29343
|
+
let remainingAdditionLines = 0;
|
|
29344
|
+
let hasOpenedUnifiedFile = false;
|
|
29345
|
+
while (lineStartIndex < contents.length) {
|
|
29346
|
+
const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);
|
|
29347
|
+
if (remainingDeletionLines <= 0 && remainingAdditionLines <= 0) {
|
|
29348
|
+
if (isUnifiedDiffFileHeaderAt(contents, lineStartIndex)) {
|
|
29349
|
+
if (lineStartIndex > partStartIndex) parts.push(contents.slice(partStartIndex, lineStartIndex));
|
|
29350
|
+
partStartIndex = lineStartIndex;
|
|
29351
|
+
hasOpenedUnifiedFile = true;
|
|
29352
|
+
lineStartIndex = getNextLineStartIndex(contents, nextLineStartIndex);
|
|
29353
|
+
continue;
|
|
29354
|
+
}
|
|
29355
|
+
if (hasOpenedUnifiedFile && contents.startsWith("@@ -", lineStartIndex)) {
|
|
29356
|
+
const fileHeader = parseHunkHeader(contents.slice(lineStartIndex, nextLineStartIndex));
|
|
29357
|
+
if (fileHeader != null) {
|
|
29358
|
+
remainingDeletionLines = fileHeader.deletionCount;
|
|
29359
|
+
remainingAdditionLines = fileHeader.additionCount;
|
|
29360
|
+
}
|
|
29361
|
+
}
|
|
29362
|
+
lineStartIndex = nextLineStartIndex;
|
|
29363
|
+
continue;
|
|
29364
|
+
}
|
|
29365
|
+
const firstChar = contents[lineStartIndex];
|
|
29366
|
+
if (firstChar === "\\") {
|
|
29367
|
+
lineStartIndex = nextLineStartIndex;
|
|
29368
|
+
continue;
|
|
29369
|
+
}
|
|
29370
|
+
if (firstChar === " ") {
|
|
29371
|
+
remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);
|
|
29372
|
+
remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);
|
|
29373
|
+
} else if (firstChar === "-") remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);
|
|
29374
|
+
else if (firstChar === "+") remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);
|
|
29375
|
+
lineStartIndex = nextLineStartIndex;
|
|
29376
|
+
}
|
|
29377
|
+
parts.push(contents.slice(partStartIndex));
|
|
29378
|
+
return parts;
|
|
29379
|
+
}
|
|
29380
|
+
function startsWithUnifiedDiffFileHeader(contents) {
|
|
29381
|
+
return isUnifiedDiffFileHeaderAt(contents, 0);
|
|
29382
|
+
}
|
|
29383
|
+
function isUnifiedDiffFileHeaderAt(contents, lineStartIndex) {
|
|
29384
|
+
const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);
|
|
29385
|
+
return isUnifiedDiffHeaderLineAt(contents, lineStartIndex, "---") && isUnifiedDiffHeaderLineAt(contents, nextLineStartIndex, "+++");
|
|
29386
|
+
}
|
|
29387
|
+
function isUnifiedDiffHeaderLineAt(contents, lineStartIndex, prefix) {
|
|
29388
|
+
if (!contents.startsWith(prefix, lineStartIndex)) return false;
|
|
29389
|
+
const separator = contents[lineStartIndex + prefix.length];
|
|
29390
|
+
if (separator !== " " && separator !== " ") return false;
|
|
29391
|
+
for (let index = lineStartIndex + prefix.length + 1; index < contents.length; index++) {
|
|
29392
|
+
const char = contents[index];
|
|
29393
|
+
if (char === "\n" || char === "\r") break;
|
|
29394
|
+
if (char !== " " && char !== " ") return true;
|
|
29395
|
+
}
|
|
29396
|
+
return false;
|
|
29397
|
+
}
|
|
29398
|
+
function getNextLineStartIndex(contents, lineStartIndex) {
|
|
29399
|
+
const newlineIndex = contents.indexOf("\n", lineStartIndex);
|
|
29400
|
+
return newlineIndex === -1 ? contents.length : newlineIndex + 1;
|
|
29401
|
+
}
|
|
29402
|
+
function isHunkBodyLine(line) {
|
|
29403
|
+
const firstChar = line[0];
|
|
29404
|
+
return firstChar === "+" || firstChar === "-" || firstChar === " ";
|
|
29405
|
+
}
|
|
29406
|
+
function isFormatPatchVersionSeparator(line) {
|
|
29407
|
+
if (!line.startsWith("--")) return false;
|
|
29408
|
+
for (let index = 2; index < line.length; index++) {
|
|
29409
|
+
const char = line[index];
|
|
29410
|
+
if (char !== " " && char !== " " && char !== "\n" && char !== "\r") return false;
|
|
29411
|
+
}
|
|
29412
|
+
return true;
|
|
29413
|
+
}
|
|
29414
|
+
function parseHunkHeader(line) {
|
|
29415
|
+
if (!line.startsWith("@@ -")) return;
|
|
29416
|
+
let index = 4;
|
|
29417
|
+
const deletionStartResult = readPositiveInteger(line, index);
|
|
29418
|
+
if (deletionStartResult == null) return;
|
|
29419
|
+
const deletionStart = deletionStartResult.value;
|
|
29420
|
+
index = deletionStartResult.endIndex;
|
|
29421
|
+
let deletionCount = 1;
|
|
29422
|
+
if (line[index] === ",") {
|
|
29423
|
+
const deletionCountResult = readPositiveInteger(line, index + 1);
|
|
29424
|
+
if (deletionCountResult == null) return;
|
|
29425
|
+
deletionCount = deletionCountResult.value;
|
|
29426
|
+
index = deletionCountResult.endIndex;
|
|
29427
|
+
}
|
|
29428
|
+
if (line[index] !== " " || line[index + 1] !== "+") return;
|
|
29429
|
+
index += 2;
|
|
29430
|
+
const additionStartResult = readPositiveInteger(line, index);
|
|
29431
|
+
if (additionStartResult == null) return;
|
|
29432
|
+
const additionStart = additionStartResult.value;
|
|
29433
|
+
index = additionStartResult.endIndex;
|
|
29434
|
+
let additionCount = 1;
|
|
29435
|
+
if (line[index] === ",") {
|
|
29436
|
+
const additionCountResult = readPositiveInteger(line, index + 1);
|
|
29437
|
+
if (additionCountResult == null) return;
|
|
29438
|
+
additionCount = additionCountResult.value;
|
|
29439
|
+
index = additionCountResult.endIndex;
|
|
29440
|
+
}
|
|
29441
|
+
if (line[index] !== " " || line[index + 1] !== "@" || line[index + 2] !== "@") return;
|
|
29442
|
+
let hunkContext;
|
|
29443
|
+
const contextStartIndex = index + 3;
|
|
29444
|
+
if (line[contextStartIndex] === " ") hunkContext = trimLineEnd(line.slice(contextStartIndex + 1));
|
|
29445
|
+
return {
|
|
29446
|
+
additionCount,
|
|
29447
|
+
additionStart,
|
|
29448
|
+
deletionCount,
|
|
29449
|
+
deletionStart,
|
|
29450
|
+
hunkContext
|
|
29451
|
+
};
|
|
29452
|
+
}
|
|
29453
|
+
function readPositiveInteger(value, startIndex) {
|
|
29454
|
+
let index = startIndex;
|
|
29455
|
+
let parsedValue = 0;
|
|
29456
|
+
for (; index < value.length; index++) {
|
|
29457
|
+
const digit = value.charCodeAt(index) - 48;
|
|
29458
|
+
if (digit < 0 || digit > 9) break;
|
|
29459
|
+
parsedValue = parsedValue * 10 + digit;
|
|
29460
|
+
}
|
|
29461
|
+
if (index === startIndex) return;
|
|
29462
|
+
return {
|
|
29463
|
+
value: parsedValue,
|
|
29464
|
+
endIndex: index
|
|
29465
|
+
};
|
|
29466
|
+
}
|
|
29467
|
+
function trimLineEnd(value) {
|
|
29468
|
+
if (value.endsWith("\r\n")) return value.slice(0, -2);
|
|
29469
|
+
if (value.endsWith("\n")) return value.slice(0, -1);
|
|
29470
|
+
return value;
|
|
29471
|
+
}
|
|
29472
|
+
function isGitDiffPatch(data) {
|
|
29473
|
+
return data.startsWith("diff --git") || data.includes("\ndiff --git");
|
|
29474
|
+
}
|
|
29475
|
+
function splitAtLinePrefix(contents, prefix) {
|
|
29476
|
+
if (contents.length === 0) return [""];
|
|
29477
|
+
const newlinePrefix = `\n${prefix}`;
|
|
29478
|
+
const firstBoundaryIndex = contents.startsWith(prefix) ? 0 : findLinePrefixIndex(contents, newlinePrefix, 0);
|
|
29479
|
+
if (firstBoundaryIndex === -1) return [contents];
|
|
29480
|
+
const parts = [];
|
|
29481
|
+
if (firstBoundaryIndex > 0) parts.push(contents.slice(0, firstBoundaryIndex));
|
|
29482
|
+
let startIndex = firstBoundaryIndex;
|
|
29483
|
+
for (;;) {
|
|
29484
|
+
const nextBoundaryIndex = findLinePrefixIndex(contents, newlinePrefix, startIndex + 1);
|
|
29485
|
+
if (nextBoundaryIndex === -1) break;
|
|
29486
|
+
parts.push(contents.slice(startIndex, nextBoundaryIndex));
|
|
29487
|
+
startIndex = nextBoundaryIndex;
|
|
29488
|
+
}
|
|
29489
|
+
parts.push(contents.slice(startIndex));
|
|
29490
|
+
return parts;
|
|
29491
|
+
}
|
|
29492
|
+
function findLinePrefixIndex(contents, newlinePrefix, fromIndex) {
|
|
29493
|
+
const index = contents.indexOf(newlinePrefix, fromIndex);
|
|
29494
|
+
return index === -1 ? -1 : index + 1;
|
|
29495
|
+
}
|
|
29496
|
+
function maybeDetachOptionalString(value) {
|
|
29497
|
+
return value == null ? value : detachString(value);
|
|
29498
|
+
}
|
|
29499
|
+
function parseRawLineType(firstChar) {
|
|
29500
|
+
return firstChar === " " ? "context" : firstChar === "\\" ? "metadata" : firstChar === "+" ? "addition" : "deletion";
|
|
29501
|
+
}
|
|
29502
|
+
function getParsedLineContent(rawLine) {
|
|
29503
|
+
const processedLine = rawLine.slice(1);
|
|
29504
|
+
return detachString(processedLine === "" ? "\n" : processedLine);
|
|
29505
|
+
}
|
|
29506
|
+
function createContentGroup(type, deletionLineIndex, additionLineIndex) {
|
|
29507
|
+
if (type === "change") return {
|
|
29508
|
+
type: "change",
|
|
29509
|
+
additions: 0,
|
|
29510
|
+
deletions: 0,
|
|
29511
|
+
additionLineIndex,
|
|
29512
|
+
deletionLineIndex
|
|
29513
|
+
};
|
|
29514
|
+
return {
|
|
29515
|
+
type: "context",
|
|
29516
|
+
lines: 0,
|
|
29517
|
+
additionLineIndex,
|
|
29518
|
+
deletionLineIndex
|
|
29519
|
+
};
|
|
29520
|
+
}
|
|
29521
|
+
//#endregion
|
|
29522
|
+
//#region src/checkpointing/ThreadChangedFiles.ts
|
|
29523
|
+
/**
|
|
29524
|
+
* Per-thread changed-file attribution for checkpoint diffs.
|
|
29525
|
+
*
|
|
29526
|
+
* A checkpoint snapshots the whole working tree (`git add -A`), so on a shared
|
|
29527
|
+
* worktree the diff between two of a thread's checkpoints also contains every
|
|
29528
|
+
* edit other threads made in the window. The thread's own tool activities are
|
|
29529
|
+
* per-thread by construction, and the inline changed-files summary the clients
|
|
29530
|
+
* derive from them is already the surface users trust. These helpers extract
|
|
29531
|
+
* that same path list on the server and cut a checkpoint diff down to it.
|
|
29532
|
+
*
|
|
29533
|
+
* `collectActivityChangedFilePaths` must stay in lockstep with
|
|
29534
|
+
* `collectChangedFiles` in `apps/web/src/session-logic.ts` (and the mobile
|
|
29535
|
+
* copy in `threadActivity.ts`): same field names, same nested keys, same depth
|
|
29536
|
+
* bound. The one deliberate difference is dropping the cap of 12 paths - that
|
|
29537
|
+
* cap exists for display, and a filter that stopped collecting would silently
|
|
29538
|
+
* drop real work from the diff.
|
|
29539
|
+
*
|
|
29540
|
+
* @module ThreadChangedFiles
|
|
29541
|
+
*/
|
|
29542
|
+
const CHANGED_FILE_FIELDS = [
|
|
29543
|
+
"path",
|
|
29544
|
+
"filePath",
|
|
29545
|
+
"relativePath",
|
|
29546
|
+
"filename",
|
|
29547
|
+
"newPath",
|
|
29548
|
+
"oldPath"
|
|
29549
|
+
];
|
|
29550
|
+
const NESTED_PAYLOAD_KEYS = [
|
|
29551
|
+
"item",
|
|
29552
|
+
"result",
|
|
29553
|
+
"input",
|
|
29554
|
+
"data",
|
|
29555
|
+
"changes",
|
|
29556
|
+
"files",
|
|
29557
|
+
"edits",
|
|
29558
|
+
"patch",
|
|
29559
|
+
"patches",
|
|
29560
|
+
"operations"
|
|
29561
|
+
];
|
|
29562
|
+
const MAX_COLLECT_DEPTH = 4;
|
|
29563
|
+
function asRecord$3(value) {
|
|
29564
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
29565
|
+
}
|
|
29566
|
+
function pushChangedFilePath(target, value) {
|
|
29567
|
+
if (typeof value !== "string") return;
|
|
29568
|
+
const normalized = value.trim();
|
|
29569
|
+
if (normalized.length === 0) return;
|
|
29570
|
+
target.add(normalized);
|
|
29571
|
+
}
|
|
29572
|
+
function collectChangedFilePaths(value, target, depth) {
|
|
29573
|
+
if (depth > MAX_COLLECT_DEPTH) return;
|
|
29574
|
+
if (Array.isArray(value)) {
|
|
29575
|
+
for (const entry of value) collectChangedFilePaths(entry, target, depth + 1);
|
|
29576
|
+
return;
|
|
29577
|
+
}
|
|
29578
|
+
const record = asRecord$3(value);
|
|
29579
|
+
if (!record) return;
|
|
29580
|
+
for (const field of CHANGED_FILE_FIELDS) pushChangedFilePath(target, record[field]);
|
|
29581
|
+
for (const nestedKey of NESTED_PAYLOAD_KEYS) if (nestedKey in record) collectChangedFilePaths(record[nestedKey], target, depth + 1);
|
|
29582
|
+
}
|
|
29583
|
+
/**
|
|
29584
|
+
* Extract the file paths a single activity payload names, exactly as the
|
|
29585
|
+
* clients do for the inline changed-files summary.
|
|
29586
|
+
*/
|
|
29587
|
+
function collectActivityChangedFilePaths(payload) {
|
|
29588
|
+
const target = /* @__PURE__ */ new Set();
|
|
29589
|
+
collectChangedFilePaths(asRecord$3(asRecord$3(payload)?.data), target, 0);
|
|
29590
|
+
return target;
|
|
29591
|
+
}
|
|
29592
|
+
/**
|
|
29593
|
+
* Normalize activity-named paths to the workspace-relative form git patches
|
|
29594
|
+
* use. Adapters report paths as the tool received them, which may be absolute;
|
|
29595
|
+
* a path outside the workspace cannot appear in the checkpoint diff and is
|
|
29596
|
+
* dropped rather than mismatched.
|
|
29597
|
+
*/
|
|
29598
|
+
function normalizeChangedFilePaths(changedPaths, workspaceCwd) {
|
|
29599
|
+
const workspacePrefix = workspaceCwd.endsWith("/") ? workspaceCwd : `${workspaceCwd}/`;
|
|
29600
|
+
const normalized = /* @__PURE__ */ new Set();
|
|
29601
|
+
for (const changedPath of changedPaths) {
|
|
29602
|
+
let candidate = changedPath;
|
|
29603
|
+
if (candidate.startsWith(workspacePrefix)) candidate = candidate.slice(workspacePrefix.length);
|
|
29604
|
+
else if (candidate.startsWith("/")) continue;
|
|
29605
|
+
else if (candidate.startsWith("./")) candidate = candidate.slice(2);
|
|
29606
|
+
if (candidate.length > 0) normalized.add(candidate);
|
|
29607
|
+
}
|
|
29608
|
+
return normalized;
|
|
29609
|
+
}
|
|
29610
|
+
const DIFF_FILE_HEADER = /^diff --git /gm;
|
|
29611
|
+
function splitUnifiedDiffBlocks(diff) {
|
|
29612
|
+
const starts = [];
|
|
29613
|
+
for (const match of diff.matchAll(DIFF_FILE_HEADER)) starts.push(match.index);
|
|
29614
|
+
return starts.map((start, index) => diff.slice(start, starts[index + 1]));
|
|
29615
|
+
}
|
|
29616
|
+
function blockNamesPath(block, allowedPaths) {
|
|
29617
|
+
try {
|
|
29618
|
+
return parsePatchFiles(block).some((patch) => patch.files.some((file) => allowedPaths.has(file.name) || file.prevName !== void 0 && allowedPaths.has(file.prevName)));
|
|
29619
|
+
} catch {
|
|
29620
|
+
return true;
|
|
29621
|
+
}
|
|
29622
|
+
}
|
|
29623
|
+
/**
|
|
29624
|
+
* Cut a unified diff down to the files a thread's own activities name.
|
|
29625
|
+
*
|
|
29626
|
+
* `changedPaths` is the raw activity path list; normalization against
|
|
29627
|
+
* `workspaceCwd` happens here. The caller decides what an empty path list
|
|
29628
|
+
* means - this function treats it literally and returns an empty diff.
|
|
29629
|
+
*/
|
|
29630
|
+
function filterUnifiedDiffToChangedFiles(diff, changedPaths, workspaceCwd) {
|
|
29631
|
+
if (diff.length === 0) return diff;
|
|
29632
|
+
const allowedPaths = normalizeChangedFilePaths(changedPaths, workspaceCwd);
|
|
29633
|
+
return splitUnifiedDiffBlocks(diff).filter((block) => blockNamesPath(block, allowedPaths)).join("");
|
|
29634
|
+
}
|
|
29635
|
+
//#endregion
|
|
29636
|
+
//#region src/checkpointing/Errors.ts
|
|
29637
|
+
const CheckpointDiffOperation = Schema$1.Literals(["CheckpointDiffQuery.getTurnDiff", "CheckpointDiffQuery.getFullThreadDiff"]);
|
|
29638
|
+
/** The computed result does not satisfy the checkpoint RPC contract. */
|
|
29639
|
+
var CheckpointDiffResultInvalidError = class extends Schema$1.TaggedErrorClass()("CheckpointDiffResultInvalidError", {
|
|
29640
|
+
operation: CheckpointDiffOperation,
|
|
29641
|
+
threadId: ThreadId
|
|
29642
|
+
}) {
|
|
29643
|
+
get message() {
|
|
29644
|
+
const result = this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
|
|
29645
|
+
return `Checkpoint invariant violation in ${this.operation}: Computed ${result} result does not satisfy contract schema.`;
|
|
29646
|
+
}
|
|
29647
|
+
};
|
|
29648
|
+
/** Projection state no longer contains the requested checkpoint thread. */
|
|
29649
|
+
var CheckpointThreadNotFoundError = class extends Schema$1.TaggedErrorClass()("CheckpointThreadNotFoundError", {
|
|
29650
|
+
operation: CheckpointDiffOperation,
|
|
29651
|
+
threadId: ThreadId
|
|
29652
|
+
}) {
|
|
29653
|
+
get message() {
|
|
29654
|
+
return `Checkpoint invariant violation in ${this.operation}: Thread '${this.threadId}' not found.`;
|
|
29655
|
+
}
|
|
29656
|
+
};
|
|
29657
|
+
/** The checkpoint thread has no workspace path from which to compute a diff. */
|
|
29658
|
+
var CheckpointWorkspacePathMissingError = class extends Schema$1.TaggedErrorClass()("CheckpointWorkspacePathMissingError", {
|
|
29659
|
+
operation: CheckpointDiffOperation,
|
|
29660
|
+
threadId: ThreadId
|
|
29661
|
+
}) {
|
|
29662
|
+
get message() {
|
|
29663
|
+
const diff = this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
|
|
29664
|
+
return `Checkpoint invariant violation in ${this.operation}: Workspace path missing for thread '${this.threadId}' when computing ${diff}.`;
|
|
29665
|
+
}
|
|
29666
|
+
};
|
|
29667
|
+
/** The requested turn lies beyond the latest available checkpoint. */
|
|
29668
|
+
var CheckpointTurnRangeUnavailableError = class extends Schema$1.TaggedErrorClass()("CheckpointTurnRangeUnavailableError", {
|
|
29669
|
+
operation: CheckpointDiffOperation,
|
|
29670
|
+
threadId: ThreadId,
|
|
29671
|
+
requestedTurnCount: NonNegativeInt,
|
|
29672
|
+
availableTurnCount: NonNegativeInt
|
|
29673
|
+
}) {
|
|
29674
|
+
get message() {
|
|
29675
|
+
return `Checkpoint unavailable for thread ${this.threadId} turn ${this.requestedTurnCount}: Turn diff range exceeds current turn count: requested ${this.requestedTurnCount}, current ${this.availableTurnCount}.`;
|
|
29676
|
+
}
|
|
29677
|
+
};
|
|
29678
|
+
/** Expected checkpoint metadata does not contain the requested Git ref. */
|
|
29679
|
+
var CheckpointRefUnavailableError = class extends Schema$1.TaggedErrorClass()("CheckpointRefUnavailableError", {
|
|
29680
|
+
operation: CheckpointDiffOperation,
|
|
29681
|
+
threadId: ThreadId,
|
|
29682
|
+
turnCount: NonNegativeInt,
|
|
29683
|
+
checkpoint: Schema$1.Literals(["from", "to"])
|
|
29684
|
+
}) {
|
|
29685
|
+
get message() {
|
|
29686
|
+
return `Checkpoint unavailable for thread ${this.threadId} turn ${this.turnCount}: Checkpoint ref is unavailable for turn ${this.turnCount}.`;
|
|
29687
|
+
}
|
|
29688
|
+
};
|
|
29689
|
+
//#endregion
|
|
29690
|
+
//#region src/checkpointing/Utils.ts
|
|
29691
|
+
const CHECKPOINT_REFS_PREFIX = "refs/p4/checkpoints";
|
|
29692
|
+
function checkpointRefForThreadTurn(threadId, turnCount) {
|
|
29693
|
+
return CheckpointRef.make(`${CHECKPOINT_REFS_PREFIX}/${Encoding.encodeBase64Url(threadId)}/turn/${turnCount}`);
|
|
29694
|
+
}
|
|
29695
|
+
function resolveThreadWorkspaceCwd(input) {
|
|
29696
|
+
const worktreeCwd = input.thread.worktreePath ?? void 0;
|
|
29697
|
+
if (worktreeCwd) return worktreeCwd;
|
|
29698
|
+
return input.projects.find((project) => project.id === input.thread.projectId)?.workspaceRoot;
|
|
29699
|
+
}
|
|
29700
|
+
//#endregion
|
|
29701
|
+
//#region src/git/remoteRefs.ts
|
|
29702
|
+
function parseRemoteNamesInGitOrder(stdout) {
|
|
29703
|
+
const remoteNames = [];
|
|
29704
|
+
for (const line of stdout.split("\n")) {
|
|
29705
|
+
const remoteName = line.trim();
|
|
29706
|
+
if (remoteName.length > 0) remoteNames.push(remoteName);
|
|
29707
|
+
}
|
|
29708
|
+
return remoteNames;
|
|
29709
|
+
}
|
|
29710
|
+
function parseRemoteNames(stdout) {
|
|
29711
|
+
return parseRemoteNamesInGitOrder(stdout).toSorted((a, b) => b.length - a.length);
|
|
29712
|
+
}
|
|
29713
|
+
function parseRemoteRefWithRemoteNames(ref, remoteNames) {
|
|
29714
|
+
const trimmedRef = ref.trim();
|
|
29715
|
+
if (trimmedRef.length === 0) return null;
|
|
29716
|
+
for (const remoteName of remoteNames) {
|
|
29717
|
+
const remotePrefix = `${remoteName}/`;
|
|
29718
|
+
if (!trimmedRef.startsWith(remotePrefix)) continue;
|
|
29719
|
+
const branchName = trimmedRef.slice(remotePrefix.length).trim();
|
|
29720
|
+
if (branchName.length === 0) return null;
|
|
29721
|
+
return {
|
|
29722
|
+
remoteRef: trimmedRef,
|
|
29723
|
+
remoteName,
|
|
29724
|
+
branchName
|
|
29725
|
+
};
|
|
29726
|
+
}
|
|
29727
|
+
return null;
|
|
29728
|
+
}
|
|
29729
|
+
function extractBranchNameFromRemoteRef(ref, options) {
|
|
29730
|
+
const normalized = ref.trim();
|
|
29731
|
+
if (normalized.length === 0) return "";
|
|
29732
|
+
if (normalized.startsWith("refs/remotes/")) return extractBranchNameFromRemoteRef(normalized.slice(13), options);
|
|
29733
|
+
const parsedRemoteRef = parseRemoteRefWithRemoteNames(normalized, options?.remoteName ? [options.remoteName] : options?.remoteNames ?? []);
|
|
29734
|
+
if (parsedRemoteRef) return parsedRemoteRef.branchName;
|
|
29735
|
+
const firstSlash = normalized.indexOf("/");
|
|
29736
|
+
if (firstSlash === -1) return normalized;
|
|
29737
|
+
return normalized.slice(firstSlash + 1).trim();
|
|
29738
|
+
}
|
|
29739
|
+
//#endregion
|
|
29740
|
+
//#region src/vcs/GitVcsDriverCore.ts
|
|
29741
|
+
const DEFAULT_TIMEOUT_MS$5 = 3e4;
|
|
29742
|
+
const DEFAULT_MAX_OUTPUT_BYTES$1 = 1e6;
|
|
29743
|
+
const OUTPUT_TRUNCATED_MARKER$1 = "\n\n[truncated]";
|
|
29744
|
+
const PREPARED_COMMIT_PATCH_MAX_OUTPUT_BYTES = 49e3;
|
|
29745
|
+
const RANGE_COMMIT_SUMMARY_MAX_OUTPUT_BYTES = 19e3;
|
|
29746
|
+
const RANGE_DIFF_SUMMARY_MAX_OUTPUT_BYTES = 19e3;
|
|
29747
|
+
const RANGE_DIFF_PATCH_MAX_OUTPUT_BYTES = 59e3;
|
|
29748
|
+
const REVIEW_DIFF_PATCH_MAX_OUTPUT_BYTES = 12e4;
|
|
29749
|
+
const REVIEW_UNTRACKED_DIFF_MAX_OUTPUT_BYTES = 8e4;
|
|
29750
|
+
const WORKSPACE_FILES_MAX_OUTPUT_BYTES$1 = 12e4;
|
|
29751
|
+
const STATUS_UPSTREAM_REFRESH_INTERVAL = Duration.seconds(15);
|
|
29752
|
+
const STATUS_UPSTREAM_REFRESH_TIMEOUT = Duration.seconds(5);
|
|
29753
|
+
const STATUS_UPSTREAM_REFRESH_FAILURE_BASE_COOLDOWN = Duration.seconds(30);
|
|
29754
|
+
const STATUS_UPSTREAM_REFRESH_FAILURE_MAX_COOLDOWN = Duration.minutes(15);
|
|
29755
|
+
const STATUS_UPSTREAM_REFRESH_CACHE_CAPACITY = 2048;
|
|
29756
|
+
const REPOSITORY_PATHS_CACHE_CAPACITY = 2048;
|
|
29757
|
+
const REPOSITORY_PATHS_CACHE_TTL = Duration.minutes(10);
|
|
29758
|
+
const REPOSITORY_PATHS_REFRESH_COALESCE_TTL = Duration.seconds(5);
|
|
29759
|
+
const NON_REPOSITORY_PATHS_CACHE_TTL = Duration.seconds(1);
|
|
29760
|
+
const LIST_REFS_SNAPSHOT_CACHE_CAPACITY = 64;
|
|
29761
|
+
const LIST_REFS_SNAPSHOT_CACHE_TTL = Duration.minutes(2);
|
|
29762
|
+
const LIST_REFS_REFRESH_COALESCE_TTL = Duration.seconds(5);
|
|
29763
|
+
const LIST_REFS_REFRESH_FAILURE_COOLDOWN = Duration.seconds(30);
|
|
29764
|
+
const STATUS_UPSTREAM_REFRESH_ENV = Object.freeze({
|
|
29765
|
+
GCM_INTERACTIVE: "never",
|
|
29766
|
+
GIT_ASKPASS: "",
|
|
29767
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
29768
|
+
SSH_ASKPASS: "",
|
|
29769
|
+
SSH_ASKPASS_REQUIRE: "never"
|
|
29770
|
+
});
|
|
29771
|
+
const DEFAULT_BASE_BRANCH_CANDIDATES = ["main", "master"];
|
|
29772
|
+
const GIT_LIST_BRANCHES_DEFAULT_LIMIT = 100;
|
|
29773
|
+
const NON_REPOSITORY_STATUS_DETAILS = Object.freeze({
|
|
29774
|
+
isRepo: false,
|
|
29775
|
+
hasOriginRemote: false,
|
|
29776
|
+
isDefaultBranch: false,
|
|
29777
|
+
branch: null,
|
|
29778
|
+
upstreamRef: null,
|
|
29779
|
+
hasWorkingTreeChanges: false,
|
|
29780
|
+
workingTree: {
|
|
29781
|
+
files: [],
|
|
29782
|
+
insertions: 0,
|
|
29783
|
+
deletions: 0
|
|
29784
|
+
},
|
|
29785
|
+
hasUpstream: false,
|
|
29786
|
+
aheadCount: 0,
|
|
29787
|
+
behindCount: 0,
|
|
29788
|
+
aheadOfDefaultCount: 0
|
|
29789
|
+
});
|
|
29790
|
+
const NON_REPOSITORY_REMOTE_STATUS_DETAILS = Object.freeze({
|
|
29791
|
+
isRepo: false,
|
|
29792
|
+
isDefaultBranch: false,
|
|
29793
|
+
branch: null,
|
|
29794
|
+
upstreamRef: null,
|
|
29795
|
+
hasUpstream: false,
|
|
29796
|
+
aheadCount: 0,
|
|
29797
|
+
behindCount: 0,
|
|
29798
|
+
aheadOfDefaultCount: 0
|
|
29799
|
+
});
|
|
29800
|
+
var StatusRemoteRefreshCacheKey = class extends Data.Class {};
|
|
29801
|
+
function statusUpstreamRefreshFailureCooldown(consecutiveFailures) {
|
|
29802
|
+
const exponent = Math.max(0, consecutiveFailures - 1);
|
|
29803
|
+
const cooldownMs = Duration.toMillis(STATUS_UPSTREAM_REFRESH_FAILURE_BASE_COOLDOWN) * Math.pow(2, exponent);
|
|
29804
|
+
return Duration.min(Duration.millis(cooldownMs), STATUS_UPSTREAM_REFRESH_FAILURE_MAX_COOLDOWN);
|
|
29805
|
+
}
|
|
29806
|
+
var GitRefsSnapshotCacheKey = class extends Data.Class {};
|
|
29807
|
+
var GitRefsRefreshCacheKey = class extends Data.Class {};
|
|
29808
|
+
function parseBranchAb(value) {
|
|
29809
|
+
const match = value.match(/^\+(\d+)\s+-(\d+)$/);
|
|
29810
|
+
if (!match) return {
|
|
29811
|
+
ahead: 0,
|
|
29812
|
+
behind: 0
|
|
29813
|
+
};
|
|
29814
|
+
return {
|
|
29815
|
+
ahead: Number(match[1] ?? "0"),
|
|
29816
|
+
behind: Number(match[2] ?? "0")
|
|
29817
|
+
};
|
|
29818
|
+
}
|
|
29819
|
+
function parseNumstatEntries(stdout) {
|
|
29820
|
+
const entries = [];
|
|
29821
|
+
for (const line of stdout.split(/\r?\n/g)) {
|
|
29822
|
+
if (line.trim().length === 0) continue;
|
|
29823
|
+
const [addedRaw, deletedRaw, ...pathParts] = line.split(" ");
|
|
29824
|
+
const rawPath = pathParts.length > 1 ? (pathParts.at(-1) ?? "").trim() : pathParts.join(" ").trim();
|
|
29825
|
+
if (rawPath.length === 0) continue;
|
|
29826
|
+
const added = Number.parseInt(addedRaw ?? "0", 10);
|
|
29827
|
+
const deleted = Number.parseInt(deletedRaw ?? "0", 10);
|
|
29828
|
+
const renameArrowIndex = rawPath.indexOf(" => ");
|
|
29829
|
+
const normalizedPath = renameArrowIndex >= 0 ? rawPath.slice(renameArrowIndex + 4).trim() : rawPath;
|
|
29830
|
+
entries.push({
|
|
29831
|
+
path: normalizedPath.length > 0 ? normalizedPath : rawPath,
|
|
29832
|
+
insertions: Number.isFinite(added) ? added : 0,
|
|
29833
|
+
deletions: Number.isFinite(deleted) ? deleted : 0
|
|
29834
|
+
});
|
|
29835
|
+
}
|
|
29836
|
+
return entries;
|
|
29837
|
+
}
|
|
29838
|
+
function parsePorcelainPath(line) {
|
|
29839
|
+
if (line.startsWith("? ") || line.startsWith("! ")) {
|
|
29840
|
+
const simple = line.slice(2).trim();
|
|
29841
|
+
return simple.length > 0 ? simple : null;
|
|
29842
|
+
}
|
|
29843
|
+
if (!(line.startsWith("1 ") || line.startsWith("2 ") || line.startsWith("u "))) return null;
|
|
29844
|
+
const tabIndex = line.indexOf(" ");
|
|
29845
|
+
if (tabIndex >= 0) {
|
|
29846
|
+
const [filePath] = line.slice(tabIndex + 1).split(" ");
|
|
29847
|
+
return filePath?.trim().length ? filePath.trim() : null;
|
|
29848
|
+
}
|
|
29849
|
+
const filePath = line.trim().split(/\s+/g).at(-1) ?? "";
|
|
29850
|
+
return filePath.length > 0 ? filePath : null;
|
|
29851
|
+
}
|
|
29852
|
+
function filterBranchesForListQuery(refs, query) {
|
|
29853
|
+
if (!query) return refs;
|
|
29854
|
+
const normalizedQuery = query.toLowerCase();
|
|
29855
|
+
return refs.filter((refName) => refName.name.toLowerCase().includes(normalizedQuery));
|
|
29214
29856
|
}
|
|
29215
29857
|
function paginateBranches(input) {
|
|
29216
29858
|
const cursor = input.cursor ?? 0;
|
|
@@ -31596,6 +32238,32 @@ function buildTurnDiffResult(input, diff) {
|
|
|
31596
32238
|
const make$39 = Effect.gen(function* () {
|
|
31597
32239
|
const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
|
|
31598
32240
|
const checkpointStore = yield* CheckpointStore;
|
|
32241
|
+
const threadActivities = yield* ProjectionThreadActivityRepository;
|
|
32242
|
+
/**
|
|
32243
|
+
* The file paths this thread's own tool activities name, optionally limited
|
|
32244
|
+
* to a set of turns. This is the attribution a checkpoint cannot provide: a
|
|
32245
|
+
* checkpoint snapshots the whole tree, so on a shared worktree its diff also
|
|
32246
|
+
* contains other threads' edits, while activities are per-thread by
|
|
32247
|
+
* construction.
|
|
32248
|
+
*/
|
|
32249
|
+
const collectThreadChangedFilePaths = Effect.fn("CheckpointDiffQuery.collectThreadChangedFilePaths")(function* (threadId, turnIds) {
|
|
32250
|
+
const activities = yield* threadActivities.listByThreadId({ threadId });
|
|
32251
|
+
const changedPaths = /* @__PURE__ */ new Set();
|
|
32252
|
+
for (const activity of activities) {
|
|
32253
|
+
if (activity.tone !== "tool") continue;
|
|
32254
|
+
if (turnIds !== null && (activity.turnId === null || !turnIds.has(activity.turnId))) continue;
|
|
32255
|
+
for (const changedPath of collectActivityChangedFilePaths(activity.payload)) changedPaths.add(changedPath);
|
|
32256
|
+
}
|
|
32257
|
+
return changedPaths;
|
|
32258
|
+
});
|
|
32259
|
+
/**
|
|
32260
|
+
* A thread whose activities name no paths at all gets the unfiltered diff.
|
|
32261
|
+
* That is the deliberate escape valve: a thread working purely through shell
|
|
32262
|
+
* commands never names the files it touched, and erasing its whole diff
|
|
32263
|
+
* would be worse than the shared-worktree contamination this filter exists
|
|
32264
|
+
* to remove.
|
|
32265
|
+
*/
|
|
32266
|
+
const attributeDiffToThread = (diff, changedPaths, workspaceCwd) => changedPaths.size === 0 ? diff : filterUnifiedDiffToChangedFiles(diff, changedPaths, workspaceCwd);
|
|
31599
32267
|
const getTurnDiff = Effect.fn("getTurnDiff")(function* (input) {
|
|
31600
32268
|
const operation = "CheckpointDiffQuery.getTurnDiff";
|
|
31601
32269
|
const ignoreWhitespace = input.ignoreWhitespace ?? true;
|
|
@@ -31649,13 +32317,16 @@ const make$39 = Effect.gen(function* () {
|
|
|
31649
32317
|
turnCount: input.toTurnCount,
|
|
31650
32318
|
checkpoint: "to"
|
|
31651
32319
|
});
|
|
31652
|
-
const
|
|
32320
|
+
const diff = yield* checkpointStore.diffCheckpoints({
|
|
31653
32321
|
cwd: workspaceCwd,
|
|
31654
32322
|
fromCheckpointRef,
|
|
31655
32323
|
toCheckpointRef,
|
|
31656
32324
|
fallbackFromToHead: false,
|
|
31657
32325
|
ignoreWhitespace
|
|
31658
|
-
}).pipe(Effect.withSpan("checkpoint.turnDiff.diffCheckpoints"))
|
|
32326
|
+
}).pipe(Effect.withSpan("checkpoint.turnDiff.diffCheckpoints"));
|
|
32327
|
+
const turnIdsInRange = new Set(threadContext.value.checkpoints.filter((checkpoint) => checkpoint.checkpointTurnCount > input.fromTurnCount && checkpoint.checkpointTurnCount <= input.toTurnCount).map((checkpoint) => checkpoint.turnId));
|
|
32328
|
+
const changedPaths = yield* collectThreadChangedFilePaths(input.threadId, turnIdsInRange);
|
|
32329
|
+
const turnDiff = buildTurnDiffResult(input, attributeDiffToThread(diff, changedPaths, workspaceCwd));
|
|
31659
32330
|
if (!isTurnDiffResult(turnDiff)) return yield* new CheckpointDiffResultInvalidError({
|
|
31660
32331
|
operation,
|
|
31661
32332
|
threadId: input.threadId
|
|
@@ -31713,11 +32384,12 @@ const make$39 = Effect.gen(function* () {
|
|
|
31713
32384
|
fallbackFromToHead: false,
|
|
31714
32385
|
ignoreWhitespace
|
|
31715
32386
|
}).pipe(Effect.withSpan("checkpoint.fullThread.diffCheckpoints"));
|
|
32387
|
+
const changedPaths = yield* collectThreadChangedFilePaths(input.threadId, null);
|
|
31716
32388
|
const turnDiff = buildTurnDiffResult({
|
|
31717
32389
|
threadId: input.threadId,
|
|
31718
32390
|
fromTurnCount: 0,
|
|
31719
32391
|
toTurnCount: input.toTurnCount
|
|
31720
|
-
}, diff);
|
|
32392
|
+
}, attributeDiffToThread(diff, changedPaths, workspaceCwd));
|
|
31721
32393
|
if (!isTurnDiffResult(turnDiff)) return yield* new CheckpointDiffResultInvalidError({
|
|
31722
32394
|
operation,
|
|
31723
32395
|
threadId: input.threadId
|
|
@@ -32297,7 +32969,7 @@ const normalizeDispatchCommand = (command) => Effect.gen(function* () {
|
|
|
32297
32969
|
const buildTaskRow = (input, taskId, timestamp, repositoryKey = null) => ({
|
|
32298
32970
|
taskId,
|
|
32299
32971
|
projectId: input.projectId ?? null,
|
|
32300
|
-
repositoryKey,
|
|
32972
|
+
repositoryKey: repositoryKey ?? input.repositoryKey ?? null,
|
|
32301
32973
|
threadId: input.threadId ?? null,
|
|
32302
32974
|
title: input.title,
|
|
32303
32975
|
body: input.body ?? "",
|
|
@@ -83142,796 +83814,264 @@ const make$2 = Effect.gen(function* () {
|
|
|
83142
83814
|
if (targetBranch === oldBranch) return;
|
|
83143
83815
|
const renamed = yield* gitWorkflow.renameBranch({
|
|
83144
83816
|
cwd,
|
|
83145
|
-
oldBranch,
|
|
83146
|
-
newBranch: targetBranch
|
|
83147
|
-
});
|
|
83148
|
-
yield* orchestrationEngine.dispatch({
|
|
83149
|
-
type: "thread.meta.update",
|
|
83150
|
-
commandId: yield* serverCommandId("worktree-branch-rename"),
|
|
83151
|
-
threadId: input.threadId,
|
|
83152
|
-
branch: renamed.branch,
|
|
83153
|
-
worktreePath: cwd
|
|
83154
|
-
});
|
|
83155
|
-
yield* vcsStatusBroadcaster.refreshStatus(cwd).pipe(Effect.ignoreCause({ log: true }));
|
|
83156
|
-
}).pipe(Effect.catchCause((cause) => Effect.logWarning("provider command reactor failed to generate or rename worktree branch", {
|
|
83157
|
-
threadId: input.threadId,
|
|
83158
|
-
cwd,
|
|
83159
|
-
oldBranch,
|
|
83160
|
-
cause: Cause.pretty(cause)
|
|
83161
|
-
})));
|
|
83162
|
-
});
|
|
83163
|
-
const maybeGenerateThreadTitleForFirstTurn = Effect.fn("maybeGenerateThreadTitleForFirstTurn")(function* (input) {
|
|
83164
|
-
const attachments = input.attachments ?? [];
|
|
83165
|
-
yield* Effect.gen(function* () {
|
|
83166
|
-
const { textGenerationModelSelection: modelSelection } = yield* serverSettingsService.getSettings;
|
|
83167
|
-
const generated = yield* textGeneration.generateThreadTitle({
|
|
83168
|
-
cwd: input.cwd,
|
|
83169
|
-
message: input.messageText,
|
|
83170
|
-
...attachments.length > 0 ? { attachments } : {},
|
|
83171
|
-
modelSelection
|
|
83172
|
-
});
|
|
83173
|
-
if (!generated) return;
|
|
83174
|
-
const thread = yield* resolveThread(input.threadId);
|
|
83175
|
-
if (!thread) return;
|
|
83176
|
-
if (!canReplaceThreadTitle(thread.title, input.titleSeed)) return;
|
|
83177
|
-
yield* orchestrationEngine.dispatch({
|
|
83178
|
-
type: "thread.meta.update",
|
|
83179
|
-
commandId: yield* serverCommandId("thread-title-rename"),
|
|
83180
|
-
threadId: input.threadId,
|
|
83181
|
-
title: generated.title
|
|
83182
|
-
});
|
|
83183
|
-
}).pipe(Effect.catchCause((cause) => Effect.logWarning("provider command reactor failed to generate or rename thread title", {
|
|
83184
|
-
threadId: input.threadId,
|
|
83185
|
-
cwd: input.cwd,
|
|
83186
|
-
cause: Cause.pretty(cause)
|
|
83187
|
-
})));
|
|
83188
|
-
});
|
|
83189
|
-
const processTurnStartRequested = Effect.fn("processTurnStartRequested")(function* (event) {
|
|
83190
|
-
const key = turnStartKeyForEvent(event);
|
|
83191
|
-
if (yield* hasHandledTurnStartRecently(key)) return;
|
|
83192
|
-
const thread = yield* resolveThread(event.payload.threadId);
|
|
83193
|
-
if (!thread) return;
|
|
83194
|
-
const message = thread.messages.find((entry) => entry.id === event.payload.messageId);
|
|
83195
|
-
if (!message || message.role !== "user") {
|
|
83196
|
-
yield* appendProviderFailureActivity({
|
|
83197
|
-
threadId: event.payload.threadId,
|
|
83198
|
-
kind: "provider.turn.start.failed",
|
|
83199
|
-
summary: "Provider turn start failed",
|
|
83200
|
-
detail: `User message '${event.payload.messageId}' was not found for turn start request.`,
|
|
83201
|
-
turnId: null,
|
|
83202
|
-
createdAt: event.payload.createdAt
|
|
83203
|
-
});
|
|
83204
|
-
return;
|
|
83205
|
-
}
|
|
83206
|
-
if (thread.messages.filter((entry) => entry.role === "user").length === 1) {
|
|
83207
|
-
const project = yield* resolveProject(thread.projectId);
|
|
83208
|
-
const generationCwd = resolveThreadWorkspaceCwd({
|
|
83209
|
-
thread,
|
|
83210
|
-
projects: project ? [project] : []
|
|
83211
|
-
}) ?? process.cwd();
|
|
83212
|
-
const generationInput = {
|
|
83213
|
-
messageText: message.text,
|
|
83214
|
-
...message.attachments !== void 0 ? { attachments: message.attachments } : {},
|
|
83215
|
-
...event.payload.titleSeed !== void 0 ? { titleSeed: event.payload.titleSeed } : {}
|
|
83216
|
-
};
|
|
83217
|
-
yield* maybeGenerateAndRenameWorktreeBranchForFirstTurn({
|
|
83218
|
-
threadId: event.payload.threadId,
|
|
83219
|
-
branch: thread.branch,
|
|
83220
|
-
worktreePath: thread.worktreePath,
|
|
83221
|
-
...generationInput
|
|
83222
|
-
}).pipe(Effect.forkScoped);
|
|
83223
|
-
if (canReplaceThreadTitle(thread.title, event.payload.titleSeed)) yield* maybeGenerateThreadTitleForFirstTurn({
|
|
83224
|
-
threadId: event.payload.threadId,
|
|
83225
|
-
cwd: generationCwd,
|
|
83226
|
-
...generationInput
|
|
83227
|
-
}).pipe(Effect.forkScoped);
|
|
83228
|
-
}
|
|
83229
|
-
const handleTurnStartFailure = (cause) => {
|
|
83230
|
-
if (Cause.hasInterruptsOnly(cause)) return Effect.void;
|
|
83231
|
-
const detail = formatFailureDetail(cause);
|
|
83232
|
-
return setThreadSessionErrorOnTurnStartFailure({
|
|
83233
|
-
threadId: event.payload.threadId,
|
|
83234
|
-
detail,
|
|
83235
|
-
createdAt: event.payload.createdAt
|
|
83236
|
-
}).pipe(Effect.flatMap(() => appendProviderFailureActivity({
|
|
83237
|
-
threadId: event.payload.threadId,
|
|
83238
|
-
kind: "provider.turn.start.failed",
|
|
83239
|
-
summary: "Provider turn start failed",
|
|
83240
|
-
detail,
|
|
83241
|
-
turnId: null,
|
|
83242
|
-
createdAt: event.payload.createdAt
|
|
83243
|
-
})), Effect.asVoid);
|
|
83244
|
-
};
|
|
83245
|
-
const recoverTurnStartFailure = (cause) => handleTurnStartFailure(cause).pipe(Effect.catchCause((recoveryCause) => Effect.logWarning("provider command reactor failed to recover turn start failure", {
|
|
83246
|
-
eventType: event.type,
|
|
83247
|
-
threadId: event.payload.threadId,
|
|
83248
|
-
cause: Cause.pretty(recoveryCause),
|
|
83249
|
-
originalCause: Cause.pretty(cause)
|
|
83250
|
-
})));
|
|
83251
|
-
const sendTurnRequest = yield* buildSendTurnRequestForThread({
|
|
83252
|
-
threadId: event.payload.threadId,
|
|
83253
|
-
messageText: message.text,
|
|
83254
|
-
...message.attachments !== void 0 ? { attachments: message.attachments } : {},
|
|
83255
|
-
...event.payload.modelSelection !== void 0 ? { modelSelection: event.payload.modelSelection } : {},
|
|
83256
|
-
interactionMode: event.payload.interactionMode,
|
|
83257
|
-
createdAt: event.payload.createdAt
|
|
83258
|
-
}).pipe(Effect.map(Option.some), Effect.catchCause((cause) => handleTurnStartFailure(cause).pipe(Effect.as(Option.none()))));
|
|
83259
|
-
if (Option.isNone(sendTurnRequest)) return;
|
|
83260
|
-
yield* providerService.sendTurn(sendTurnRequest.value).pipe(Effect.catchCause(recoverTurnStartFailure), Effect.forkScoped);
|
|
83261
|
-
});
|
|
83262
|
-
const processTurnInterruptRequested = Effect.fn("processTurnInterruptRequested")(function* (event) {
|
|
83263
|
-
const thread = yield* resolveThread(event.payload.threadId);
|
|
83264
|
-
if (!thread) return;
|
|
83265
|
-
if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
|
|
83266
|
-
threadId: event.payload.threadId,
|
|
83267
|
-
kind: "provider.turn.interrupt.failed",
|
|
83268
|
-
summary: "Provider turn interrupt failed",
|
|
83269
|
-
detail: "No active provider session is bound to this thread.",
|
|
83270
|
-
turnId: event.payload.turnId ?? null,
|
|
83271
|
-
createdAt: event.payload.createdAt
|
|
83272
|
-
});
|
|
83273
|
-
yield* providerService.interruptTurn({ threadId: event.payload.threadId });
|
|
83274
|
-
yield* appendTurnInterruptedActivity({
|
|
83275
|
-
threadId: event.payload.threadId,
|
|
83276
|
-
turnId: event.payload.turnId ?? null,
|
|
83277
|
-
createdAt: event.payload.createdAt
|
|
83278
|
-
});
|
|
83279
|
-
});
|
|
83280
|
-
const processApprovalResponseRequested = Effect.fn("processApprovalResponseRequested")(function* (event) {
|
|
83281
|
-
const thread = yield* resolveThread(event.payload.threadId);
|
|
83282
|
-
if (!thread) return;
|
|
83283
|
-
if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
|
|
83284
|
-
threadId: event.payload.threadId,
|
|
83285
|
-
kind: "provider.approval.respond.failed",
|
|
83286
|
-
summary: "Provider approval response failed",
|
|
83287
|
-
detail: "No active provider session is bound to this thread.",
|
|
83288
|
-
turnId: null,
|
|
83289
|
-
createdAt: event.payload.createdAt,
|
|
83290
|
-
requestId: event.payload.requestId
|
|
83291
|
-
});
|
|
83292
|
-
yield* providerService.respondToRequest({
|
|
83293
|
-
threadId: event.payload.threadId,
|
|
83294
|
-
requestId: event.payload.requestId,
|
|
83295
|
-
decision: event.payload.decision
|
|
83296
|
-
}).pipe(Effect.catchCause((cause) => appendProviderFailureActivity({
|
|
83297
|
-
threadId: event.payload.threadId,
|
|
83298
|
-
kind: "provider.approval.respond.failed",
|
|
83299
|
-
summary: "Provider approval response failed",
|
|
83300
|
-
detail: isUnknownPendingApprovalRequestError(cause) ? stalePendingRequestDetail("approval", event.payload.requestId) : Cause.pretty(cause),
|
|
83301
|
-
turnId: null,
|
|
83302
|
-
createdAt: event.payload.createdAt,
|
|
83303
|
-
requestId: event.payload.requestId
|
|
83304
|
-
})));
|
|
83305
|
-
});
|
|
83306
|
-
const processUserInputResponseRequested = Effect.fn("processUserInputResponseRequested")(function* (event) {
|
|
83307
|
-
const thread = yield* resolveThread(event.payload.threadId);
|
|
83308
|
-
if (!thread) return;
|
|
83309
|
-
if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
|
|
83310
|
-
threadId: event.payload.threadId,
|
|
83311
|
-
kind: "provider.user-input.respond.failed",
|
|
83312
|
-
summary: "Provider user input response failed",
|
|
83313
|
-
detail: "No active provider session is bound to this thread.",
|
|
83314
|
-
turnId: null,
|
|
83315
|
-
createdAt: event.payload.createdAt,
|
|
83316
|
-
requestId: event.payload.requestId
|
|
83317
|
-
});
|
|
83318
|
-
yield* providerService.respondToUserInput({
|
|
83319
|
-
threadId: event.payload.threadId,
|
|
83320
|
-
requestId: event.payload.requestId,
|
|
83321
|
-
answers: event.payload.answers
|
|
83322
|
-
}).pipe(Effect.catchCause((cause) => appendProviderFailureActivity({
|
|
83323
|
-
threadId: event.payload.threadId,
|
|
83324
|
-
kind: "provider.user-input.respond.failed",
|
|
83325
|
-
summary: "Provider user input response failed",
|
|
83326
|
-
detail: isUnknownPendingUserInputRequestError(cause) ? stalePendingRequestDetail("user-input", event.payload.requestId) : Cause.pretty(cause),
|
|
83327
|
-
turnId: null,
|
|
83328
|
-
createdAt: event.payload.createdAt,
|
|
83329
|
-
requestId: event.payload.requestId
|
|
83330
|
-
})));
|
|
83331
|
-
});
|
|
83332
|
-
const processSessionStopRequested = Effect.fn("processSessionStopRequested")(function* (event) {
|
|
83333
|
-
const thread = yield* resolveThread(event.payload.threadId);
|
|
83334
|
-
if (!thread) return;
|
|
83335
|
-
const now = event.payload.createdAt;
|
|
83336
|
-
if (thread.session && thread.session.status !== "stopped") yield* providerService.stopSession({ threadId: thread.id });
|
|
83337
|
-
yield* setThreadSession({
|
|
83338
|
-
threadId: thread.id,
|
|
83339
|
-
session: {
|
|
83340
|
-
threadId: thread.id,
|
|
83341
|
-
status: "stopped",
|
|
83342
|
-
providerName: thread.session?.providerName ?? null,
|
|
83343
|
-
...thread.session?.providerInstanceId !== void 0 ? { providerInstanceId: thread.session.providerInstanceId } : {},
|
|
83344
|
-
runtimeMode: thread.session?.runtimeMode ?? DEFAULT_RUNTIME_MODE,
|
|
83345
|
-
activeTurnId: null,
|
|
83346
|
-
lastError: thread.session?.lastError ?? null,
|
|
83347
|
-
updatedAt: now
|
|
83348
|
-
},
|
|
83349
|
-
createdAt: now
|
|
83350
|
-
});
|
|
83351
|
-
});
|
|
83352
|
-
const processDomainEvent = Effect.fn("processDomainEvent")(function* (event) {
|
|
83353
|
-
yield* Effect.annotateCurrentSpan({
|
|
83354
|
-
"orchestration.event_type": event.type,
|
|
83355
|
-
"orchestration.thread_id": event.payload.threadId,
|
|
83356
|
-
...event.commandId ? { "orchestration.command_id": event.commandId } : {}
|
|
83357
|
-
});
|
|
83358
|
-
yield* increment(orchestrationEventsProcessedTotal, { eventType: event.type });
|
|
83359
|
-
switch (event.type) {
|
|
83360
|
-
case "thread.runtime-mode-set": {
|
|
83361
|
-
const thread = yield* resolveThread(event.payload.threadId);
|
|
83362
|
-
if (!thread?.session || thread.session.status === "stopped") return;
|
|
83363
|
-
const cachedModelSelection = threadModelSelections.get(event.payload.threadId);
|
|
83364
|
-
yield* ensureSessionForThread(event.payload.threadId, event.occurredAt, cachedModelSelection !== void 0 ? { modelSelection: cachedModelSelection } : {});
|
|
83365
|
-
return;
|
|
83366
|
-
}
|
|
83367
|
-
case "thread.turn-start-requested":
|
|
83368
|
-
yield* processTurnStartRequested(event);
|
|
83369
|
-
return;
|
|
83370
|
-
case "thread.turn-interrupt-requested":
|
|
83371
|
-
yield* processTurnInterruptRequested(event);
|
|
83372
|
-
return;
|
|
83373
|
-
case "thread.approval-response-requested":
|
|
83374
|
-
yield* processApprovalResponseRequested(event);
|
|
83375
|
-
return;
|
|
83376
|
-
case "thread.user-input-response-requested":
|
|
83377
|
-
yield* processUserInputResponseRequested(event);
|
|
83378
|
-
return;
|
|
83379
|
-
case "thread.session-stop-requested":
|
|
83380
|
-
yield* processSessionStopRequested(event);
|
|
83381
|
-
return;
|
|
83382
|
-
}
|
|
83383
|
-
});
|
|
83384
|
-
const processDomainEventSafely = (event) => processDomainEvent(event).pipe(Effect.catchCause((cause) => {
|
|
83385
|
-
if (Cause.hasInterruptsOnly(cause)) return Effect.failCause(cause);
|
|
83386
|
-
return Effect.logWarning("provider command reactor failed to process event", {
|
|
83387
|
-
eventType: event.type,
|
|
83388
|
-
cause: Cause.pretty(cause)
|
|
83389
|
-
});
|
|
83390
|
-
}));
|
|
83391
|
-
const worker = yield* makeDrainableWorker(processDomainEventSafely);
|
|
83392
|
-
return {
|
|
83393
|
-
start: Effect.fn("start")(function* () {
|
|
83394
|
-
const processEvent = Effect.fn("processEvent")(function* (event) {
|
|
83395
|
-
if (event.type === "thread.runtime-mode-set" || event.type === "thread.turn-start-requested" || event.type === "thread.turn-interrupt-requested" || event.type === "thread.approval-response-requested" || event.type === "thread.user-input-response-requested" || event.type === "thread.session-stop-requested") return yield* worker.enqueue(event);
|
|
83396
|
-
});
|
|
83397
|
-
yield* Effect.forkScoped(Stream.runForEach(orchestrationEngine.streamDomainEvents, processEvent));
|
|
83398
|
-
}),
|
|
83399
|
-
drain: worker.drain
|
|
83400
|
-
};
|
|
83401
|
-
});
|
|
83402
|
-
const ProviderCommandReactorLive = Layer.effect(ProviderCommandReactor, make$2);
|
|
83403
|
-
(() => {
|
|
83404
|
-
try {
|
|
83405
|
-
return process.env.NODE_ENV === "development";
|
|
83406
|
-
} catch {
|
|
83407
|
-
return false;
|
|
83408
|
-
}
|
|
83409
|
-
})();
|
|
83410
|
-
const COMMIT_METADATA_SPLIT = /(?=^From [a-f0-9]+ .+$)/m;
|
|
83411
|
-
const GIT_DIFF_FILE_BREAK_REGEX = /(?=^diff --git)/gm;
|
|
83412
|
-
const FILENAME_HEADER_REGEX = /^(---|\+\+\+)\s+([^\t\r\n]+)/;
|
|
83413
|
-
const FILENAME_HEADER_REGEX_GIT = /^(---|\+\+\+)\s+[ab]\/([^\t\r\n]+)/;
|
|
83414
|
-
const ALTERNATE_FILE_NAMES_GIT = /^diff --git (?:"a\/(.+?)"|a\/(.+?)) (?:"b\/(.+?)"|b\/(.+?))$/;
|
|
83415
|
-
const INDEX_LINE_METADATA = /^index ([0-9a-f]+)\.\.([0-9a-f]+)(?: (\d+))?$/i;
|
|
83416
|
-
Object.freeze({
|
|
83417
|
-
fromStart: 0,
|
|
83418
|
-
fromEnd: 0
|
|
83419
|
-
});
|
|
83420
|
-
//#endregion
|
|
83421
|
-
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/cleanLastNewline.js
|
|
83422
|
-
function cleanLastNewline(contents) {
|
|
83423
|
-
let end = contents.length;
|
|
83424
|
-
if (contents.charCodeAt(end - 1) === 10) {
|
|
83425
|
-
end--;
|
|
83426
|
-
if (contents.charCodeAt(end - 1) === 13) end--;
|
|
83427
|
-
}
|
|
83428
|
-
return contents.slice(0, end);
|
|
83429
|
-
}
|
|
83430
|
-
//#endregion
|
|
83431
|
-
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/detachString.js
|
|
83432
|
-
const stringDetachEncoder = new TextEncoder();
|
|
83433
|
-
const stringDetachDecoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
83434
|
-
const SURROGATE_CODE_UNIT_PATTERN = /[\uD800-\uDFFF]/;
|
|
83435
|
-
const STRING_DETACH_INITIAL_BUFFER_SIZE = 1024;
|
|
83436
|
-
let stringDetachBuffer = new Uint8Array(STRING_DETACH_INITIAL_BUFFER_SIZE);
|
|
83437
|
-
function releaseStringDetachBuffer() {
|
|
83438
|
-
if (stringDetachBuffer.length !== STRING_DETACH_INITIAL_BUFFER_SIZE) stringDetachBuffer = new Uint8Array(STRING_DETACH_INITIAL_BUFFER_SIZE);
|
|
83439
|
-
}
|
|
83440
|
-
function detachString(value) {
|
|
83441
|
-
if (value.length === 0) return value;
|
|
83442
|
-
if (SURROGATE_CODE_UNIT_PATTERN.test(value)) return JSON.parse(JSON.stringify(value));
|
|
83443
|
-
const requiredByteLength = value.length * 3;
|
|
83444
|
-
if (stringDetachBuffer.length < requiredByteLength) stringDetachBuffer = new Uint8Array(requiredByteLength);
|
|
83445
|
-
const { written } = stringDetachEncoder.encodeInto(value, stringDetachBuffer);
|
|
83446
|
-
return stringDetachDecoder.decode(stringDetachBuffer.subarray(0, written));
|
|
83447
|
-
}
|
|
83448
|
-
//#endregion
|
|
83449
|
-
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/parsePatchFiles.js
|
|
83450
|
-
function processPatch(data, cacheKeyPrefix, throwOnError) {
|
|
83451
|
-
try {
|
|
83452
|
-
return _processPatch(data, cacheKeyPrefix, throwOnError);
|
|
83453
|
-
} finally {
|
|
83454
|
-
releaseStringDetachBuffer();
|
|
83455
|
-
}
|
|
83456
|
-
}
|
|
83457
|
-
function _processPatch(data, cacheKeyPrefix, throwOnError = false) {
|
|
83458
|
-
const isGitDiff = isGitDiffPatch(data);
|
|
83459
|
-
const rawFiles = isGitDiff ? splitGitDiffFiles(data) : splitUnifiedDiffFiles(data);
|
|
83460
|
-
let patchMetadata;
|
|
83461
|
-
const files = [];
|
|
83462
|
-
for (const fileOrPatchMetadata of rawFiles) {
|
|
83463
|
-
if (isGitDiff && !GIT_DIFF_FILE_BREAK_REGEX.test(fileOrPatchMetadata)) {
|
|
83464
|
-
if (patchMetadata == null) patchMetadata = detachString(fileOrPatchMetadata);
|
|
83465
|
-
else if (throwOnError) throw Error("parsePatchContent: unknown file blob");
|
|
83466
|
-
else console.error("parsePatchContent: unknown file blob:", fileOrPatchMetadata);
|
|
83467
|
-
continue;
|
|
83468
|
-
} else if (!isGitDiff && !startsWithUnifiedDiffFileHeader(fileOrPatchMetadata)) {
|
|
83469
|
-
if (patchMetadata == null) patchMetadata = detachString(fileOrPatchMetadata);
|
|
83470
|
-
else if (throwOnError) throw Error("parsePatchContent: unknown file blob");
|
|
83471
|
-
else console.error("parsePatchContent: unknown file blob:", fileOrPatchMetadata);
|
|
83472
|
-
continue;
|
|
83473
|
-
}
|
|
83474
|
-
const currentFile = _processFile(fileOrPatchMetadata, {
|
|
83475
|
-
cacheKey: cacheKeyPrefix != null ? `${cacheKeyPrefix}-${files.length}` : void 0,
|
|
83476
|
-
isGitDiff,
|
|
83477
|
-
throwOnError
|
|
83478
|
-
});
|
|
83479
|
-
if (currentFile != null) files.push(currentFile);
|
|
83480
|
-
}
|
|
83481
|
-
return {
|
|
83482
|
-
patchMetadata,
|
|
83483
|
-
files
|
|
83484
|
-
};
|
|
83485
|
-
}
|
|
83486
|
-
function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREAK_REGEX.test(fileDiffString), oldFile, newFile, throwOnError = false } = {}) {
|
|
83487
|
-
let lastHunkEnd = 0;
|
|
83488
|
-
const hunks = splitAtLinePrefix(fileDiffString, "@@ ");
|
|
83489
|
-
let currentFile;
|
|
83490
|
-
const isPartial = oldFile == null || newFile == null;
|
|
83491
|
-
let deletionLineIndex = 0;
|
|
83492
|
-
let additionLineIndex = 0;
|
|
83493
|
-
for (const hunk of hunks) {
|
|
83494
|
-
const lines = splitWithNewlines(hunk);
|
|
83495
|
-
const firstLine = lines[0];
|
|
83496
|
-
if (firstLine == null) {
|
|
83497
|
-
if (throwOnError) throw Error("parsePatchContent: invalid hunk");
|
|
83498
|
-
else console.error("parsePatchContent: invalid hunk", hunk);
|
|
83499
|
-
continue;
|
|
83500
|
-
}
|
|
83501
|
-
const fileHeader = parseHunkHeader(firstLine);
|
|
83502
|
-
let additionLines = 0;
|
|
83503
|
-
let deletionLines = 0;
|
|
83504
|
-
if (fileHeader == null || currentFile == null) {
|
|
83505
|
-
if (currentFile != null) {
|
|
83506
|
-
if (throwOnError) throw Error("parsePatchContent: Invalid hunk");
|
|
83507
|
-
else console.error("parsePatchContent: Invalid hunk", hunk);
|
|
83508
|
-
continue;
|
|
83509
|
-
}
|
|
83510
|
-
currentFile = {
|
|
83511
|
-
name: "",
|
|
83512
|
-
type: "change",
|
|
83513
|
-
hunks: [],
|
|
83514
|
-
splitLineCount: 0,
|
|
83515
|
-
unifiedLineCount: 0,
|
|
83516
|
-
isPartial,
|
|
83517
|
-
additionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(newFile.contents) : [],
|
|
83518
|
-
deletionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(oldFile.contents) : [],
|
|
83519
|
-
cacheKey: maybeDetachOptionalString(cacheKey)
|
|
83520
|
-
};
|
|
83521
|
-
if (currentFile.additionLines.length === 1 && newFile?.contents === "") currentFile.additionLines.length = 0;
|
|
83522
|
-
if (currentFile.deletionLines.length === 1 && oldFile?.contents === "") currentFile.deletionLines.length = 0;
|
|
83523
|
-
for (const line of lines) {
|
|
83524
|
-
if (line.startsWith("diff --git")) {
|
|
83525
|
-
const filenameMatch$1 = line.trim().match(ALTERNATE_FILE_NAMES_GIT);
|
|
83526
|
-
const prevName = filenameMatch$1?.[1] ?? filenameMatch$1?.[2];
|
|
83527
|
-
const name = filenameMatch$1?.[3] ?? filenameMatch$1?.[4];
|
|
83528
|
-
if (prevName == null || name == null) {
|
|
83529
|
-
if (throwOnError) throw Error("parsePatchContent: invalid git diff header");
|
|
83530
|
-
else console.error("parsePatchContent: invalid git diff header", line);
|
|
83531
|
-
continue;
|
|
83532
|
-
}
|
|
83533
|
-
currentFile.name = detachString(name.trim());
|
|
83534
|
-
if (prevName !== name) currentFile.prevName = detachString(prevName.trim());
|
|
83535
|
-
continue;
|
|
83536
|
-
}
|
|
83537
|
-
const filenameMatch = line.startsWith("---") || line.startsWith("+++") ? line.match(isGitDiff ? FILENAME_HEADER_REGEX_GIT : FILENAME_HEADER_REGEX) : null;
|
|
83538
|
-
if (filenameMatch != null) {
|
|
83539
|
-
const [, type, fileName] = filenameMatch;
|
|
83540
|
-
if (type === "---" && fileName !== "/dev/null") {
|
|
83541
|
-
const detachedFileName = detachString(fileName.trim());
|
|
83542
|
-
currentFile.prevName = detachedFileName;
|
|
83543
|
-
currentFile.name = detachedFileName;
|
|
83544
|
-
} else if (type === "+++" && fileName !== "/dev/null") currentFile.name = detachString(fileName.trim());
|
|
83545
|
-
} else if (isGitDiff) {
|
|
83546
|
-
if (line.startsWith("new mode ")) currentFile.mode = detachString(line.slice(8).trim());
|
|
83547
|
-
if (line.startsWith("old mode ")) currentFile.prevMode = detachString(line.slice(8).trim());
|
|
83548
|
-
if (line.startsWith("new file mode")) {
|
|
83549
|
-
currentFile.type = "new";
|
|
83550
|
-
currentFile.mode = detachString(line.slice(13).trim());
|
|
83551
|
-
}
|
|
83552
|
-
if (line.startsWith("deleted file mode")) {
|
|
83553
|
-
currentFile.type = "deleted";
|
|
83554
|
-
currentFile.mode = detachString(line.slice(17).trim());
|
|
83555
|
-
}
|
|
83556
|
-
if (line.startsWith("similarity index")) if (line.startsWith("similarity index 100%")) currentFile.type = "rename-pure";
|
|
83557
|
-
else currentFile.type = "rename-changed";
|
|
83558
|
-
if (line.startsWith("index ")) {
|
|
83559
|
-
const [, prevObjectId, newObjectId, mode] = line.trim().match(INDEX_LINE_METADATA) ?? [];
|
|
83560
|
-
if (prevObjectId != null) currentFile.prevObjectId = detachString(prevObjectId);
|
|
83561
|
-
if (newObjectId != null) currentFile.newObjectId = detachString(newObjectId);
|
|
83562
|
-
if (mode != null) currentFile.mode = detachString(mode);
|
|
83563
|
-
}
|
|
83564
|
-
if (line.startsWith("rename from ")) currentFile.prevName = detachString(line.slice(12).trim());
|
|
83565
|
-
if (line.startsWith("rename to ")) currentFile.name = detachString(line.slice(10).trim());
|
|
83566
|
-
}
|
|
83567
|
-
}
|
|
83568
|
-
continue;
|
|
83569
|
-
}
|
|
83570
|
-
let currentContent;
|
|
83571
|
-
let lastLineType;
|
|
83572
|
-
while (lines.length > 0 && (lines[lines.length - 1] === "\n" || lines[lines.length - 1] === "\r" || lines[lines.length - 1] === "\r\n" || lines[lines.length - 1] === "")) lines.pop();
|
|
83573
|
-
const { additionStart, deletionStart } = fileHeader;
|
|
83574
|
-
deletionLineIndex = isPartial ? deletionLineIndex : deletionStart - 1;
|
|
83575
|
-
additionLineIndex = isPartial ? additionLineIndex : additionStart - 1;
|
|
83576
|
-
const hunkData = {
|
|
83577
|
-
collapsedBefore: 0,
|
|
83578
|
-
splitLineCount: 0,
|
|
83579
|
-
splitLineStart: 0,
|
|
83580
|
-
unifiedLineCount: 0,
|
|
83581
|
-
unifiedLineStart: 0,
|
|
83582
|
-
additionCount: fileHeader.additionCount,
|
|
83583
|
-
additionStart,
|
|
83584
|
-
additionLines,
|
|
83585
|
-
deletionCount: fileHeader.deletionCount,
|
|
83586
|
-
deletionStart,
|
|
83587
|
-
deletionLines,
|
|
83588
|
-
deletionLineIndex,
|
|
83589
|
-
additionLineIndex,
|
|
83590
|
-
hunkContent: [],
|
|
83591
|
-
hunkContext: maybeDetachOptionalString(fileHeader.hunkContext),
|
|
83592
|
-
hunkSpecs: detachString(firstLine),
|
|
83593
|
-
noEOFCRAdditions: false,
|
|
83594
|
-
noEOFCRDeletions: false
|
|
83595
|
-
};
|
|
83596
|
-
let parsedAdditionLines = 0;
|
|
83597
|
-
let parsedDeletionLines = 0;
|
|
83598
|
-
for (let lineIndex = 1; lineIndex < lines.length; lineIndex++) {
|
|
83599
|
-
const rawLine = lines[lineIndex];
|
|
83600
|
-
if (parsedAdditionLines >= hunkData.additionCount && parsedDeletionLines >= hunkData.deletionCount && !rawLine.startsWith("\\")) {
|
|
83601
|
-
if (throwOnError && isHunkBodyLine(rawLine) && !isFormatPatchVersionSeparator(rawLine)) throw Error("parsePatchContent: hunk has more lines than expected");
|
|
83602
|
-
break;
|
|
83603
|
-
}
|
|
83604
|
-
const firstChar = rawLine[0];
|
|
83605
|
-
if (firstChar !== "+" && firstChar !== "-" && firstChar !== " " && firstChar !== "\\") {
|
|
83606
|
-
if (throwOnError) throw Error("parsePatchContent: invalid hunk line");
|
|
83607
|
-
console.error(`parseLineType: Invalid firstChar: "${firstChar}", full line: "${rawLine}"`);
|
|
83608
|
-
console.error("processFile: invalid rawLine:", rawLine);
|
|
83609
|
-
continue;
|
|
83610
|
-
}
|
|
83611
|
-
const type = parseRawLineType(firstChar);
|
|
83612
|
-
if (type === "addition") {
|
|
83613
|
-
if (throwOnError && parsedAdditionLines >= hunkData.additionCount) throw Error("parsePatchContent: hunk has too many addition lines");
|
|
83614
|
-
const line = getParsedLineContent(rawLine);
|
|
83615
|
-
if (currentContent == null || currentContent.type !== "change") {
|
|
83616
|
-
currentContent = createContentGroup("change", deletionLineIndex, additionLineIndex);
|
|
83617
|
-
hunkData.hunkContent.push(currentContent);
|
|
83618
|
-
}
|
|
83619
|
-
additionLineIndex++;
|
|
83620
|
-
parsedAdditionLines++;
|
|
83621
|
-
if (isPartial) currentFile.additionLines.push(line);
|
|
83622
|
-
currentContent.additions++;
|
|
83623
|
-
additionLines++;
|
|
83624
|
-
lastLineType = "addition";
|
|
83625
|
-
} else if (type === "deletion") {
|
|
83626
|
-
if (throwOnError && parsedDeletionLines >= hunkData.deletionCount) throw Error("parsePatchContent: hunk has too many deletion lines");
|
|
83627
|
-
const line = getParsedLineContent(rawLine);
|
|
83628
|
-
if (currentContent == null || currentContent.type !== "change") {
|
|
83629
|
-
currentContent = createContentGroup("change", deletionLineIndex, additionLineIndex);
|
|
83630
|
-
hunkData.hunkContent.push(currentContent);
|
|
83631
|
-
}
|
|
83632
|
-
deletionLineIndex++;
|
|
83633
|
-
parsedDeletionLines++;
|
|
83634
|
-
if (isPartial) currentFile.deletionLines.push(line);
|
|
83635
|
-
currentContent.deletions++;
|
|
83636
|
-
deletionLines++;
|
|
83637
|
-
lastLineType = "deletion";
|
|
83638
|
-
} else if (type === "context") {
|
|
83639
|
-
if (throwOnError && (parsedDeletionLines >= hunkData.deletionCount || parsedAdditionLines >= hunkData.additionCount)) throw Error("parsePatchContent: hunk has too many context lines");
|
|
83640
|
-
const line = getParsedLineContent(rawLine);
|
|
83641
|
-
if (currentContent == null || currentContent.type !== "context") {
|
|
83642
|
-
currentContent = createContentGroup("context", deletionLineIndex, additionLineIndex);
|
|
83643
|
-
hunkData.hunkContent.push(currentContent);
|
|
83644
|
-
}
|
|
83645
|
-
additionLineIndex++;
|
|
83646
|
-
deletionLineIndex++;
|
|
83647
|
-
parsedAdditionLines++;
|
|
83648
|
-
parsedDeletionLines++;
|
|
83649
|
-
if (isPartial) {
|
|
83650
|
-
currentFile.deletionLines.push(line);
|
|
83651
|
-
currentFile.additionLines.push(line);
|
|
83652
|
-
}
|
|
83653
|
-
currentContent.lines++;
|
|
83654
|
-
lastLineType = "context";
|
|
83655
|
-
} else if (type === "metadata" && currentContent != null) {
|
|
83656
|
-
if (currentContent.type === "context") {
|
|
83657
|
-
hunkData.noEOFCRAdditions = true;
|
|
83658
|
-
hunkData.noEOFCRDeletions = true;
|
|
83659
|
-
} else if (lastLineType === "deletion") hunkData.noEOFCRDeletions = true;
|
|
83660
|
-
else if (lastLineType === "addition") hunkData.noEOFCRAdditions = true;
|
|
83661
|
-
if (isPartial && (lastLineType === "addition" || lastLineType === "context")) {
|
|
83662
|
-
const lastIndex = currentFile.additionLines.length - 1;
|
|
83663
|
-
if (lastIndex >= 0) currentFile.additionLines[lastIndex] = cleanLastNewline(currentFile.additionLines[lastIndex]);
|
|
83664
|
-
}
|
|
83665
|
-
if (isPartial && (lastLineType === "deletion" || lastLineType === "context")) {
|
|
83666
|
-
const lastIndex = currentFile.deletionLines.length - 1;
|
|
83667
|
-
if (lastIndex >= 0) currentFile.deletionLines[lastIndex] = cleanLastNewline(currentFile.deletionLines[lastIndex]);
|
|
83668
|
-
}
|
|
83669
|
-
}
|
|
83817
|
+
oldBranch,
|
|
83818
|
+
newBranch: targetBranch
|
|
83819
|
+
});
|
|
83820
|
+
yield* orchestrationEngine.dispatch({
|
|
83821
|
+
type: "thread.meta.update",
|
|
83822
|
+
commandId: yield* serverCommandId("worktree-branch-rename"),
|
|
83823
|
+
threadId: input.threadId,
|
|
83824
|
+
branch: renamed.branch,
|
|
83825
|
+
worktreePath: cwd
|
|
83826
|
+
});
|
|
83827
|
+
yield* vcsStatusBroadcaster.refreshStatus(cwd).pipe(Effect.ignoreCause({ log: true }));
|
|
83828
|
+
}).pipe(Effect.catchCause((cause) => Effect.logWarning("provider command reactor failed to generate or rename worktree branch", {
|
|
83829
|
+
threadId: input.threadId,
|
|
83830
|
+
cwd,
|
|
83831
|
+
oldBranch,
|
|
83832
|
+
cause: Cause.pretty(cause)
|
|
83833
|
+
})));
|
|
83834
|
+
});
|
|
83835
|
+
const maybeGenerateThreadTitleForFirstTurn = Effect.fn("maybeGenerateThreadTitleForFirstTurn")(function* (input) {
|
|
83836
|
+
const attachments = input.attachments ?? [];
|
|
83837
|
+
yield* Effect.gen(function* () {
|
|
83838
|
+
const { textGenerationModelSelection: modelSelection } = yield* serverSettingsService.getSettings;
|
|
83839
|
+
const generated = yield* textGeneration.generateThreadTitle({
|
|
83840
|
+
cwd: input.cwd,
|
|
83841
|
+
message: input.messageText,
|
|
83842
|
+
...attachments.length > 0 ? { attachments } : {},
|
|
83843
|
+
modelSelection
|
|
83844
|
+
});
|
|
83845
|
+
if (!generated) return;
|
|
83846
|
+
const thread = yield* resolveThread(input.threadId);
|
|
83847
|
+
if (!thread) return;
|
|
83848
|
+
if (!canReplaceThreadTitle(thread.title, input.titleSeed)) return;
|
|
83849
|
+
yield* orchestrationEngine.dispatch({
|
|
83850
|
+
type: "thread.meta.update",
|
|
83851
|
+
commandId: yield* serverCommandId("thread-title-rename"),
|
|
83852
|
+
threadId: input.threadId,
|
|
83853
|
+
title: generated.title
|
|
83854
|
+
});
|
|
83855
|
+
}).pipe(Effect.catchCause((cause) => Effect.logWarning("provider command reactor failed to generate or rename thread title", {
|
|
83856
|
+
threadId: input.threadId,
|
|
83857
|
+
cwd: input.cwd,
|
|
83858
|
+
cause: Cause.pretty(cause)
|
|
83859
|
+
})));
|
|
83860
|
+
});
|
|
83861
|
+
const processTurnStartRequested = Effect.fn("processTurnStartRequested")(function* (event) {
|
|
83862
|
+
const key = turnStartKeyForEvent(event);
|
|
83863
|
+
if (yield* hasHandledTurnStartRecently(key)) return;
|
|
83864
|
+
const thread = yield* resolveThread(event.payload.threadId);
|
|
83865
|
+
if (!thread) return;
|
|
83866
|
+
const message = thread.messages.find((entry) => entry.id === event.payload.messageId);
|
|
83867
|
+
if (!message || message.role !== "user") {
|
|
83868
|
+
yield* appendProviderFailureActivity({
|
|
83869
|
+
threadId: event.payload.threadId,
|
|
83870
|
+
kind: "provider.turn.start.failed",
|
|
83871
|
+
summary: "Provider turn start failed",
|
|
83872
|
+
detail: `User message '${event.payload.messageId}' was not found for turn start request.`,
|
|
83873
|
+
turnId: null,
|
|
83874
|
+
createdAt: event.payload.createdAt
|
|
83875
|
+
});
|
|
83876
|
+
return;
|
|
83670
83877
|
}
|
|
83671
|
-
if (
|
|
83672
|
-
|
|
83673
|
-
|
|
83674
|
-
|
|
83675
|
-
|
|
83676
|
-
|
|
83677
|
-
|
|
83678
|
-
|
|
83679
|
-
|
|
83680
|
-
|
|
83681
|
-
|
|
83682
|
-
|
|
83878
|
+
if (thread.messages.filter((entry) => entry.role === "user").length === 1) {
|
|
83879
|
+
const project = yield* resolveProject(thread.projectId);
|
|
83880
|
+
const generationCwd = resolveThreadWorkspaceCwd({
|
|
83881
|
+
thread,
|
|
83882
|
+
projects: project ? [project] : []
|
|
83883
|
+
}) ?? process.cwd();
|
|
83884
|
+
const generationInput = {
|
|
83885
|
+
messageText: message.text,
|
|
83886
|
+
...message.attachments !== void 0 ? { attachments: message.attachments } : {},
|
|
83887
|
+
...event.payload.titleSeed !== void 0 ? { titleSeed: event.payload.titleSeed } : {}
|
|
83888
|
+
};
|
|
83889
|
+
yield* maybeGenerateAndRenameWorktreeBranchForFirstTurn({
|
|
83890
|
+
threadId: event.payload.threadId,
|
|
83891
|
+
branch: thread.branch,
|
|
83892
|
+
worktreePath: thread.worktreePath,
|
|
83893
|
+
...generationInput
|
|
83894
|
+
}).pipe(Effect.forkScoped);
|
|
83895
|
+
if (canReplaceThreadTitle(thread.title, event.payload.titleSeed)) yield* maybeGenerateThreadTitleForFirstTurn({
|
|
83896
|
+
threadId: event.payload.threadId,
|
|
83897
|
+
cwd: generationCwd,
|
|
83898
|
+
...generationInput
|
|
83899
|
+
}).pipe(Effect.forkScoped);
|
|
83683
83900
|
}
|
|
83684
|
-
|
|
83685
|
-
|
|
83686
|
-
|
|
83687
|
-
|
|
83688
|
-
|
|
83689
|
-
|
|
83690
|
-
|
|
83691
|
-
|
|
83692
|
-
|
|
83693
|
-
|
|
83694
|
-
|
|
83695
|
-
|
|
83696
|
-
|
|
83697
|
-
|
|
83698
|
-
|
|
83699
|
-
|
|
83700
|
-
|
|
83701
|
-
|
|
83702
|
-
|
|
83703
|
-
|
|
83704
|
-
|
|
83705
|
-
|
|
83706
|
-
|
|
83707
|
-
|
|
83708
|
-
|
|
83709
|
-
|
|
83710
|
-
|
|
83711
|
-
|
|
83712
|
-
|
|
83713
|
-
|
|
83714
|
-
|
|
83715
|
-
|
|
83716
|
-
|
|
83717
|
-
const
|
|
83718
|
-
|
|
83719
|
-
|
|
83720
|
-
|
|
83721
|
-
|
|
83722
|
-
|
|
83723
|
-
|
|
83724
|
-
|
|
83725
|
-
|
|
83726
|
-
|
|
83727
|
-
|
|
83728
|
-
|
|
83729
|
-
|
|
83730
|
-
|
|
83731
|
-
|
|
83732
|
-
|
|
83733
|
-
|
|
83734
|
-
}
|
|
83735
|
-
function
|
|
83736
|
-
|
|
83737
|
-
|
|
83738
|
-
|
|
83739
|
-
|
|
83740
|
-
|
|
83741
|
-
|
|
83742
|
-
|
|
83743
|
-
|
|
83744
|
-
|
|
83745
|
-
|
|
83746
|
-
|
|
83747
|
-
|
|
83748
|
-
|
|
83749
|
-
|
|
83750
|
-
|
|
83751
|
-
|
|
83752
|
-
|
|
83753
|
-
|
|
83754
|
-
|
|
83755
|
-
|
|
83756
|
-
|
|
83757
|
-
|
|
83758
|
-
|
|
83759
|
-
|
|
83760
|
-
|
|
83761
|
-
|
|
83762
|
-
|
|
83763
|
-
|
|
83764
|
-
|
|
83765
|
-
|
|
83766
|
-
|
|
83767
|
-
|
|
83768
|
-
|
|
83769
|
-
|
|
83770
|
-
|
|
83771
|
-
|
|
83772
|
-
|
|
83773
|
-
|
|
83774
|
-
|
|
83901
|
+
const handleTurnStartFailure = (cause) => {
|
|
83902
|
+
if (Cause.hasInterruptsOnly(cause)) return Effect.void;
|
|
83903
|
+
const detail = formatFailureDetail(cause);
|
|
83904
|
+
return setThreadSessionErrorOnTurnStartFailure({
|
|
83905
|
+
threadId: event.payload.threadId,
|
|
83906
|
+
detail,
|
|
83907
|
+
createdAt: event.payload.createdAt
|
|
83908
|
+
}).pipe(Effect.flatMap(() => appendProviderFailureActivity({
|
|
83909
|
+
threadId: event.payload.threadId,
|
|
83910
|
+
kind: "provider.turn.start.failed",
|
|
83911
|
+
summary: "Provider turn start failed",
|
|
83912
|
+
detail,
|
|
83913
|
+
turnId: null,
|
|
83914
|
+
createdAt: event.payload.createdAt
|
|
83915
|
+
})), Effect.asVoid);
|
|
83916
|
+
};
|
|
83917
|
+
const recoverTurnStartFailure = (cause) => handleTurnStartFailure(cause).pipe(Effect.catchCause((recoveryCause) => Effect.logWarning("provider command reactor failed to recover turn start failure", {
|
|
83918
|
+
eventType: event.type,
|
|
83919
|
+
threadId: event.payload.threadId,
|
|
83920
|
+
cause: Cause.pretty(recoveryCause),
|
|
83921
|
+
originalCause: Cause.pretty(cause)
|
|
83922
|
+
})));
|
|
83923
|
+
const sendTurnRequest = yield* buildSendTurnRequestForThread({
|
|
83924
|
+
threadId: event.payload.threadId,
|
|
83925
|
+
messageText: message.text,
|
|
83926
|
+
...message.attachments !== void 0 ? { attachments: message.attachments } : {},
|
|
83927
|
+
...event.payload.modelSelection !== void 0 ? { modelSelection: event.payload.modelSelection } : {},
|
|
83928
|
+
interactionMode: event.payload.interactionMode,
|
|
83929
|
+
createdAt: event.payload.createdAt
|
|
83930
|
+
}).pipe(Effect.map(Option.some), Effect.catchCause((cause) => handleTurnStartFailure(cause).pipe(Effect.as(Option.none()))));
|
|
83931
|
+
if (Option.isNone(sendTurnRequest)) return;
|
|
83932
|
+
yield* providerService.sendTurn(sendTurnRequest.value).pipe(Effect.catchCause(recoverTurnStartFailure), Effect.forkScoped);
|
|
83933
|
+
});
|
|
83934
|
+
const processTurnInterruptRequested = Effect.fn("processTurnInterruptRequested")(function* (event) {
|
|
83935
|
+
const thread = yield* resolveThread(event.payload.threadId);
|
|
83936
|
+
if (!thread) return;
|
|
83937
|
+
if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
|
|
83938
|
+
threadId: event.payload.threadId,
|
|
83939
|
+
kind: "provider.turn.interrupt.failed",
|
|
83940
|
+
summary: "Provider turn interrupt failed",
|
|
83941
|
+
detail: "No active provider session is bound to this thread.",
|
|
83942
|
+
turnId: event.payload.turnId ?? null,
|
|
83943
|
+
createdAt: event.payload.createdAt
|
|
83944
|
+
});
|
|
83945
|
+
yield* providerService.interruptTurn({ threadId: event.payload.threadId });
|
|
83946
|
+
yield* appendTurnInterruptedActivity({
|
|
83947
|
+
threadId: event.payload.threadId,
|
|
83948
|
+
turnId: event.payload.turnId ?? null,
|
|
83949
|
+
createdAt: event.payload.createdAt
|
|
83950
|
+
});
|
|
83951
|
+
});
|
|
83952
|
+
const processApprovalResponseRequested = Effect.fn("processApprovalResponseRequested")(function* (event) {
|
|
83953
|
+
const thread = yield* resolveThread(event.payload.threadId);
|
|
83954
|
+
if (!thread) return;
|
|
83955
|
+
if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
|
|
83956
|
+
threadId: event.payload.threadId,
|
|
83957
|
+
kind: "provider.approval.respond.failed",
|
|
83958
|
+
summary: "Provider approval response failed",
|
|
83959
|
+
detail: "No active provider session is bound to this thread.",
|
|
83960
|
+
turnId: null,
|
|
83961
|
+
createdAt: event.payload.createdAt,
|
|
83962
|
+
requestId: event.payload.requestId
|
|
83963
|
+
});
|
|
83964
|
+
yield* providerService.respondToRequest({
|
|
83965
|
+
threadId: event.payload.threadId,
|
|
83966
|
+
requestId: event.payload.requestId,
|
|
83967
|
+
decision: event.payload.decision
|
|
83968
|
+
}).pipe(Effect.catchCause((cause) => appendProviderFailureActivity({
|
|
83969
|
+
threadId: event.payload.threadId,
|
|
83970
|
+
kind: "provider.approval.respond.failed",
|
|
83971
|
+
summary: "Provider approval response failed",
|
|
83972
|
+
detail: isUnknownPendingApprovalRequestError(cause) ? stalePendingRequestDetail("approval", event.payload.requestId) : Cause.pretty(cause),
|
|
83973
|
+
turnId: null,
|
|
83974
|
+
createdAt: event.payload.createdAt,
|
|
83975
|
+
requestId: event.payload.requestId
|
|
83976
|
+
})));
|
|
83977
|
+
});
|
|
83978
|
+
const processUserInputResponseRequested = Effect.fn("processUserInputResponseRequested")(function* (event) {
|
|
83979
|
+
const thread = yield* resolveThread(event.payload.threadId);
|
|
83980
|
+
if (!thread) return;
|
|
83981
|
+
if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
|
|
83982
|
+
threadId: event.payload.threadId,
|
|
83983
|
+
kind: "provider.user-input.respond.failed",
|
|
83984
|
+
summary: "Provider user input response failed",
|
|
83985
|
+
detail: "No active provider session is bound to this thread.",
|
|
83986
|
+
turnId: null,
|
|
83987
|
+
createdAt: event.payload.createdAt,
|
|
83988
|
+
requestId: event.payload.requestId
|
|
83989
|
+
});
|
|
83990
|
+
yield* providerService.respondToUserInput({
|
|
83991
|
+
threadId: event.payload.threadId,
|
|
83992
|
+
requestId: event.payload.requestId,
|
|
83993
|
+
answers: event.payload.answers
|
|
83994
|
+
}).pipe(Effect.catchCause((cause) => appendProviderFailureActivity({
|
|
83995
|
+
threadId: event.payload.threadId,
|
|
83996
|
+
kind: "provider.user-input.respond.failed",
|
|
83997
|
+
summary: "Provider user input response failed",
|
|
83998
|
+
detail: isUnknownPendingUserInputRequestError(cause) ? stalePendingRequestDetail("user-input", event.payload.requestId) : Cause.pretty(cause),
|
|
83999
|
+
turnId: null,
|
|
84000
|
+
createdAt: event.payload.createdAt,
|
|
84001
|
+
requestId: event.payload.requestId
|
|
84002
|
+
})));
|
|
84003
|
+
});
|
|
84004
|
+
const processSessionStopRequested = Effect.fn("processSessionStopRequested")(function* (event) {
|
|
84005
|
+
const thread = yield* resolveThread(event.payload.threadId);
|
|
84006
|
+
if (!thread) return;
|
|
84007
|
+
const now = event.payload.createdAt;
|
|
84008
|
+
if (thread.session && thread.session.status !== "stopped") yield* providerService.stopSession({ threadId: thread.id });
|
|
84009
|
+
yield* setThreadSession({
|
|
84010
|
+
threadId: thread.id,
|
|
84011
|
+
session: {
|
|
84012
|
+
threadId: thread.id,
|
|
84013
|
+
status: "stopped",
|
|
84014
|
+
providerName: thread.session?.providerName ?? null,
|
|
84015
|
+
...thread.session?.providerInstanceId !== void 0 ? { providerInstanceId: thread.session.providerInstanceId } : {},
|
|
84016
|
+
runtimeMode: thread.session?.runtimeMode ?? DEFAULT_RUNTIME_MODE,
|
|
84017
|
+
activeTurnId: null,
|
|
84018
|
+
lastError: thread.session?.lastError ?? null,
|
|
84019
|
+
updatedAt: now
|
|
84020
|
+
},
|
|
84021
|
+
createdAt: now
|
|
84022
|
+
});
|
|
84023
|
+
});
|
|
84024
|
+
const processDomainEvent = Effect.fn("processDomainEvent")(function* (event) {
|
|
84025
|
+
yield* Effect.annotateCurrentSpan({
|
|
84026
|
+
"orchestration.event_type": event.type,
|
|
84027
|
+
"orchestration.thread_id": event.payload.threadId,
|
|
84028
|
+
...event.commandId ? { "orchestration.command_id": event.commandId } : {}
|
|
84029
|
+
});
|
|
84030
|
+
yield* increment(orchestrationEventsProcessedTotal, { eventType: event.type });
|
|
84031
|
+
switch (event.type) {
|
|
84032
|
+
case "thread.runtime-mode-set": {
|
|
84033
|
+
const thread = yield* resolveThread(event.payload.threadId);
|
|
84034
|
+
if (!thread?.session || thread.session.status === "stopped") return;
|
|
84035
|
+
const cachedModelSelection = threadModelSelections.get(event.payload.threadId);
|
|
84036
|
+
yield* ensureSessionForThread(event.payload.threadId, event.occurredAt, cachedModelSelection !== void 0 ? { modelSelection: cachedModelSelection } : {});
|
|
84037
|
+
return;
|
|
83775
84038
|
}
|
|
83776
|
-
|
|
83777
|
-
|
|
83778
|
-
|
|
83779
|
-
|
|
83780
|
-
|
|
83781
|
-
|
|
83782
|
-
|
|
84039
|
+
case "thread.turn-start-requested":
|
|
84040
|
+
yield* processTurnStartRequested(event);
|
|
84041
|
+
return;
|
|
84042
|
+
case "thread.turn-interrupt-requested":
|
|
84043
|
+
yield* processTurnInterruptRequested(event);
|
|
84044
|
+
return;
|
|
84045
|
+
case "thread.approval-response-requested":
|
|
84046
|
+
yield* processApprovalResponseRequested(event);
|
|
84047
|
+
return;
|
|
84048
|
+
case "thread.user-input-response-requested":
|
|
84049
|
+
yield* processUserInputResponseRequested(event);
|
|
84050
|
+
return;
|
|
84051
|
+
case "thread.session-stop-requested":
|
|
84052
|
+
yield* processSessionStopRequested(event);
|
|
84053
|
+
return;
|
|
83783
84054
|
}
|
|
83784
|
-
|
|
83785
|
-
|
|
83786
|
-
|
|
83787
|
-
|
|
83788
|
-
|
|
83789
|
-
|
|
83790
|
-
|
|
83791
|
-
|
|
83792
|
-
|
|
83793
|
-
}
|
|
83794
|
-
function startsWithUnifiedDiffFileHeader(contents) {
|
|
83795
|
-
return isUnifiedDiffFileHeaderAt(contents, 0);
|
|
83796
|
-
}
|
|
83797
|
-
function isUnifiedDiffFileHeaderAt(contents, lineStartIndex) {
|
|
83798
|
-
const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);
|
|
83799
|
-
return isUnifiedDiffHeaderLineAt(contents, lineStartIndex, "---") && isUnifiedDiffHeaderLineAt(contents, nextLineStartIndex, "+++");
|
|
83800
|
-
}
|
|
83801
|
-
function isUnifiedDiffHeaderLineAt(contents, lineStartIndex, prefix) {
|
|
83802
|
-
if (!contents.startsWith(prefix, lineStartIndex)) return false;
|
|
83803
|
-
const separator = contents[lineStartIndex + prefix.length];
|
|
83804
|
-
if (separator !== " " && separator !== " ") return false;
|
|
83805
|
-
for (let index = lineStartIndex + prefix.length + 1; index < contents.length; index++) {
|
|
83806
|
-
const char = contents[index];
|
|
83807
|
-
if (char === "\n" || char === "\r") break;
|
|
83808
|
-
if (char !== " " && char !== " ") return true;
|
|
83809
|
-
}
|
|
83810
|
-
return false;
|
|
83811
|
-
}
|
|
83812
|
-
function getNextLineStartIndex(contents, lineStartIndex) {
|
|
83813
|
-
const newlineIndex = contents.indexOf("\n", lineStartIndex);
|
|
83814
|
-
return newlineIndex === -1 ? contents.length : newlineIndex + 1;
|
|
83815
|
-
}
|
|
83816
|
-
function isHunkBodyLine(line) {
|
|
83817
|
-
const firstChar = line[0];
|
|
83818
|
-
return firstChar === "+" || firstChar === "-" || firstChar === " ";
|
|
83819
|
-
}
|
|
83820
|
-
function isFormatPatchVersionSeparator(line) {
|
|
83821
|
-
if (!line.startsWith("--")) return false;
|
|
83822
|
-
for (let index = 2; index < line.length; index++) {
|
|
83823
|
-
const char = line[index];
|
|
83824
|
-
if (char !== " " && char !== " " && char !== "\n" && char !== "\r") return false;
|
|
83825
|
-
}
|
|
83826
|
-
return true;
|
|
83827
|
-
}
|
|
83828
|
-
function parseHunkHeader(line) {
|
|
83829
|
-
if (!line.startsWith("@@ -")) return;
|
|
83830
|
-
let index = 4;
|
|
83831
|
-
const deletionStartResult = readPositiveInteger(line, index);
|
|
83832
|
-
if (deletionStartResult == null) return;
|
|
83833
|
-
const deletionStart = deletionStartResult.value;
|
|
83834
|
-
index = deletionStartResult.endIndex;
|
|
83835
|
-
let deletionCount = 1;
|
|
83836
|
-
if (line[index] === ",") {
|
|
83837
|
-
const deletionCountResult = readPositiveInteger(line, index + 1);
|
|
83838
|
-
if (deletionCountResult == null) return;
|
|
83839
|
-
deletionCount = deletionCountResult.value;
|
|
83840
|
-
index = deletionCountResult.endIndex;
|
|
83841
|
-
}
|
|
83842
|
-
if (line[index] !== " " || line[index + 1] !== "+") return;
|
|
83843
|
-
index += 2;
|
|
83844
|
-
const additionStartResult = readPositiveInteger(line, index);
|
|
83845
|
-
if (additionStartResult == null) return;
|
|
83846
|
-
const additionStart = additionStartResult.value;
|
|
83847
|
-
index = additionStartResult.endIndex;
|
|
83848
|
-
let additionCount = 1;
|
|
83849
|
-
if (line[index] === ",") {
|
|
83850
|
-
const additionCountResult = readPositiveInteger(line, index + 1);
|
|
83851
|
-
if (additionCountResult == null) return;
|
|
83852
|
-
additionCount = additionCountResult.value;
|
|
83853
|
-
index = additionCountResult.endIndex;
|
|
83854
|
-
}
|
|
83855
|
-
if (line[index] !== " " || line[index + 1] !== "@" || line[index + 2] !== "@") return;
|
|
83856
|
-
let hunkContext;
|
|
83857
|
-
const contextStartIndex = index + 3;
|
|
83858
|
-
if (line[contextStartIndex] === " ") hunkContext = trimLineEnd(line.slice(contextStartIndex + 1));
|
|
83859
|
-
return {
|
|
83860
|
-
additionCount,
|
|
83861
|
-
additionStart,
|
|
83862
|
-
deletionCount,
|
|
83863
|
-
deletionStart,
|
|
83864
|
-
hunkContext
|
|
83865
|
-
};
|
|
83866
|
-
}
|
|
83867
|
-
function readPositiveInteger(value, startIndex) {
|
|
83868
|
-
let index = startIndex;
|
|
83869
|
-
let parsedValue = 0;
|
|
83870
|
-
for (; index < value.length; index++) {
|
|
83871
|
-
const digit = value.charCodeAt(index) - 48;
|
|
83872
|
-
if (digit < 0 || digit > 9) break;
|
|
83873
|
-
parsedValue = parsedValue * 10 + digit;
|
|
83874
|
-
}
|
|
83875
|
-
if (index === startIndex) return;
|
|
83876
|
-
return {
|
|
83877
|
-
value: parsedValue,
|
|
83878
|
-
endIndex: index
|
|
83879
|
-
};
|
|
83880
|
-
}
|
|
83881
|
-
function trimLineEnd(value) {
|
|
83882
|
-
if (value.endsWith("\r\n")) return value.slice(0, -2);
|
|
83883
|
-
if (value.endsWith("\n")) return value.slice(0, -1);
|
|
83884
|
-
return value;
|
|
83885
|
-
}
|
|
83886
|
-
function isGitDiffPatch(data) {
|
|
83887
|
-
return data.startsWith("diff --git") || data.includes("\ndiff --git");
|
|
83888
|
-
}
|
|
83889
|
-
function splitAtLinePrefix(contents, prefix) {
|
|
83890
|
-
if (contents.length === 0) return [""];
|
|
83891
|
-
const newlinePrefix = `\n${prefix}`;
|
|
83892
|
-
const firstBoundaryIndex = contents.startsWith(prefix) ? 0 : findLinePrefixIndex(contents, newlinePrefix, 0);
|
|
83893
|
-
if (firstBoundaryIndex === -1) return [contents];
|
|
83894
|
-
const parts = [];
|
|
83895
|
-
if (firstBoundaryIndex > 0) parts.push(contents.slice(0, firstBoundaryIndex));
|
|
83896
|
-
let startIndex = firstBoundaryIndex;
|
|
83897
|
-
for (;;) {
|
|
83898
|
-
const nextBoundaryIndex = findLinePrefixIndex(contents, newlinePrefix, startIndex + 1);
|
|
83899
|
-
if (nextBoundaryIndex === -1) break;
|
|
83900
|
-
parts.push(contents.slice(startIndex, nextBoundaryIndex));
|
|
83901
|
-
startIndex = nextBoundaryIndex;
|
|
83902
|
-
}
|
|
83903
|
-
parts.push(contents.slice(startIndex));
|
|
83904
|
-
return parts;
|
|
83905
|
-
}
|
|
83906
|
-
function findLinePrefixIndex(contents, newlinePrefix, fromIndex) {
|
|
83907
|
-
const index = contents.indexOf(newlinePrefix, fromIndex);
|
|
83908
|
-
return index === -1 ? -1 : index + 1;
|
|
83909
|
-
}
|
|
83910
|
-
function maybeDetachOptionalString(value) {
|
|
83911
|
-
return value == null ? value : detachString(value);
|
|
83912
|
-
}
|
|
83913
|
-
function parseRawLineType(firstChar) {
|
|
83914
|
-
return firstChar === " " ? "context" : firstChar === "\\" ? "metadata" : firstChar === "+" ? "addition" : "deletion";
|
|
83915
|
-
}
|
|
83916
|
-
function getParsedLineContent(rawLine) {
|
|
83917
|
-
const processedLine = rawLine.slice(1);
|
|
83918
|
-
return detachString(processedLine === "" ? "\n" : processedLine);
|
|
83919
|
-
}
|
|
83920
|
-
function createContentGroup(type, deletionLineIndex, additionLineIndex) {
|
|
83921
|
-
if (type === "change") return {
|
|
83922
|
-
type: "change",
|
|
83923
|
-
additions: 0,
|
|
83924
|
-
deletions: 0,
|
|
83925
|
-
additionLineIndex,
|
|
83926
|
-
deletionLineIndex
|
|
83927
|
-
};
|
|
84055
|
+
});
|
|
84056
|
+
const processDomainEventSafely = (event) => processDomainEvent(event).pipe(Effect.catchCause((cause) => {
|
|
84057
|
+
if (Cause.hasInterruptsOnly(cause)) return Effect.failCause(cause);
|
|
84058
|
+
return Effect.logWarning("provider command reactor failed to process event", {
|
|
84059
|
+
eventType: event.type,
|
|
84060
|
+
cause: Cause.pretty(cause)
|
|
84061
|
+
});
|
|
84062
|
+
}));
|
|
84063
|
+
const worker = yield* makeDrainableWorker(processDomainEventSafely);
|
|
83928
84064
|
return {
|
|
83929
|
-
|
|
83930
|
-
|
|
83931
|
-
|
|
83932
|
-
|
|
84065
|
+
start: Effect.fn("start")(function* () {
|
|
84066
|
+
const processEvent = Effect.fn("processEvent")(function* (event) {
|
|
84067
|
+
if (event.type === "thread.runtime-mode-set" || event.type === "thread.turn-start-requested" || event.type === "thread.turn-interrupt-requested" || event.type === "thread.approval-response-requested" || event.type === "thread.user-input-response-requested" || event.type === "thread.session-stop-requested") return yield* worker.enqueue(event);
|
|
84068
|
+
});
|
|
84069
|
+
yield* Effect.forkScoped(Stream.runForEach(orchestrationEngine.streamDomainEvents, processEvent));
|
|
84070
|
+
}),
|
|
84071
|
+
drain: worker.drain
|
|
83933
84072
|
};
|
|
83934
|
-
}
|
|
84073
|
+
});
|
|
84074
|
+
const ProviderCommandReactorLive = Layer.effect(ProviderCommandReactor, make$2);
|
|
83935
84075
|
//#endregion
|
|
83936
84076
|
//#region src/checkpointing/Diffs.ts
|
|
83937
84077
|
function parseTurnDiffFilesFromUnifiedDiff(diff) {
|
|
@@ -83972,6 +84112,7 @@ const make$1 = Effect.gen(function* () {
|
|
|
83972
84112
|
const receiptBus = yield* RuntimeReceiptBus;
|
|
83973
84113
|
const workspaceEntries = yield* WorkspaceEntries;
|
|
83974
84114
|
const vcsStatusBroadcaster = yield* VcsStatusBroadcaster;
|
|
84115
|
+
const threadActivities = yield* ProjectionThreadActivityRepository;
|
|
83975
84116
|
const appendRevertFailureActivity = (input) => Effect.all({
|
|
83976
84117
|
commandId: serverCommandId("checkpoint-revert-failure"),
|
|
83977
84118
|
activityId: serverEventId
|
|
@@ -84060,13 +84201,21 @@ const make$1 = Effect.gen(function* () {
|
|
|
84060
84201
|
checkpointRef: targetCheckpointRef
|
|
84061
84202
|
});
|
|
84062
84203
|
yield* workspaceEntries.refresh(input.cwd);
|
|
84204
|
+
const turnChangedPaths = yield* threadActivities.listByThreadId({ threadId: input.threadId }).pipe(Effect.map((activities) => {
|
|
84205
|
+
const changedPaths = /* @__PURE__ */ new Set();
|
|
84206
|
+
for (const activity of activities) {
|
|
84207
|
+
if (activity.tone !== "tool" || activity.turnId !== input.turnId) continue;
|
|
84208
|
+
for (const changedPath of collectActivityChangedFilePaths(activity.payload)) changedPaths.add(changedPath);
|
|
84209
|
+
}
|
|
84210
|
+
return normalizeChangedFilePaths(changedPaths, input.cwd);
|
|
84211
|
+
}), Effect.orElseSucceed(() => /* @__PURE__ */ new Set()));
|
|
84063
84212
|
const files = yield* checkpointStore.diffCheckpoints({
|
|
84064
84213
|
cwd: input.cwd,
|
|
84065
84214
|
fromCheckpointRef,
|
|
84066
84215
|
toCheckpointRef: targetCheckpointRef,
|
|
84067
84216
|
fallbackFromToHead: false,
|
|
84068
84217
|
ignoreWhitespace: false
|
|
84069
|
-
}).pipe(Effect.map((diff) => parseTurnDiffFilesFromUnifiedDiff(diff).map((file) => ({
|
|
84218
|
+
}).pipe(Effect.map((diff) => parseTurnDiffFilesFromUnifiedDiff(diff).filter((file) => turnChangedPaths.size === 0 || turnChangedPaths.has(file.path)).map((file) => ({
|
|
84070
84219
|
path: file.path,
|
|
84071
84220
|
kind: "modified",
|
|
84072
84221
|
additions: file.additions,
|