@p4code/cli 0.1.8 → 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 +962 -745
- package/dist/client/assets/{DiffPanel-D4tNpljU.js → DiffPanel-BRroAgOK.js} +2 -2
- package/dist/client/assets/{FilePreviewPanel-xICJSzZ6.js → FilePreviewPanel-Bdd2Ml_z.js} +2 -2
- package/dist/client/assets/{PreviewPanel-CK9d1fc5.js → PreviewPanel-DoJd5FXR.js} +2 -2
- package/dist/client/assets/{angular-html-BgzZxO9w.js → angular-html-BA0WzHZ0.js} +2 -2
- package/dist/client/assets/{angular-ts-YFEXVhe6.js → angular-ts-BehluKB7.js} +2 -2
- package/dist/client/assets/{apl-BoBwF9HI.js → apl-DPnuuIo7.js} +2 -2
- package/dist/client/assets/arrow-right-B_11zHBP.js +2 -0
- package/dist/client/assets/{astro-Ds5TXooD.js → astro-G6Zz-WSX.js} +2 -2
- package/dist/client/assets/{blade-CDtJf5YR.js → blade-c1NgE6B9.js} +2 -2
- package/dist/client/assets/{c-JH0umSmP.js → c-BbDaxzL5.js} +2 -2
- package/dist/client/assets/{cobol-gMss6BA3.js → cobol-DPWRf7_s.js} +2 -2
- package/dist/client/assets/{coffee-DESPXYwo.js → coffee-kZI3-HKr.js} +2 -2
- package/dist/client/assets/{cpp-CZztA1XN.js → cpp-DbB1uwNF.js} +2 -2
- package/dist/client/assets/{crystal-CDWlJpLE.js → crystal-C9rif4zq.js} +2 -2
- package/dist/client/assets/{css-CNPTTtX1.js → css-BzXrG2ii.js} +2 -2
- package/dist/client/assets/{edge-DSlrkPAr.js → edge-CIqg8jED.js} +2 -2
- package/dist/client/assets/{elixir-DrLl_wv7.js → elixir-L1xpfUlV.js} +2 -2
- package/dist/client/assets/{elm-CwB92FlT.js → elm-C4bqF3BU.js} +2 -2
- package/dist/client/assets/{erb-DXHrZ2ye.js → erb-DQxpBRS7.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-CuJ4hnrK.js → fileCommentAnnotations-DXLRihuo.js} +2 -2
- package/dist/client/assets/{git-rebase-uRnCoWg0.js → git-rebase-DCFBvSos.js} +2 -2
- package/dist/client/assets/{glimmer-js-DU9fMoZx.js → glimmer-js-CMcw0KDm.js} +2 -2
- package/dist/client/assets/{glimmer-ts-Bftqha5Z.js → glimmer-ts-zKGsihEs.js} +2 -2
- package/dist/client/assets/{glsl-CVVphTeN.js → glsl-C-DKYe1o.js} +2 -2
- package/dist/client/assets/{graphql-CwED2DHh.js → graphql-D-Jaf-It.js} +2 -2
- package/dist/client/assets/{hack-CwiQSrzl.js → hack-Cy1Ek-eJ.js} +2 -2
- package/dist/client/assets/{haml-C2iiqAZE.js → haml-DSBhTnP_.js} +2 -2
- package/dist/client/assets/{handlebars-BtvKqvl0.js → handlebars-BTjhBiVA.js} +2 -2
- package/dist/client/assets/{html-BRvZZmrv.js → html-CuFf_rJP.js} +2 -2
- package/dist/client/assets/{html-derivative-rVjUDzCo.js → html-derivative-B6vKETtb.js} +2 -2
- package/dist/client/assets/{http-Cvb4plLT.js → http-TaTxS49l.js} +2 -2
- package/dist/client/assets/{hurl-TX6OEub-.js → hurl-Jwth1u4b.js} +2 -2
- package/dist/client/assets/index-WQyWsxuV.js +660 -0
- package/dist/client/assets/index-nkPMSYxq.css +1 -0
- package/dist/client/assets/{java-CudutWch.js → java-Ba5MdLVF.js} +2 -2
- package/dist/client/assets/{javascript-D7gB3c_x.js → javascript-_mHojD6_.js} +2 -2
- package/dist/client/assets/{jinja-Ce0WqJfV.js → jinja-BhX9YpO0.js} +2 -2
- package/dist/client/assets/{jison-2U6TlYgq.js → jison-S0Rrxw4o.js} +2 -2
- package/dist/client/assets/{json-oe5h_2FV.js → json-B-G4K1LM.js} +2 -2
- package/dist/client/assets/{jsx-B0f4Z6sx.js → jsx-X6TBdO7T.js} +2 -2
- package/dist/client/assets/{julia-By6UDEAG.js → julia-He6A0R8c.js} +2 -2
- package/dist/client/assets/{just-YTIO1wok.js → just-CQ533yYC.js} +2 -2
- package/dist/client/assets/{latex-B9HLUatB.js → latex-BBBRtbj7.js} +2 -2
- package/dist/client/assets/{liquid-DajcsI9e.js → liquid-CA9B-Q_J.js} +2 -2
- package/dist/client/assets/{lua-CINm0eWo.js → lua-DXLYC8yx.js} +2 -2
- package/dist/client/assets/{marko-DXvL73SK.js → marko-BXfllCK7.js} +2 -2
- package/dist/client/assets/{mdc-CYsP-lJY.js → mdc-D13Xs_kf.js} +2 -2
- package/dist/client/assets/{nginx-CPKmhI0k.js → nginx-HcisF7-i.js} +2 -2
- package/dist/client/assets/{nim-DodS9Uy_.js → nim-YbKRMFDo.js} +2 -2
- package/dist/client/assets/{perl-COac5jCW.js → perl-CV978rzN.js} +2 -2
- package/dist/client/assets/{php-DLugOmp_.js → php-B8Rmr1r4.js} +2 -2
- package/dist/client/assets/{pug-ukoxsRP-.js → pug-CI1Ka8om.js} +2 -2
- package/dist/client/assets/{qml-DEoQyDDD.js → qml-CyQLZsMJ.js} +2 -2
- package/dist/client/assets/{r-CePyxHEB.js → r-C-0JMTYO.js} +2 -2
- package/dist/client/assets/{razor-uhGlTCzi.js → razor-BCppTDFk.js} +2 -2
- package/dist/client/assets/{regexp-BYNm_E6v.js → regexp-DWt_neai.js} +2 -2
- package/dist/client/assets/{rst-BMMyVK7q.js → rst-CDLeyhcr.js} +2 -2
- package/dist/client/assets/{ruby-BBl_q7lV.js → ruby-Bq-7Grqk.js} +2 -2
- package/dist/client/assets/{sas-q_pdbMhY.js → sas-Cn10Nqsd.js} +2 -2
- package/dist/client/assets/{scss-Bf5qLSyj.js → scss-821PYndD.js} +2 -2
- package/dist/client/assets/{shellscript-CnkO-FF6.js → shellscript-CGnWrTWh.js} +2 -2
- package/dist/client/assets/{shellsession-CGTIDec0.js → shellsession-SoJX0uTA.js} +2 -2
- package/dist/client/assets/{soy-D_X4Ckow.js → soy-BDpemwx6.js} +2 -2
- package/dist/client/assets/{sql-wOawmdfM.js → sql-BAre1tMG.js} +2 -2
- package/dist/client/assets/{stata-CKQN4lyV.js → stata-BVoUBbRH.js} +2 -2
- package/dist/client/assets/{surrealql-tjpKGjMP.js → surrealql-77kldaFv.js} +2 -2
- package/dist/client/assets/{svelte-mCzdghlf.js → svelte-BrVa4Wrm.js} +2 -2
- package/dist/client/assets/{templ-COV4wNUr.js → templ-DD-yE4Ei.js} +2 -2
- package/dist/client/assets/{tex-CC1f6JM7.js → tex-3Cd89BRS.js} +2 -2
- package/dist/client/assets/{textarea-BDADSCjn.js → textarea-DJbYd4DI.js} +24 -24
- package/dist/client/assets/{ts-tags-CrIJ77ir.js → ts-tags-CqnWMU9s.js} +2 -2
- package/dist/client/assets/{tsx-IX8SGkp3.js → tsx-C56Uu7is.js} +2 -2
- package/dist/client/assets/{twig-DXR_a9UJ.js → twig-2EWf2LgK.js} +2 -2
- package/dist/client/assets/{typescript-BgLtzzgs.js → typescript-DoXLYiyl.js} +2 -2
- package/dist/client/assets/{vue-Dzfv___3.js → vue-DIv66ZbN.js} +2 -2
- package/dist/client/assets/{vue-html-BHyzHcFt.js → vue-html-DJnU3oci.js} +2 -2
- package/dist/client/assets/{vue-vine-DOSBq7Kw.js → vue-vine-CnFyQ4Cm.js} +2 -2
- package/dist/client/assets/{xml-BI5bRQfx.js → xml-DflQf7I-.js} +2 -2
- package/dist/client/assets/{xsl-B4FzWFML.js → xsl-DegV0fmP.js} +2 -2
- package/dist/client/assets/{yaml-CHgKneKM.js → yaml-CQI6ctBx.js} +2 -2
- package/dist/client/index.html +3 -3
- package/package.json +1 -1
- package/dist/client/assets/arrow-right-CXxWzaql.js +0 -2
- package/dist/client/assets/index-CTDey6k4.css +0 -1
- package/dist/client/assets/index-DJPm8QPz.js +0 -664
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
|
});
|
|
@@ -7076,6 +7072,15 @@ const AssigneeField = TrimmedNonEmptyString.check(Schema$1.isMaxLength(TASK_ASSI
|
|
|
7076
7072
|
* no remote, where there is nothing stable to key on.
|
|
7077
7073
|
*/
|
|
7078
7074
|
const RepositoryKeyField = TrimmedNonEmptyString.pipe(Schema$1.annotateEncoded({ description: "Canonical repository key (normalized git remote, e.g. github.com/owner/repo). Portable across machines, unlike projectId." }));
|
|
7075
|
+
/**
|
|
7076
|
+
* Manual board position within a column, as a lexicographic fractional key.
|
|
7077
|
+
*
|
|
7078
|
+
* Compared as a plain string: smaller sorts higher. Keys are minted by the
|
|
7079
|
+
* board between the neighbours of a drop, so moving one card writes one row
|
|
7080
|
+
* rather than renumbering the column. `null` means the task has never been
|
|
7081
|
+
* placed by hand and falls back to the priority/recency order.
|
|
7082
|
+
*/
|
|
7083
|
+
const OrderKeyField = TrimmedNonEmptyString.pipe(Schema$1.annotateEncoded({ description: "Manual board position key. Lexicographic: smaller sorts higher in the column. Null means no manual position." }));
|
|
7079
7084
|
const LabelsField = Schema$1.Array(TaskLabel).check(Schema$1.isMaxLength(TASK_LABELS_MAX_COUNT)).pipe(Schema$1.annotateEncoded({ description: "Free-form tags used to group and filter tasks." }));
|
|
7080
7085
|
const TaskIdField = TaskId.pipe(Schema$1.annotateEncoded({ description: "Id of the task to act on - the UUID or the readable id (e.g. P4-12)." }));
|
|
7081
7086
|
const Task = Schema$1.Struct({
|
|
@@ -7089,6 +7094,15 @@ const Task = Schema$1.Struct({
|
|
|
7089
7094
|
*/
|
|
7090
7095
|
readableId: Schema$1.NullOr(TrimmedNonEmptyString).pipe(Schema$1.withDecodingDefault(Effect.succeed(null))),
|
|
7091
7096
|
/**
|
|
7097
|
+
* Manual board position: a lexicographic fractional key, compared as a plain
|
|
7098
|
+
* string, smaller first. Written only when a card is dragged to a position;
|
|
7099
|
+
* `null` means "never placed by hand" and the board falls back to its
|
|
7100
|
+
* priority/recency order. Nullable-with-default for the same version-skew
|
|
7101
|
+
* reason as `readableId`: a row from a store without the migration decodes to
|
|
7102
|
+
* `null` rather than failing the whole board.
|
|
7103
|
+
*/
|
|
7104
|
+
orderKey: Schema$1.NullOr(TrimmedNonEmptyString).pipe(Schema$1.withDecodingDefault(Effect.succeed(null))),
|
|
7105
|
+
/**
|
|
7092
7106
|
* The project this task belongs to, or `null` for a task that is not scoped
|
|
7093
7107
|
* to one. This references the existing workspace project registry rather than
|
|
7094
7108
|
* a task-board-private notion of a project.
|
|
@@ -7141,7 +7155,13 @@ const TaskCreateInput = Schema$1.Struct({
|
|
|
7141
7155
|
*/
|
|
7142
7156
|
const HubTaskCreateInput = Schema$1.Struct({
|
|
7143
7157
|
...TaskCreateInput.fields,
|
|
7144
|
-
readableIdPrefix: Schema$1.optional(TrimmedNonEmptyString)
|
|
7158
|
+
readableIdPrefix: Schema$1.optional(TrimmedNonEmptyString),
|
|
7159
|
+
/**
|
|
7160
|
+
* Carried on the hub's create route (but not the public one) so a server
|
|
7161
|
+
* mirroring an already-placed row to the hub does not lose its position.
|
|
7162
|
+
* An agent filing a new task has no business picking a slot.
|
|
7163
|
+
*/
|
|
7164
|
+
orderKey: Schema$1.optional(OrderKeyField)
|
|
7145
7165
|
});
|
|
7146
7166
|
/**
|
|
7147
7167
|
* Every field is optional and an omitted field is left untouched. The nullable
|
|
@@ -7158,7 +7178,8 @@ const TaskUpdateInput = Schema$1.Struct({
|
|
|
7158
7178
|
status: Schema$1.optional(StatusField),
|
|
7159
7179
|
priority: Schema$1.optional(PriorityField),
|
|
7160
7180
|
assignee: Schema$1.optional(Schema$1.NullOr(AssigneeField)),
|
|
7161
|
-
labels: Schema$1.optional(LabelsField)
|
|
7181
|
+
labels: Schema$1.optional(LabelsField),
|
|
7182
|
+
orderKey: Schema$1.optional(Schema$1.NullOr(OrderKeyField))
|
|
7162
7183
|
});
|
|
7163
7184
|
/**
|
|
7164
7185
|
* A task an agent has drafted but has not filed.
|
|
@@ -12112,6 +12133,20 @@ var _037_TaskReadableIds_default = Effect.gen(function* () {
|
|
|
12112
12133
|
`;
|
|
12113
12134
|
});
|
|
12114
12135
|
//#endregion
|
|
12136
|
+
//#region src/persistence/Migrations/038_TaskOrderKeys.ts
|
|
12137
|
+
/**
|
|
12138
|
+
* Manual board position (`order_key`): a lexicographic fractional key written
|
|
12139
|
+
* when a card is dragged to a position, so one move rewrites one row.
|
|
12140
|
+
*
|
|
12141
|
+
* Existing rows are deliberately not backfilled. A null key means "never placed
|
|
12142
|
+
* by hand", and the board's comparator falls back to the old priority/recency
|
|
12143
|
+
* order for those - so a board nobody has dragged on looks exactly as it did
|
|
12144
|
+
* before this migration.
|
|
12145
|
+
*/
|
|
12146
|
+
var _038_TaskOrderKeys_default = Effect.gen(function* () {
|
|
12147
|
+
yield* (yield* SqlClient.SqlClient)`ALTER TABLE tasks ADD COLUMN order_key TEXT`;
|
|
12148
|
+
});
|
|
12149
|
+
//#endregion
|
|
12115
12150
|
//#region src/persistence/Migrations.ts
|
|
12116
12151
|
/**
|
|
12117
12152
|
* MigrationsLive - Migration runner with inline loader
|
|
@@ -12317,6 +12352,11 @@ const migrationEntries = [
|
|
|
12317
12352
|
37,
|
|
12318
12353
|
"TaskReadableIds",
|
|
12319
12354
|
_037_TaskReadableIds_default
|
|
12355
|
+
],
|
|
12356
|
+
[
|
|
12357
|
+
38,
|
|
12358
|
+
"TaskOrderKeys",
|
|
12359
|
+
_038_TaskOrderKeys_default
|
|
12320
12360
|
]
|
|
12321
12361
|
];
|
|
12322
12362
|
const makeMigrationLoader = (throughId) => Migrator.fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
|
|
@@ -13950,6 +13990,7 @@ const TASK_COLUMNS = `
|
|
|
13950
13990
|
priority,
|
|
13951
13991
|
assignee,
|
|
13952
13992
|
labels_json AS "labels",
|
|
13993
|
+
order_key AS "orderKey",
|
|
13953
13994
|
created_at AS "createdAt",
|
|
13954
13995
|
updated_at AS "updatedAt"
|
|
13955
13996
|
`;
|
|
@@ -13972,6 +14013,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
13972
14013
|
priority,
|
|
13973
14014
|
assignee,
|
|
13974
14015
|
labels_json,
|
|
14016
|
+
order_key,
|
|
13975
14017
|
created_at,
|
|
13976
14018
|
updated_at
|
|
13977
14019
|
)
|
|
@@ -13987,6 +14029,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
13987
14029
|
${row.priority},
|
|
13988
14030
|
${row.assignee},
|
|
13989
14031
|
${JSON.stringify(row.labels)},
|
|
14032
|
+
${row.orderKey},
|
|
13990
14033
|
${row.createdAt},
|
|
13991
14034
|
${row.updatedAt}
|
|
13992
14035
|
)
|
|
@@ -14002,6 +14045,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
14002
14045
|
priority = excluded.priority,
|
|
14003
14046
|
assignee = excluded.assignee,
|
|
14004
14047
|
labels_json = excluded.labels_json,
|
|
14048
|
+
order_key = excluded.order_key,
|
|
14005
14049
|
created_at = excluded.created_at,
|
|
14006
14050
|
updated_at = excluded.updated_at
|
|
14007
14051
|
`
|
|
@@ -14099,6 +14143,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
14099
14143
|
...input.priority !== void 0 ? { priority: input.priority } : {},
|
|
14100
14144
|
...input.assignee !== void 0 ? { assignee: input.assignee } : {},
|
|
14101
14145
|
...input.labels !== void 0 ? { labels: input.labels } : {},
|
|
14146
|
+
...input.orderKey !== void 0 ? { orderKey: input.orderKey } : {},
|
|
14102
14147
|
updatedAt
|
|
14103
14148
|
};
|
|
14104
14149
|
yield* upsertTaskRow(updated);
|
|
@@ -14136,6 +14181,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
14136
14181
|
...input.patch.priority !== void 0 ? { priority: input.patch.priority } : {},
|
|
14137
14182
|
...input.patch.assignee !== void 0 ? { assignee: input.patch.assignee } : {},
|
|
14138
14183
|
...input.patch.labels !== void 0 ? { labels: input.patch.labels } : {},
|
|
14184
|
+
...input.patch.orderKey !== void 0 ? { orderKey: input.patch.orderKey } : {},
|
|
14139
14185
|
updatedAt
|
|
14140
14186
|
};
|
|
14141
14187
|
yield* upsertTaskRow(updated);
|
|
@@ -14268,6 +14314,7 @@ const createTaskRoute = HttpRouter.add("POST", "/tasks", respondToHubFailures(Ef
|
|
|
14268
14314
|
priority: input.priority ?? "none",
|
|
14269
14315
|
assignee: input.assignee ?? null,
|
|
14270
14316
|
labels: input.labels ?? [],
|
|
14317
|
+
orderKey: input.orderKey ?? null,
|
|
14271
14318
|
createdAt: timestamp,
|
|
14272
14319
|
updatedAt: timestamp
|
|
14273
14320
|
};
|
|
@@ -14554,6 +14601,16 @@ var _004_TaskReadableIds_default = Effect.gen(function* () {
|
|
|
14554
14601
|
`;
|
|
14555
14602
|
});
|
|
14556
14603
|
//#endregion
|
|
14604
|
+
//#region src/hub/Migrations/005_TaskOrderKeys.ts
|
|
14605
|
+
/**
|
|
14606
|
+
* Manual board position (`order_key`), mirroring the environment server's
|
|
14607
|
+
* migration 038: a lexicographic fractional key written when a card is dragged
|
|
14608
|
+
* to a position. No backfill - null falls back to priority/recency order.
|
|
14609
|
+
*/
|
|
14610
|
+
var _005_TaskOrderKeys_default = Effect.gen(function* () {
|
|
14611
|
+
yield* (yield* SqlClient.SqlClient)`ALTER TABLE tasks ADD COLUMN order_key TEXT`;
|
|
14612
|
+
});
|
|
14613
|
+
//#endregion
|
|
14557
14614
|
//#region src/hub/Migrations.ts
|
|
14558
14615
|
/**
|
|
14559
14616
|
* Hub migrations.
|
|
@@ -14584,6 +14641,11 @@ const hubMigrationEntries = [
|
|
|
14584
14641
|
4,
|
|
14585
14642
|
"TaskReadableIds",
|
|
14586
14643
|
_004_TaskReadableIds_default
|
|
14644
|
+
],
|
|
14645
|
+
[
|
|
14646
|
+
5,
|
|
14647
|
+
"TaskOrderKeys",
|
|
14648
|
+
_005_TaskOrderKeys_default
|
|
14587
14649
|
]
|
|
14588
14650
|
];
|
|
14589
14651
|
const hubMigrationLoader = Migrator.fromRecord(Object.fromEntries(hubMigrationEntries.map(([id, name, migration]) => [`${id}_${name}`, migration])));
|
|
@@ -28924,222 +28986,868 @@ const staticAndDevRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* (
|
|
|
28924
28986
|
contentType
|
|
28925
28987
|
});
|
|
28926
28988
|
}));
|
|
28927
|
-
|
|
28928
|
-
|
|
28929
|
-
|
|
28930
|
-
|
|
28931
|
-
|
|
28932
|
-
operation: CheckpointDiffOperation,
|
|
28933
|
-
threadId: ThreadId
|
|
28934
|
-
}) {
|
|
28935
|
-
get message() {
|
|
28936
|
-
const result = this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
|
|
28937
|
-
return `Checkpoint invariant violation in ${this.operation}: Computed ${result} result does not satisfy contract schema.`;
|
|
28938
|
-
}
|
|
28939
|
-
};
|
|
28940
|
-
/** Projection state no longer contains the requested checkpoint thread. */
|
|
28941
|
-
var CheckpointThreadNotFoundError = class extends Schema$1.TaggedErrorClass()("CheckpointThreadNotFoundError", {
|
|
28942
|
-
operation: CheckpointDiffOperation,
|
|
28943
|
-
threadId: ThreadId
|
|
28944
|
-
}) {
|
|
28945
|
-
get message() {
|
|
28946
|
-
return `Checkpoint invariant violation in ${this.operation}: Thread '${this.threadId}' not found.`;
|
|
28947
|
-
}
|
|
28948
|
-
};
|
|
28949
|
-
/** The checkpoint thread has no workspace path from which to compute a diff. */
|
|
28950
|
-
var CheckpointWorkspacePathMissingError = class extends Schema$1.TaggedErrorClass()("CheckpointWorkspacePathMissingError", {
|
|
28951
|
-
operation: CheckpointDiffOperation,
|
|
28952
|
-
threadId: ThreadId
|
|
28953
|
-
}) {
|
|
28954
|
-
get message() {
|
|
28955
|
-
const diff = this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
|
|
28956
|
-
return `Checkpoint invariant violation in ${this.operation}: Workspace path missing for thread '${this.threadId}' when computing ${diff}.`;
|
|
28957
|
-
}
|
|
28958
|
-
};
|
|
28959
|
-
/** The requested turn lies beyond the latest available checkpoint. */
|
|
28960
|
-
var CheckpointTurnRangeUnavailableError = class extends Schema$1.TaggedErrorClass()("CheckpointTurnRangeUnavailableError", {
|
|
28961
|
-
operation: CheckpointDiffOperation,
|
|
28962
|
-
threadId: ThreadId,
|
|
28963
|
-
requestedTurnCount: NonNegativeInt,
|
|
28964
|
-
availableTurnCount: NonNegativeInt
|
|
28965
|
-
}) {
|
|
28966
|
-
get message() {
|
|
28967
|
-
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;
|
|
28968
28994
|
}
|
|
28969
|
-
};
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
|
|
28973
|
-
|
|
28974
|
-
|
|
28975
|
-
|
|
28976
|
-
|
|
28977
|
-
|
|
28978
|
-
|
|
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--;
|
|
28979
29013
|
}
|
|
28980
|
-
|
|
29014
|
+
return contents.slice(0, end);
|
|
29015
|
+
}
|
|
28981
29016
|
//#endregion
|
|
28982
|
-
//#region
|
|
28983
|
-
const
|
|
28984
|
-
|
|
28985
|
-
|
|
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);
|
|
28986
29025
|
}
|
|
28987
|
-
function
|
|
28988
|
-
|
|
28989
|
-
if (
|
|
28990
|
-
|
|
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));
|
|
28991
29033
|
}
|
|
28992
29034
|
//#endregion
|
|
28993
|
-
//#region
|
|
28994
|
-
function
|
|
28995
|
-
|
|
28996
|
-
|
|
28997
|
-
|
|
28998
|
-
|
|
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();
|
|
28999
29041
|
}
|
|
29000
|
-
return remoteNames;
|
|
29001
|
-
}
|
|
29002
|
-
function parseRemoteNames(stdout) {
|
|
29003
|
-
return parseRemoteNamesInGitOrder(stdout).toSorted((a, b) => b.length - a.length);
|
|
29004
29042
|
}
|
|
29005
|
-
function
|
|
29006
|
-
const
|
|
29007
|
-
|
|
29008
|
-
|
|
29009
|
-
|
|
29010
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
|
|
29017
|
-
|
|
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);
|
|
29018
29066
|
}
|
|
29019
|
-
return null;
|
|
29020
|
-
}
|
|
29021
|
-
function extractBranchNameFromRemoteRef(ref, options) {
|
|
29022
|
-
const normalized = ref.trim();
|
|
29023
|
-
if (normalized.length === 0) return "";
|
|
29024
|
-
if (normalized.startsWith("refs/remotes/")) return extractBranchNameFromRemoteRef(normalized.slice(13), options);
|
|
29025
|
-
const parsedRemoteRef = parseRemoteRefWithRemoteNames(normalized, options?.remoteName ? [options.remoteName] : options?.remoteNames ?? []);
|
|
29026
|
-
if (parsedRemoteRef) return parsedRemoteRef.branchName;
|
|
29027
|
-
const firstSlash = normalized.indexOf("/");
|
|
29028
|
-
if (firstSlash === -1) return normalized;
|
|
29029
|
-
return normalized.slice(firstSlash + 1).trim();
|
|
29030
|
-
}
|
|
29031
|
-
//#endregion
|
|
29032
|
-
//#region src/vcs/GitVcsDriverCore.ts
|
|
29033
|
-
const DEFAULT_TIMEOUT_MS$5 = 3e4;
|
|
29034
|
-
const DEFAULT_MAX_OUTPUT_BYTES$1 = 1e6;
|
|
29035
|
-
const OUTPUT_TRUNCATED_MARKER$1 = "\n\n[truncated]";
|
|
29036
|
-
const PREPARED_COMMIT_PATCH_MAX_OUTPUT_BYTES = 49e3;
|
|
29037
|
-
const RANGE_COMMIT_SUMMARY_MAX_OUTPUT_BYTES = 19e3;
|
|
29038
|
-
const RANGE_DIFF_SUMMARY_MAX_OUTPUT_BYTES = 19e3;
|
|
29039
|
-
const RANGE_DIFF_PATCH_MAX_OUTPUT_BYTES = 59e3;
|
|
29040
|
-
const REVIEW_DIFF_PATCH_MAX_OUTPUT_BYTES = 12e4;
|
|
29041
|
-
const REVIEW_UNTRACKED_DIFF_MAX_OUTPUT_BYTES = 8e4;
|
|
29042
|
-
const WORKSPACE_FILES_MAX_OUTPUT_BYTES$1 = 12e4;
|
|
29043
|
-
const STATUS_UPSTREAM_REFRESH_INTERVAL = Duration.seconds(15);
|
|
29044
|
-
const STATUS_UPSTREAM_REFRESH_TIMEOUT = Duration.seconds(5);
|
|
29045
|
-
const STATUS_UPSTREAM_REFRESH_FAILURE_BASE_COOLDOWN = Duration.seconds(30);
|
|
29046
|
-
const STATUS_UPSTREAM_REFRESH_FAILURE_MAX_COOLDOWN = Duration.minutes(15);
|
|
29047
|
-
const STATUS_UPSTREAM_REFRESH_CACHE_CAPACITY = 2048;
|
|
29048
|
-
const REPOSITORY_PATHS_CACHE_CAPACITY = 2048;
|
|
29049
|
-
const REPOSITORY_PATHS_CACHE_TTL = Duration.minutes(10);
|
|
29050
|
-
const REPOSITORY_PATHS_REFRESH_COALESCE_TTL = Duration.seconds(5);
|
|
29051
|
-
const NON_REPOSITORY_PATHS_CACHE_TTL = Duration.seconds(1);
|
|
29052
|
-
const LIST_REFS_SNAPSHOT_CACHE_CAPACITY = 64;
|
|
29053
|
-
const LIST_REFS_SNAPSHOT_CACHE_TTL = Duration.minutes(2);
|
|
29054
|
-
const LIST_REFS_REFRESH_COALESCE_TTL = Duration.seconds(5);
|
|
29055
|
-
const LIST_REFS_REFRESH_FAILURE_COOLDOWN = Duration.seconds(30);
|
|
29056
|
-
const STATUS_UPSTREAM_REFRESH_ENV = Object.freeze({
|
|
29057
|
-
GCM_INTERACTIVE: "never",
|
|
29058
|
-
GIT_ASKPASS: "",
|
|
29059
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
29060
|
-
SSH_ASKPASS: "",
|
|
29061
|
-
SSH_ASKPASS_REQUIRE: "never"
|
|
29062
|
-
});
|
|
29063
|
-
const DEFAULT_BASE_BRANCH_CANDIDATES = ["main", "master"];
|
|
29064
|
-
const GIT_LIST_BRANCHES_DEFAULT_LIMIT = 100;
|
|
29065
|
-
const NON_REPOSITORY_STATUS_DETAILS = Object.freeze({
|
|
29066
|
-
isRepo: false,
|
|
29067
|
-
hasOriginRemote: false,
|
|
29068
|
-
isDefaultBranch: false,
|
|
29069
|
-
branch: null,
|
|
29070
|
-
upstreamRef: null,
|
|
29071
|
-
hasWorkingTreeChanges: false,
|
|
29072
|
-
workingTree: {
|
|
29073
|
-
files: [],
|
|
29074
|
-
insertions: 0,
|
|
29075
|
-
deletions: 0
|
|
29076
|
-
},
|
|
29077
|
-
hasUpstream: false,
|
|
29078
|
-
aheadCount: 0,
|
|
29079
|
-
behindCount: 0,
|
|
29080
|
-
aheadOfDefaultCount: 0
|
|
29081
|
-
});
|
|
29082
|
-
const NON_REPOSITORY_REMOTE_STATUS_DETAILS = Object.freeze({
|
|
29083
|
-
isRepo: false,
|
|
29084
|
-
isDefaultBranch: false,
|
|
29085
|
-
branch: null,
|
|
29086
|
-
upstreamRef: null,
|
|
29087
|
-
hasUpstream: false,
|
|
29088
|
-
aheadCount: 0,
|
|
29089
|
-
behindCount: 0,
|
|
29090
|
-
aheadOfDefaultCount: 0
|
|
29091
|
-
});
|
|
29092
|
-
var StatusRemoteRefreshCacheKey = class extends Data.Class {};
|
|
29093
|
-
function statusUpstreamRefreshFailureCooldown(consecutiveFailures) {
|
|
29094
|
-
const exponent = Math.max(0, consecutiveFailures - 1);
|
|
29095
|
-
const cooldownMs = Duration.toMillis(STATUS_UPSTREAM_REFRESH_FAILURE_BASE_COOLDOWN) * Math.pow(2, exponent);
|
|
29096
|
-
return Duration.min(Duration.millis(cooldownMs), STATUS_UPSTREAM_REFRESH_FAILURE_MAX_COOLDOWN);
|
|
29097
|
-
}
|
|
29098
|
-
var GitRefsSnapshotCacheKey = class extends Data.Class {};
|
|
29099
|
-
var GitRefsRefreshCacheKey = class extends Data.Class {};
|
|
29100
|
-
function parseBranchAb(value) {
|
|
29101
|
-
const match = value.match(/^\+(\d+)\s+-(\d+)$/);
|
|
29102
|
-
if (!match) return {
|
|
29103
|
-
ahead: 0,
|
|
29104
|
-
behind: 0
|
|
29105
|
-
};
|
|
29106
29067
|
return {
|
|
29107
|
-
|
|
29108
|
-
|
|
29068
|
+
patchMetadata,
|
|
29069
|
+
files
|
|
29109
29070
|
};
|
|
29110
29071
|
}
|
|
29111
|
-
function
|
|
29112
|
-
|
|
29113
|
-
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
|
|
29118
|
-
|
|
29119
|
-
const
|
|
29120
|
-
const
|
|
29121
|
-
|
|
29122
|
-
|
|
29123
|
-
|
|
29124
|
-
|
|
29125
|
-
|
|
29126
|
-
|
|
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;
|
|
29127
29274
|
}
|
|
29128
|
-
return
|
|
29129
|
-
|
|
29130
|
-
|
|
29131
|
-
|
|
29132
|
-
const
|
|
29133
|
-
|
|
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;
|
|
29134
29284
|
}
|
|
29135
|
-
if (!
|
|
29136
|
-
|
|
29137
|
-
|
|
29138
|
-
|
|
29139
|
-
|
|
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";
|
|
29140
29290
|
}
|
|
29141
|
-
|
|
29142
|
-
return
|
|
29291
|
+
if (currentFile.type !== "rename-pure" && currentFile.type !== "rename-changed") currentFile.prevName = void 0;
|
|
29292
|
+
return currentFile;
|
|
29293
|
+
}
|
|
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;
|
|
29143
29851
|
}
|
|
29144
29852
|
function filterBranchesForListQuery(refs, query) {
|
|
29145
29853
|
if (!query) return refs;
|
|
@@ -31530,6 +32238,32 @@ function buildTurnDiffResult(input, diff) {
|
|
|
31530
32238
|
const make$39 = Effect.gen(function* () {
|
|
31531
32239
|
const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
|
|
31532
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);
|
|
31533
32267
|
const getTurnDiff = Effect.fn("getTurnDiff")(function* (input) {
|
|
31534
32268
|
const operation = "CheckpointDiffQuery.getTurnDiff";
|
|
31535
32269
|
const ignoreWhitespace = input.ignoreWhitespace ?? true;
|
|
@@ -31583,13 +32317,16 @@ const make$39 = Effect.gen(function* () {
|
|
|
31583
32317
|
turnCount: input.toTurnCount,
|
|
31584
32318
|
checkpoint: "to"
|
|
31585
32319
|
});
|
|
31586
|
-
const
|
|
32320
|
+
const diff = yield* checkpointStore.diffCheckpoints({
|
|
31587
32321
|
cwd: workspaceCwd,
|
|
31588
32322
|
fromCheckpointRef,
|
|
31589
32323
|
toCheckpointRef,
|
|
31590
32324
|
fallbackFromToHead: false,
|
|
31591
32325
|
ignoreWhitespace
|
|
31592
|
-
}).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));
|
|
31593
32330
|
if (!isTurnDiffResult(turnDiff)) return yield* new CheckpointDiffResultInvalidError({
|
|
31594
32331
|
operation,
|
|
31595
32332
|
threadId: input.threadId
|
|
@@ -31647,11 +32384,12 @@ const make$39 = Effect.gen(function* () {
|
|
|
31647
32384
|
fallbackFromToHead: false,
|
|
31648
32385
|
ignoreWhitespace
|
|
31649
32386
|
}).pipe(Effect.withSpan("checkpoint.fullThread.diffCheckpoints"));
|
|
32387
|
+
const changedPaths = yield* collectThreadChangedFilePaths(input.threadId, null);
|
|
31650
32388
|
const turnDiff = buildTurnDiffResult({
|
|
31651
32389
|
threadId: input.threadId,
|
|
31652
32390
|
fromTurnCount: 0,
|
|
31653
32391
|
toTurnCount: input.toTurnCount
|
|
31654
|
-
}, diff);
|
|
32392
|
+
}, attributeDiffToThread(diff, changedPaths, workspaceCwd));
|
|
31655
32393
|
if (!isTurnDiffResult(turnDiff)) return yield* new CheckpointDiffResultInvalidError({
|
|
31656
32394
|
operation,
|
|
31657
32395
|
threadId: input.threadId
|
|
@@ -32231,7 +32969,7 @@ const normalizeDispatchCommand = (command) => Effect.gen(function* () {
|
|
|
32231
32969
|
const buildTaskRow = (input, taskId, timestamp, repositoryKey = null) => ({
|
|
32232
32970
|
taskId,
|
|
32233
32971
|
projectId: input.projectId ?? null,
|
|
32234
|
-
repositoryKey,
|
|
32972
|
+
repositoryKey: repositoryKey ?? input.repositoryKey ?? null,
|
|
32235
32973
|
threadId: input.threadId ?? null,
|
|
32236
32974
|
title: input.title,
|
|
32237
32975
|
body: input.body ?? "",
|
|
@@ -32239,6 +32977,7 @@ const buildTaskRow = (input, taskId, timestamp, repositoryKey = null) => ({
|
|
|
32239
32977
|
priority: input.priority ?? "none",
|
|
32240
32978
|
assignee: input.assignee ?? null,
|
|
32241
32979
|
labels: input.labels ?? [],
|
|
32980
|
+
orderKey: null,
|
|
32242
32981
|
createdAt: timestamp,
|
|
32243
32982
|
updatedAt: timestamp
|
|
32244
32983
|
});
|
|
@@ -43349,6 +44088,7 @@ const makeRemoteTaskRepository = Effect.fn("makeRemoteTaskRepository")(function*
|
|
|
43349
44088
|
priority: row.priority,
|
|
43350
44089
|
...row.assignee === null ? {} : { assignee: row.assignee },
|
|
43351
44090
|
labels: row.labels,
|
|
44091
|
+
...row.orderKey === null ? {} : { orderKey: row.orderKey },
|
|
43352
44092
|
...readableIdPrefix === void 0 ? {} : { readableIdPrefix }
|
|
43353
44093
|
}));
|
|
43354
44094
|
if (response.status !== 201 && response.status !== 200) return yield* hubUnavailable(operation, `status ${response.status}`);
|
|
@@ -83332,538 +84072,6 @@ const make$2 = Effect.gen(function* () {
|
|
|
83332
84072
|
};
|
|
83333
84073
|
});
|
|
83334
84074
|
const ProviderCommandReactorLive = Layer.effect(ProviderCommandReactor, make$2);
|
|
83335
|
-
(() => {
|
|
83336
|
-
try {
|
|
83337
|
-
return process.env.NODE_ENV === "development";
|
|
83338
|
-
} catch {
|
|
83339
|
-
return false;
|
|
83340
|
-
}
|
|
83341
|
-
})();
|
|
83342
|
-
const COMMIT_METADATA_SPLIT = /(?=^From [a-f0-9]+ .+$)/m;
|
|
83343
|
-
const GIT_DIFF_FILE_BREAK_REGEX = /(?=^diff --git)/gm;
|
|
83344
|
-
const FILENAME_HEADER_REGEX = /^(---|\+\+\+)\s+([^\t\r\n]+)/;
|
|
83345
|
-
const FILENAME_HEADER_REGEX_GIT = /^(---|\+\+\+)\s+[ab]\/([^\t\r\n]+)/;
|
|
83346
|
-
const ALTERNATE_FILE_NAMES_GIT = /^diff --git (?:"a\/(.+?)"|a\/(.+?)) (?:"b\/(.+?)"|b\/(.+?))$/;
|
|
83347
|
-
const INDEX_LINE_METADATA = /^index ([0-9a-f]+)\.\.([0-9a-f]+)(?: (\d+))?$/i;
|
|
83348
|
-
Object.freeze({
|
|
83349
|
-
fromStart: 0,
|
|
83350
|
-
fromEnd: 0
|
|
83351
|
-
});
|
|
83352
|
-
//#endregion
|
|
83353
|
-
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/cleanLastNewline.js
|
|
83354
|
-
function cleanLastNewline(contents) {
|
|
83355
|
-
let end = contents.length;
|
|
83356
|
-
if (contents.charCodeAt(end - 1) === 10) {
|
|
83357
|
-
end--;
|
|
83358
|
-
if (contents.charCodeAt(end - 1) === 13) end--;
|
|
83359
|
-
}
|
|
83360
|
-
return contents.slice(0, end);
|
|
83361
|
-
}
|
|
83362
|
-
//#endregion
|
|
83363
|
-
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/detachString.js
|
|
83364
|
-
const stringDetachEncoder = new TextEncoder();
|
|
83365
|
-
const stringDetachDecoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
83366
|
-
const SURROGATE_CODE_UNIT_PATTERN = /[\uD800-\uDFFF]/;
|
|
83367
|
-
const STRING_DETACH_INITIAL_BUFFER_SIZE = 1024;
|
|
83368
|
-
let stringDetachBuffer = new Uint8Array(STRING_DETACH_INITIAL_BUFFER_SIZE);
|
|
83369
|
-
function releaseStringDetachBuffer() {
|
|
83370
|
-
if (stringDetachBuffer.length !== STRING_DETACH_INITIAL_BUFFER_SIZE) stringDetachBuffer = new Uint8Array(STRING_DETACH_INITIAL_BUFFER_SIZE);
|
|
83371
|
-
}
|
|
83372
|
-
function detachString(value) {
|
|
83373
|
-
if (value.length === 0) return value;
|
|
83374
|
-
if (SURROGATE_CODE_UNIT_PATTERN.test(value)) return JSON.parse(JSON.stringify(value));
|
|
83375
|
-
const requiredByteLength = value.length * 3;
|
|
83376
|
-
if (stringDetachBuffer.length < requiredByteLength) stringDetachBuffer = new Uint8Array(requiredByteLength);
|
|
83377
|
-
const { written } = stringDetachEncoder.encodeInto(value, stringDetachBuffer);
|
|
83378
|
-
return stringDetachDecoder.decode(stringDetachBuffer.subarray(0, written));
|
|
83379
|
-
}
|
|
83380
|
-
//#endregion
|
|
83381
|
-
//#region ../../node_modules/.pnpm/@pierre+diffs@1.3.0-beta.5_patch_hash=7cb6da88544119adda056b2f46f43956f99326227732da0b3_3b51331382fbad9d080c5033ee1e2a6a/node_modules/@pierre/diffs/dist/utils/parsePatchFiles.js
|
|
83382
|
-
function processPatch(data, cacheKeyPrefix, throwOnError) {
|
|
83383
|
-
try {
|
|
83384
|
-
return _processPatch(data, cacheKeyPrefix, throwOnError);
|
|
83385
|
-
} finally {
|
|
83386
|
-
releaseStringDetachBuffer();
|
|
83387
|
-
}
|
|
83388
|
-
}
|
|
83389
|
-
function _processPatch(data, cacheKeyPrefix, throwOnError = false) {
|
|
83390
|
-
const isGitDiff = isGitDiffPatch(data);
|
|
83391
|
-
const rawFiles = isGitDiff ? splitGitDiffFiles(data) : splitUnifiedDiffFiles(data);
|
|
83392
|
-
let patchMetadata;
|
|
83393
|
-
const files = [];
|
|
83394
|
-
for (const fileOrPatchMetadata of rawFiles) {
|
|
83395
|
-
if (isGitDiff && !GIT_DIFF_FILE_BREAK_REGEX.test(fileOrPatchMetadata)) {
|
|
83396
|
-
if (patchMetadata == null) patchMetadata = detachString(fileOrPatchMetadata);
|
|
83397
|
-
else if (throwOnError) throw Error("parsePatchContent: unknown file blob");
|
|
83398
|
-
else console.error("parsePatchContent: unknown file blob:", fileOrPatchMetadata);
|
|
83399
|
-
continue;
|
|
83400
|
-
} else if (!isGitDiff && !startsWithUnifiedDiffFileHeader(fileOrPatchMetadata)) {
|
|
83401
|
-
if (patchMetadata == null) patchMetadata = detachString(fileOrPatchMetadata);
|
|
83402
|
-
else if (throwOnError) throw Error("parsePatchContent: unknown file blob");
|
|
83403
|
-
else console.error("parsePatchContent: unknown file blob:", fileOrPatchMetadata);
|
|
83404
|
-
continue;
|
|
83405
|
-
}
|
|
83406
|
-
const currentFile = _processFile(fileOrPatchMetadata, {
|
|
83407
|
-
cacheKey: cacheKeyPrefix != null ? `${cacheKeyPrefix}-${files.length}` : void 0,
|
|
83408
|
-
isGitDiff,
|
|
83409
|
-
throwOnError
|
|
83410
|
-
});
|
|
83411
|
-
if (currentFile != null) files.push(currentFile);
|
|
83412
|
-
}
|
|
83413
|
-
return {
|
|
83414
|
-
patchMetadata,
|
|
83415
|
-
files
|
|
83416
|
-
};
|
|
83417
|
-
}
|
|
83418
|
-
function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREAK_REGEX.test(fileDiffString), oldFile, newFile, throwOnError = false } = {}) {
|
|
83419
|
-
let lastHunkEnd = 0;
|
|
83420
|
-
const hunks = splitAtLinePrefix(fileDiffString, "@@ ");
|
|
83421
|
-
let currentFile;
|
|
83422
|
-
const isPartial = oldFile == null || newFile == null;
|
|
83423
|
-
let deletionLineIndex = 0;
|
|
83424
|
-
let additionLineIndex = 0;
|
|
83425
|
-
for (const hunk of hunks) {
|
|
83426
|
-
const lines = splitWithNewlines(hunk);
|
|
83427
|
-
const firstLine = lines[0];
|
|
83428
|
-
if (firstLine == null) {
|
|
83429
|
-
if (throwOnError) throw Error("parsePatchContent: invalid hunk");
|
|
83430
|
-
else console.error("parsePatchContent: invalid hunk", hunk);
|
|
83431
|
-
continue;
|
|
83432
|
-
}
|
|
83433
|
-
const fileHeader = parseHunkHeader(firstLine);
|
|
83434
|
-
let additionLines = 0;
|
|
83435
|
-
let deletionLines = 0;
|
|
83436
|
-
if (fileHeader == null || currentFile == null) {
|
|
83437
|
-
if (currentFile != null) {
|
|
83438
|
-
if (throwOnError) throw Error("parsePatchContent: Invalid hunk");
|
|
83439
|
-
else console.error("parsePatchContent: Invalid hunk", hunk);
|
|
83440
|
-
continue;
|
|
83441
|
-
}
|
|
83442
|
-
currentFile = {
|
|
83443
|
-
name: "",
|
|
83444
|
-
type: "change",
|
|
83445
|
-
hunks: [],
|
|
83446
|
-
splitLineCount: 0,
|
|
83447
|
-
unifiedLineCount: 0,
|
|
83448
|
-
isPartial,
|
|
83449
|
-
additionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(newFile.contents) : [],
|
|
83450
|
-
deletionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(oldFile.contents) : [],
|
|
83451
|
-
cacheKey: maybeDetachOptionalString(cacheKey)
|
|
83452
|
-
};
|
|
83453
|
-
if (currentFile.additionLines.length === 1 && newFile?.contents === "") currentFile.additionLines.length = 0;
|
|
83454
|
-
if (currentFile.deletionLines.length === 1 && oldFile?.contents === "") currentFile.deletionLines.length = 0;
|
|
83455
|
-
for (const line of lines) {
|
|
83456
|
-
if (line.startsWith("diff --git")) {
|
|
83457
|
-
const filenameMatch$1 = line.trim().match(ALTERNATE_FILE_NAMES_GIT);
|
|
83458
|
-
const prevName = filenameMatch$1?.[1] ?? filenameMatch$1?.[2];
|
|
83459
|
-
const name = filenameMatch$1?.[3] ?? filenameMatch$1?.[4];
|
|
83460
|
-
if (prevName == null || name == null) {
|
|
83461
|
-
if (throwOnError) throw Error("parsePatchContent: invalid git diff header");
|
|
83462
|
-
else console.error("parsePatchContent: invalid git diff header", line);
|
|
83463
|
-
continue;
|
|
83464
|
-
}
|
|
83465
|
-
currentFile.name = detachString(name.trim());
|
|
83466
|
-
if (prevName !== name) currentFile.prevName = detachString(prevName.trim());
|
|
83467
|
-
continue;
|
|
83468
|
-
}
|
|
83469
|
-
const filenameMatch = line.startsWith("---") || line.startsWith("+++") ? line.match(isGitDiff ? FILENAME_HEADER_REGEX_GIT : FILENAME_HEADER_REGEX) : null;
|
|
83470
|
-
if (filenameMatch != null) {
|
|
83471
|
-
const [, type, fileName] = filenameMatch;
|
|
83472
|
-
if (type === "---" && fileName !== "/dev/null") {
|
|
83473
|
-
const detachedFileName = detachString(fileName.trim());
|
|
83474
|
-
currentFile.prevName = detachedFileName;
|
|
83475
|
-
currentFile.name = detachedFileName;
|
|
83476
|
-
} else if (type === "+++" && fileName !== "/dev/null") currentFile.name = detachString(fileName.trim());
|
|
83477
|
-
} else if (isGitDiff) {
|
|
83478
|
-
if (line.startsWith("new mode ")) currentFile.mode = detachString(line.slice(8).trim());
|
|
83479
|
-
if (line.startsWith("old mode ")) currentFile.prevMode = detachString(line.slice(8).trim());
|
|
83480
|
-
if (line.startsWith("new file mode")) {
|
|
83481
|
-
currentFile.type = "new";
|
|
83482
|
-
currentFile.mode = detachString(line.slice(13).trim());
|
|
83483
|
-
}
|
|
83484
|
-
if (line.startsWith("deleted file mode")) {
|
|
83485
|
-
currentFile.type = "deleted";
|
|
83486
|
-
currentFile.mode = detachString(line.slice(17).trim());
|
|
83487
|
-
}
|
|
83488
|
-
if (line.startsWith("similarity index")) if (line.startsWith("similarity index 100%")) currentFile.type = "rename-pure";
|
|
83489
|
-
else currentFile.type = "rename-changed";
|
|
83490
|
-
if (line.startsWith("index ")) {
|
|
83491
|
-
const [, prevObjectId, newObjectId, mode] = line.trim().match(INDEX_LINE_METADATA) ?? [];
|
|
83492
|
-
if (prevObjectId != null) currentFile.prevObjectId = detachString(prevObjectId);
|
|
83493
|
-
if (newObjectId != null) currentFile.newObjectId = detachString(newObjectId);
|
|
83494
|
-
if (mode != null) currentFile.mode = detachString(mode);
|
|
83495
|
-
}
|
|
83496
|
-
if (line.startsWith("rename from ")) currentFile.prevName = detachString(line.slice(12).trim());
|
|
83497
|
-
if (line.startsWith("rename to ")) currentFile.name = detachString(line.slice(10).trim());
|
|
83498
|
-
}
|
|
83499
|
-
}
|
|
83500
|
-
continue;
|
|
83501
|
-
}
|
|
83502
|
-
let currentContent;
|
|
83503
|
-
let lastLineType;
|
|
83504
|
-
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();
|
|
83505
|
-
const { additionStart, deletionStart } = fileHeader;
|
|
83506
|
-
deletionLineIndex = isPartial ? deletionLineIndex : deletionStart - 1;
|
|
83507
|
-
additionLineIndex = isPartial ? additionLineIndex : additionStart - 1;
|
|
83508
|
-
const hunkData = {
|
|
83509
|
-
collapsedBefore: 0,
|
|
83510
|
-
splitLineCount: 0,
|
|
83511
|
-
splitLineStart: 0,
|
|
83512
|
-
unifiedLineCount: 0,
|
|
83513
|
-
unifiedLineStart: 0,
|
|
83514
|
-
additionCount: fileHeader.additionCount,
|
|
83515
|
-
additionStart,
|
|
83516
|
-
additionLines,
|
|
83517
|
-
deletionCount: fileHeader.deletionCount,
|
|
83518
|
-
deletionStart,
|
|
83519
|
-
deletionLines,
|
|
83520
|
-
deletionLineIndex,
|
|
83521
|
-
additionLineIndex,
|
|
83522
|
-
hunkContent: [],
|
|
83523
|
-
hunkContext: maybeDetachOptionalString(fileHeader.hunkContext),
|
|
83524
|
-
hunkSpecs: detachString(firstLine),
|
|
83525
|
-
noEOFCRAdditions: false,
|
|
83526
|
-
noEOFCRDeletions: false
|
|
83527
|
-
};
|
|
83528
|
-
let parsedAdditionLines = 0;
|
|
83529
|
-
let parsedDeletionLines = 0;
|
|
83530
|
-
for (let lineIndex = 1; lineIndex < lines.length; lineIndex++) {
|
|
83531
|
-
const rawLine = lines[lineIndex];
|
|
83532
|
-
if (parsedAdditionLines >= hunkData.additionCount && parsedDeletionLines >= hunkData.deletionCount && !rawLine.startsWith("\\")) {
|
|
83533
|
-
if (throwOnError && isHunkBodyLine(rawLine) && !isFormatPatchVersionSeparator(rawLine)) throw Error("parsePatchContent: hunk has more lines than expected");
|
|
83534
|
-
break;
|
|
83535
|
-
}
|
|
83536
|
-
const firstChar = rawLine[0];
|
|
83537
|
-
if (firstChar !== "+" && firstChar !== "-" && firstChar !== " " && firstChar !== "\\") {
|
|
83538
|
-
if (throwOnError) throw Error("parsePatchContent: invalid hunk line");
|
|
83539
|
-
console.error(`parseLineType: Invalid firstChar: "${firstChar}", full line: "${rawLine}"`);
|
|
83540
|
-
console.error("processFile: invalid rawLine:", rawLine);
|
|
83541
|
-
continue;
|
|
83542
|
-
}
|
|
83543
|
-
const type = parseRawLineType(firstChar);
|
|
83544
|
-
if (type === "addition") {
|
|
83545
|
-
if (throwOnError && parsedAdditionLines >= hunkData.additionCount) throw Error("parsePatchContent: hunk has too many addition lines");
|
|
83546
|
-
const line = getParsedLineContent(rawLine);
|
|
83547
|
-
if (currentContent == null || currentContent.type !== "change") {
|
|
83548
|
-
currentContent = createContentGroup("change", deletionLineIndex, additionLineIndex);
|
|
83549
|
-
hunkData.hunkContent.push(currentContent);
|
|
83550
|
-
}
|
|
83551
|
-
additionLineIndex++;
|
|
83552
|
-
parsedAdditionLines++;
|
|
83553
|
-
if (isPartial) currentFile.additionLines.push(line);
|
|
83554
|
-
currentContent.additions++;
|
|
83555
|
-
additionLines++;
|
|
83556
|
-
lastLineType = "addition";
|
|
83557
|
-
} else if (type === "deletion") {
|
|
83558
|
-
if (throwOnError && parsedDeletionLines >= hunkData.deletionCount) throw Error("parsePatchContent: hunk has too many deletion lines");
|
|
83559
|
-
const line = getParsedLineContent(rawLine);
|
|
83560
|
-
if (currentContent == null || currentContent.type !== "change") {
|
|
83561
|
-
currentContent = createContentGroup("change", deletionLineIndex, additionLineIndex);
|
|
83562
|
-
hunkData.hunkContent.push(currentContent);
|
|
83563
|
-
}
|
|
83564
|
-
deletionLineIndex++;
|
|
83565
|
-
parsedDeletionLines++;
|
|
83566
|
-
if (isPartial) currentFile.deletionLines.push(line);
|
|
83567
|
-
currentContent.deletions++;
|
|
83568
|
-
deletionLines++;
|
|
83569
|
-
lastLineType = "deletion";
|
|
83570
|
-
} else if (type === "context") {
|
|
83571
|
-
if (throwOnError && (parsedDeletionLines >= hunkData.deletionCount || parsedAdditionLines >= hunkData.additionCount)) throw Error("parsePatchContent: hunk has too many context lines");
|
|
83572
|
-
const line = getParsedLineContent(rawLine);
|
|
83573
|
-
if (currentContent == null || currentContent.type !== "context") {
|
|
83574
|
-
currentContent = createContentGroup("context", deletionLineIndex, additionLineIndex);
|
|
83575
|
-
hunkData.hunkContent.push(currentContent);
|
|
83576
|
-
}
|
|
83577
|
-
additionLineIndex++;
|
|
83578
|
-
deletionLineIndex++;
|
|
83579
|
-
parsedAdditionLines++;
|
|
83580
|
-
parsedDeletionLines++;
|
|
83581
|
-
if (isPartial) {
|
|
83582
|
-
currentFile.deletionLines.push(line);
|
|
83583
|
-
currentFile.additionLines.push(line);
|
|
83584
|
-
}
|
|
83585
|
-
currentContent.lines++;
|
|
83586
|
-
lastLineType = "context";
|
|
83587
|
-
} else if (type === "metadata" && currentContent != null) {
|
|
83588
|
-
if (currentContent.type === "context") {
|
|
83589
|
-
hunkData.noEOFCRAdditions = true;
|
|
83590
|
-
hunkData.noEOFCRDeletions = true;
|
|
83591
|
-
} else if (lastLineType === "deletion") hunkData.noEOFCRDeletions = true;
|
|
83592
|
-
else if (lastLineType === "addition") hunkData.noEOFCRAdditions = true;
|
|
83593
|
-
if (isPartial && (lastLineType === "addition" || lastLineType === "context")) {
|
|
83594
|
-
const lastIndex = currentFile.additionLines.length - 1;
|
|
83595
|
-
if (lastIndex >= 0) currentFile.additionLines[lastIndex] = cleanLastNewline(currentFile.additionLines[lastIndex]);
|
|
83596
|
-
}
|
|
83597
|
-
if (isPartial && (lastLineType === "deletion" || lastLineType === "context")) {
|
|
83598
|
-
const lastIndex = currentFile.deletionLines.length - 1;
|
|
83599
|
-
if (lastIndex >= 0) currentFile.deletionLines[lastIndex] = cleanLastNewline(currentFile.deletionLines[lastIndex]);
|
|
83600
|
-
}
|
|
83601
|
-
}
|
|
83602
|
-
}
|
|
83603
|
-
if (throwOnError && (parsedAdditionLines !== hunkData.additionCount || parsedDeletionLines !== hunkData.deletionCount)) throw Error("parsePatchContent: hunk line count mismatch");
|
|
83604
|
-
hunkData.additionLines = additionLines;
|
|
83605
|
-
hunkData.deletionLines = deletionLines;
|
|
83606
|
-
hunkData.collapsedBefore = Math.max(hunkData.additionStart - 1 - lastHunkEnd, 0);
|
|
83607
|
-
currentFile.hunks.push(hunkData);
|
|
83608
|
-
lastHunkEnd = hunkData.additionStart + hunkData.additionCount - 1;
|
|
83609
|
-
for (const content of hunkData.hunkContent) if (content.type === "context") {
|
|
83610
|
-
hunkData.splitLineCount += content.lines;
|
|
83611
|
-
hunkData.unifiedLineCount += content.lines;
|
|
83612
|
-
} else {
|
|
83613
|
-
hunkData.splitLineCount += Math.max(content.additions, content.deletions);
|
|
83614
|
-
hunkData.unifiedLineCount += content.deletions + content.additions;
|
|
83615
|
-
}
|
|
83616
|
-
hunkData.splitLineStart = currentFile.splitLineCount + hunkData.collapsedBefore;
|
|
83617
|
-
hunkData.unifiedLineStart = currentFile.unifiedLineCount + hunkData.collapsedBefore;
|
|
83618
|
-
currentFile.splitLineCount += hunkData.collapsedBefore + hunkData.splitLineCount;
|
|
83619
|
-
currentFile.unifiedLineCount += hunkData.collapsedBefore + hunkData.unifiedLineCount;
|
|
83620
|
-
}
|
|
83621
|
-
if (currentFile == null) return;
|
|
83622
|
-
if (throwOnError && isPartial && !isGitDiff && currentFile.hunks.length === 0) throw Error("parsePatchContent: unified file has no hunks");
|
|
83623
|
-
if (currentFile.hunks.length > 0 && !isPartial && currentFile.additionLines.length > 0 && currentFile.deletionLines.length > 0) {
|
|
83624
|
-
const lastHunk = currentFile.hunks[currentFile.hunks.length - 1];
|
|
83625
|
-
const lastHunkEnd$1 = lastHunk.additionStart + lastHunk.additionCount - 1;
|
|
83626
|
-
const totalFileLines = currentFile.additionLines.length;
|
|
83627
|
-
const collapsedAfter = Math.max(totalFileLines - lastHunkEnd$1, 0);
|
|
83628
|
-
currentFile.splitLineCount += collapsedAfter;
|
|
83629
|
-
currentFile.unifiedLineCount += collapsedAfter;
|
|
83630
|
-
}
|
|
83631
|
-
if (!isGitDiff) {
|
|
83632
|
-
if (currentFile.prevName != null && currentFile.name !== currentFile.prevName) if (currentFile.hunks.length > 0) currentFile.type = "rename-changed";
|
|
83633
|
-
else currentFile.type = "rename-pure";
|
|
83634
|
-
else if ((oldFile == null || oldFile.contents === "") && newFile != null && newFile.contents !== "") currentFile.type = "new";
|
|
83635
|
-
else if (oldFile != null && oldFile.contents !== "" && (newFile == null || newFile.contents === "")) currentFile.type = "deleted";
|
|
83636
|
-
}
|
|
83637
|
-
if (currentFile.type !== "rename-pure" && currentFile.type !== "rename-changed") currentFile.prevName = void 0;
|
|
83638
|
-
return currentFile;
|
|
83639
|
-
}
|
|
83640
|
-
/**
|
|
83641
|
-
* Parses a patch file string into an array of parsed patches.
|
|
83642
|
-
*
|
|
83643
|
-
* @param data - The raw patch file content (supports multi-commit patches)
|
|
83644
|
-
* @param cacheKeyPrefix - Optional prefix for generating cache keys. When provided,
|
|
83645
|
-
* each file in the patch will get a cache key in the format `prefix-patchIndex-fileIndex`.
|
|
83646
|
-
* This enables caching of rendered diff results in the worker pool.
|
|
83647
|
-
*/
|
|
83648
|
-
function parsePatchFiles(data, cacheKeyPrefix, throwOnError = false) {
|
|
83649
|
-
const patches = [];
|
|
83650
|
-
const rawPatches = hasCommitMetadataBoundary(data) ? data.split(COMMIT_METADATA_SPLIT) : [data];
|
|
83651
|
-
for (const patch of rawPatches) try {
|
|
83652
|
-
patches.push(processPatch(patch, cacheKeyPrefix != null ? `${cacheKeyPrefix}-${patches.length}` : void 0, throwOnError));
|
|
83653
|
-
} catch (error) {
|
|
83654
|
-
if (throwOnError) throw error;
|
|
83655
|
-
else console.error(error);
|
|
83656
|
-
}
|
|
83657
|
-
return patches;
|
|
83658
|
-
}
|
|
83659
|
-
function hasCommitMetadataBoundary(data) {
|
|
83660
|
-
return data.startsWith("From ") || data.includes("\nFrom ");
|
|
83661
|
-
}
|
|
83662
|
-
function splitFileContents(contents) {
|
|
83663
|
-
const lines = splitWithNewlines(contents);
|
|
83664
|
-
for (let index = 0; index < lines.length; index++) lines[index] = detachString(lines[index]);
|
|
83665
|
-
return lines;
|
|
83666
|
-
}
|
|
83667
|
-
function splitWithNewlines(contents) {
|
|
83668
|
-
if (contents.length === 0) return [""];
|
|
83669
|
-
const lines = [];
|
|
83670
|
-
let startIndex = 0;
|
|
83671
|
-
for (;;) {
|
|
83672
|
-
const newlineIndex = contents.indexOf("\n", startIndex);
|
|
83673
|
-
if (newlineIndex === -1) break;
|
|
83674
|
-
lines.push(contents.slice(startIndex, newlineIndex + 1));
|
|
83675
|
-
startIndex = newlineIndex + 1;
|
|
83676
|
-
}
|
|
83677
|
-
if (startIndex < contents.length) lines.push(contents.slice(startIndex));
|
|
83678
|
-
return lines;
|
|
83679
|
-
}
|
|
83680
|
-
function splitGitDiffFiles(contents) {
|
|
83681
|
-
return splitAtLinePrefix(contents, "diff --git");
|
|
83682
|
-
}
|
|
83683
|
-
function splitUnifiedDiffFiles(contents) {
|
|
83684
|
-
if (contents.length === 0) return [""];
|
|
83685
|
-
const parts = [];
|
|
83686
|
-
let partStartIndex = 0;
|
|
83687
|
-
let lineStartIndex = 0;
|
|
83688
|
-
let remainingDeletionLines = 0;
|
|
83689
|
-
let remainingAdditionLines = 0;
|
|
83690
|
-
let hasOpenedUnifiedFile = false;
|
|
83691
|
-
while (lineStartIndex < contents.length) {
|
|
83692
|
-
const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);
|
|
83693
|
-
if (remainingDeletionLines <= 0 && remainingAdditionLines <= 0) {
|
|
83694
|
-
if (isUnifiedDiffFileHeaderAt(contents, lineStartIndex)) {
|
|
83695
|
-
if (lineStartIndex > partStartIndex) parts.push(contents.slice(partStartIndex, lineStartIndex));
|
|
83696
|
-
partStartIndex = lineStartIndex;
|
|
83697
|
-
hasOpenedUnifiedFile = true;
|
|
83698
|
-
lineStartIndex = getNextLineStartIndex(contents, nextLineStartIndex);
|
|
83699
|
-
continue;
|
|
83700
|
-
}
|
|
83701
|
-
if (hasOpenedUnifiedFile && contents.startsWith("@@ -", lineStartIndex)) {
|
|
83702
|
-
const fileHeader = parseHunkHeader(contents.slice(lineStartIndex, nextLineStartIndex));
|
|
83703
|
-
if (fileHeader != null) {
|
|
83704
|
-
remainingDeletionLines = fileHeader.deletionCount;
|
|
83705
|
-
remainingAdditionLines = fileHeader.additionCount;
|
|
83706
|
-
}
|
|
83707
|
-
}
|
|
83708
|
-
lineStartIndex = nextLineStartIndex;
|
|
83709
|
-
continue;
|
|
83710
|
-
}
|
|
83711
|
-
const firstChar = contents[lineStartIndex];
|
|
83712
|
-
if (firstChar === "\\") {
|
|
83713
|
-
lineStartIndex = nextLineStartIndex;
|
|
83714
|
-
continue;
|
|
83715
|
-
}
|
|
83716
|
-
if (firstChar === " ") {
|
|
83717
|
-
remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);
|
|
83718
|
-
remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);
|
|
83719
|
-
} else if (firstChar === "-") remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);
|
|
83720
|
-
else if (firstChar === "+") remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);
|
|
83721
|
-
lineStartIndex = nextLineStartIndex;
|
|
83722
|
-
}
|
|
83723
|
-
parts.push(contents.slice(partStartIndex));
|
|
83724
|
-
return parts;
|
|
83725
|
-
}
|
|
83726
|
-
function startsWithUnifiedDiffFileHeader(contents) {
|
|
83727
|
-
return isUnifiedDiffFileHeaderAt(contents, 0);
|
|
83728
|
-
}
|
|
83729
|
-
function isUnifiedDiffFileHeaderAt(contents, lineStartIndex) {
|
|
83730
|
-
const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);
|
|
83731
|
-
return isUnifiedDiffHeaderLineAt(contents, lineStartIndex, "---") && isUnifiedDiffHeaderLineAt(contents, nextLineStartIndex, "+++");
|
|
83732
|
-
}
|
|
83733
|
-
function isUnifiedDiffHeaderLineAt(contents, lineStartIndex, prefix) {
|
|
83734
|
-
if (!contents.startsWith(prefix, lineStartIndex)) return false;
|
|
83735
|
-
const separator = contents[lineStartIndex + prefix.length];
|
|
83736
|
-
if (separator !== " " && separator !== " ") return false;
|
|
83737
|
-
for (let index = lineStartIndex + prefix.length + 1; index < contents.length; index++) {
|
|
83738
|
-
const char = contents[index];
|
|
83739
|
-
if (char === "\n" || char === "\r") break;
|
|
83740
|
-
if (char !== " " && char !== " ") return true;
|
|
83741
|
-
}
|
|
83742
|
-
return false;
|
|
83743
|
-
}
|
|
83744
|
-
function getNextLineStartIndex(contents, lineStartIndex) {
|
|
83745
|
-
const newlineIndex = contents.indexOf("\n", lineStartIndex);
|
|
83746
|
-
return newlineIndex === -1 ? contents.length : newlineIndex + 1;
|
|
83747
|
-
}
|
|
83748
|
-
function isHunkBodyLine(line) {
|
|
83749
|
-
const firstChar = line[0];
|
|
83750
|
-
return firstChar === "+" || firstChar === "-" || firstChar === " ";
|
|
83751
|
-
}
|
|
83752
|
-
function isFormatPatchVersionSeparator(line) {
|
|
83753
|
-
if (!line.startsWith("--")) return false;
|
|
83754
|
-
for (let index = 2; index < line.length; index++) {
|
|
83755
|
-
const char = line[index];
|
|
83756
|
-
if (char !== " " && char !== " " && char !== "\n" && char !== "\r") return false;
|
|
83757
|
-
}
|
|
83758
|
-
return true;
|
|
83759
|
-
}
|
|
83760
|
-
function parseHunkHeader(line) {
|
|
83761
|
-
if (!line.startsWith("@@ -")) return;
|
|
83762
|
-
let index = 4;
|
|
83763
|
-
const deletionStartResult = readPositiveInteger(line, index);
|
|
83764
|
-
if (deletionStartResult == null) return;
|
|
83765
|
-
const deletionStart = deletionStartResult.value;
|
|
83766
|
-
index = deletionStartResult.endIndex;
|
|
83767
|
-
let deletionCount = 1;
|
|
83768
|
-
if (line[index] === ",") {
|
|
83769
|
-
const deletionCountResult = readPositiveInteger(line, index + 1);
|
|
83770
|
-
if (deletionCountResult == null) return;
|
|
83771
|
-
deletionCount = deletionCountResult.value;
|
|
83772
|
-
index = deletionCountResult.endIndex;
|
|
83773
|
-
}
|
|
83774
|
-
if (line[index] !== " " || line[index + 1] !== "+") return;
|
|
83775
|
-
index += 2;
|
|
83776
|
-
const additionStartResult = readPositiveInteger(line, index);
|
|
83777
|
-
if (additionStartResult == null) return;
|
|
83778
|
-
const additionStart = additionStartResult.value;
|
|
83779
|
-
index = additionStartResult.endIndex;
|
|
83780
|
-
let additionCount = 1;
|
|
83781
|
-
if (line[index] === ",") {
|
|
83782
|
-
const additionCountResult = readPositiveInteger(line, index + 1);
|
|
83783
|
-
if (additionCountResult == null) return;
|
|
83784
|
-
additionCount = additionCountResult.value;
|
|
83785
|
-
index = additionCountResult.endIndex;
|
|
83786
|
-
}
|
|
83787
|
-
if (line[index] !== " " || line[index + 1] !== "@" || line[index + 2] !== "@") return;
|
|
83788
|
-
let hunkContext;
|
|
83789
|
-
const contextStartIndex = index + 3;
|
|
83790
|
-
if (line[contextStartIndex] === " ") hunkContext = trimLineEnd(line.slice(contextStartIndex + 1));
|
|
83791
|
-
return {
|
|
83792
|
-
additionCount,
|
|
83793
|
-
additionStart,
|
|
83794
|
-
deletionCount,
|
|
83795
|
-
deletionStart,
|
|
83796
|
-
hunkContext
|
|
83797
|
-
};
|
|
83798
|
-
}
|
|
83799
|
-
function readPositiveInteger(value, startIndex) {
|
|
83800
|
-
let index = startIndex;
|
|
83801
|
-
let parsedValue = 0;
|
|
83802
|
-
for (; index < value.length; index++) {
|
|
83803
|
-
const digit = value.charCodeAt(index) - 48;
|
|
83804
|
-
if (digit < 0 || digit > 9) break;
|
|
83805
|
-
parsedValue = parsedValue * 10 + digit;
|
|
83806
|
-
}
|
|
83807
|
-
if (index === startIndex) return;
|
|
83808
|
-
return {
|
|
83809
|
-
value: parsedValue,
|
|
83810
|
-
endIndex: index
|
|
83811
|
-
};
|
|
83812
|
-
}
|
|
83813
|
-
function trimLineEnd(value) {
|
|
83814
|
-
if (value.endsWith("\r\n")) return value.slice(0, -2);
|
|
83815
|
-
if (value.endsWith("\n")) return value.slice(0, -1);
|
|
83816
|
-
return value;
|
|
83817
|
-
}
|
|
83818
|
-
function isGitDiffPatch(data) {
|
|
83819
|
-
return data.startsWith("diff --git") || data.includes("\ndiff --git");
|
|
83820
|
-
}
|
|
83821
|
-
function splitAtLinePrefix(contents, prefix) {
|
|
83822
|
-
if (contents.length === 0) return [""];
|
|
83823
|
-
const newlinePrefix = `\n${prefix}`;
|
|
83824
|
-
const firstBoundaryIndex = contents.startsWith(prefix) ? 0 : findLinePrefixIndex(contents, newlinePrefix, 0);
|
|
83825
|
-
if (firstBoundaryIndex === -1) return [contents];
|
|
83826
|
-
const parts = [];
|
|
83827
|
-
if (firstBoundaryIndex > 0) parts.push(contents.slice(0, firstBoundaryIndex));
|
|
83828
|
-
let startIndex = firstBoundaryIndex;
|
|
83829
|
-
for (;;) {
|
|
83830
|
-
const nextBoundaryIndex = findLinePrefixIndex(contents, newlinePrefix, startIndex + 1);
|
|
83831
|
-
if (nextBoundaryIndex === -1) break;
|
|
83832
|
-
parts.push(contents.slice(startIndex, nextBoundaryIndex));
|
|
83833
|
-
startIndex = nextBoundaryIndex;
|
|
83834
|
-
}
|
|
83835
|
-
parts.push(contents.slice(startIndex));
|
|
83836
|
-
return parts;
|
|
83837
|
-
}
|
|
83838
|
-
function findLinePrefixIndex(contents, newlinePrefix, fromIndex) {
|
|
83839
|
-
const index = contents.indexOf(newlinePrefix, fromIndex);
|
|
83840
|
-
return index === -1 ? -1 : index + 1;
|
|
83841
|
-
}
|
|
83842
|
-
function maybeDetachOptionalString(value) {
|
|
83843
|
-
return value == null ? value : detachString(value);
|
|
83844
|
-
}
|
|
83845
|
-
function parseRawLineType(firstChar) {
|
|
83846
|
-
return firstChar === " " ? "context" : firstChar === "\\" ? "metadata" : firstChar === "+" ? "addition" : "deletion";
|
|
83847
|
-
}
|
|
83848
|
-
function getParsedLineContent(rawLine) {
|
|
83849
|
-
const processedLine = rawLine.slice(1);
|
|
83850
|
-
return detachString(processedLine === "" ? "\n" : processedLine);
|
|
83851
|
-
}
|
|
83852
|
-
function createContentGroup(type, deletionLineIndex, additionLineIndex) {
|
|
83853
|
-
if (type === "change") return {
|
|
83854
|
-
type: "change",
|
|
83855
|
-
additions: 0,
|
|
83856
|
-
deletions: 0,
|
|
83857
|
-
additionLineIndex,
|
|
83858
|
-
deletionLineIndex
|
|
83859
|
-
};
|
|
83860
|
-
return {
|
|
83861
|
-
type: "context",
|
|
83862
|
-
lines: 0,
|
|
83863
|
-
additionLineIndex,
|
|
83864
|
-
deletionLineIndex
|
|
83865
|
-
};
|
|
83866
|
-
}
|
|
83867
84075
|
//#endregion
|
|
83868
84076
|
//#region src/checkpointing/Diffs.ts
|
|
83869
84077
|
function parseTurnDiffFilesFromUnifiedDiff(diff) {
|
|
@@ -83904,6 +84112,7 @@ const make$1 = Effect.gen(function* () {
|
|
|
83904
84112
|
const receiptBus = yield* RuntimeReceiptBus;
|
|
83905
84113
|
const workspaceEntries = yield* WorkspaceEntries;
|
|
83906
84114
|
const vcsStatusBroadcaster = yield* VcsStatusBroadcaster;
|
|
84115
|
+
const threadActivities = yield* ProjectionThreadActivityRepository;
|
|
83907
84116
|
const appendRevertFailureActivity = (input) => Effect.all({
|
|
83908
84117
|
commandId: serverCommandId("checkpoint-revert-failure"),
|
|
83909
84118
|
activityId: serverEventId
|
|
@@ -83992,13 +84201,21 @@ const make$1 = Effect.gen(function* () {
|
|
|
83992
84201
|
checkpointRef: targetCheckpointRef
|
|
83993
84202
|
});
|
|
83994
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()));
|
|
83995
84212
|
const files = yield* checkpointStore.diffCheckpoints({
|
|
83996
84213
|
cwd: input.cwd,
|
|
83997
84214
|
fromCheckpointRef,
|
|
83998
84215
|
toCheckpointRef: targetCheckpointRef,
|
|
83999
84216
|
fallbackFromToHead: false,
|
|
84000
84217
|
ignoreWhitespace: false
|
|
84001
|
-
}).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) => ({
|
|
84002
84219
|
path: file.path,
|
|
84003
84220
|
kind: "modified",
|
|
84004
84221
|
additions: file.additions,
|