@davideasden/pi-undo 0.2.21 → 0.2.24
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/README.md +2 -2
- package/package.json +1 -1
- package/src/controller.ts +3 -1
- package/src/pi-runtime.ts +30 -2
package/README.md
CHANGED
|
@@ -314,7 +314,7 @@ Install the [Rust toolchain](https://rustup.rs/) before building or updating a n
|
|
|
314
314
|
npm run build:native
|
|
315
315
|
```
|
|
316
316
|
|
|
317
|
-
`npm run build:native` creates `pi-undo-fs` for the current build platform under `native/pi-undo-fs/target/release/`. The
|
|
317
|
+
`npm run build:native` creates `pi-undo-fs` for the current build platform under `native/pi-undo-fs/target/release/`. The `Native binaries` workflow builds arm64 and x64 versions on macOS, Linux, and Windows runners, verifies the full six-binary matrix, and uploads them as workflow artifacts. The `Publish to npm` workflow publishes the package when a `v*` tag is pushed, using the binaries committed under `native/bin/`.
|
|
318
318
|
|
|
319
319
|
For local development on the current platform, copy the generated file into `native/bin/` and rename it for the platform. For example, a Windows build must use the corresponding `.exe` filename.
|
|
320
320
|
|
|
@@ -323,7 +323,7 @@ cp native/pi-undo-fs/target/release/pi-undo-fs native/bin/pi-undo-fs-darwin-arm6
|
|
|
323
323
|
chmod +x native/bin/pi-undo-fs-darwin-arm64
|
|
324
324
|
```
|
|
325
325
|
|
|
326
|
-
|
|
326
|
+
Every precompiled binary listed under Requirements must be committed under `native/bin/` to be part of a release. The `Native binaries` workflow verifies the complete six-binary matrix before uploading artifacts, and the `Publish to npm` workflow publishes the package on a `v*` tag push. The npm package must configure Trusted Publishing (OIDC) for the `Publish to npm` workflow. If no binary is available for the current platform, the extension automatically uses the TypeScript fallback.
|
|
327
327
|
|
|
328
328
|
### Project Layout
|
|
329
329
|
|
package/package.json
CHANGED
package/src/controller.ts
CHANGED
|
@@ -452,7 +452,9 @@ export class UndoControllerImpl implements UndoController {
|
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
async beforeTree(event: SessionBeforeTreeEvent): Promise<SessionBeforeTreeResult | undefined> {
|
|
455
|
-
|
|
455
|
+
// Pi 0.86+ 在树导航期间也会让 isIdle() 暂时返回 false;只有 pi-undo
|
|
456
|
+
// 已经记录了尚未 settle 的 run 时,才需要中止并取消导航。
|
|
457
|
+
if (this.staged !== undefined) {
|
|
456
458
|
await this.dependencies.abortAgent();
|
|
457
459
|
return { cancel: true };
|
|
458
460
|
}
|
package/src/pi-runtime.ts
CHANGED
|
@@ -285,7 +285,13 @@ function rebuildControllerState(
|
|
|
285
285
|
identity: SessionFileIdentity,
|
|
286
286
|
): ControllerInitialState {
|
|
287
287
|
const state = sessionStateFor(manager);
|
|
288
|
-
const
|
|
288
|
+
const branch = physicalBranch(manager, manager.getLeafId());
|
|
289
|
+
const checkpoints = checkpointFrontierAfterDetachedRun(
|
|
290
|
+
manager,
|
|
291
|
+
identity,
|
|
292
|
+
branch,
|
|
293
|
+
state.getCheckpoints(identity),
|
|
294
|
+
);
|
|
289
295
|
const cursor = state.getCursor(identity);
|
|
290
296
|
let undoStack = [...checkpoints];
|
|
291
297
|
if (cursor !== null) {
|
|
@@ -305,12 +311,34 @@ function rebuildControllerState(
|
|
|
305
311
|
if (sourceCursor === undefined) throw new Error("cursor redo safety manifest 缺失");
|
|
306
312
|
return { checkpoint, targetManifestId: sourceCursor.rollbackManifestId };
|
|
307
313
|
});
|
|
308
|
-
const branch = physicalBranch(manager, manager.getLeafId());
|
|
309
314
|
const lastBarrier = findLastIndex(branch, (entry) => entry.type === "custom" && entry.customType === "pi-undo:barrier");
|
|
310
315
|
const lastCheckpoint = findLastIndex(branch, (entry) => entry.type === "custom" && entry.customType === "pi-undo:checkpoint");
|
|
311
316
|
return { undoStack, redoStack, historyPaused: lastBarrier > lastCheckpoint };
|
|
312
317
|
}
|
|
313
318
|
|
|
319
|
+
/**
|
|
320
|
+
* redo 或树导航后的新 run 会挂在 cursor 后面,使前一个 checkpoint 脱离当前物理 branch。
|
|
321
|
+
* start entry 保存了 run 前的逻辑叶,利用它恢复可信的 checkpoint frontier,再接上当前 branch。
|
|
322
|
+
*/
|
|
323
|
+
function checkpointFrontierAfterDetachedRun(
|
|
324
|
+
manager: ReadonlySessionManager,
|
|
325
|
+
identity: SessionFileIdentity,
|
|
326
|
+
branch: readonly Record<string, unknown>[],
|
|
327
|
+
current: readonly CheckpointRecord[],
|
|
328
|
+
): CheckpointRecord[] {
|
|
329
|
+
const start = [...branch].reverse().find((entry) => entry.type === "custom" && entry.customType === "pi-undo:start");
|
|
330
|
+
if (start === undefined || !isRecord(start.data)) return [...current];
|
|
331
|
+
const sourceLogicalLeaf = start.data.sourceLogicalLeaf;
|
|
332
|
+
if (typeof sourceLogicalLeaf !== "string") return [...current];
|
|
333
|
+
const sourceCheckpoint = findCheckpointByEndLeaf(manager, identity, sourceLogicalLeaf);
|
|
334
|
+
if (sourceCheckpoint === undefined) return [...current];
|
|
335
|
+
const inherited = checkpointFrontierById(manager, identity, sourceCheckpoint.checkpointId);
|
|
336
|
+
return [
|
|
337
|
+
...inherited,
|
|
338
|
+
...current.filter((checkpoint) => !inherited.some((candidate) => candidate.checkpointId === checkpoint.checkpointId)),
|
|
339
|
+
].filter((checkpoint, index, all) => all.findIndex((candidate) => candidate.checkpointId === checkpoint.checkpointId) === index);
|
|
340
|
+
}
|
|
341
|
+
|
|
314
342
|
function checkpointFrontierById(
|
|
315
343
|
manager: ReadonlySessionManager,
|
|
316
344
|
identity: SessionFileIdentity,
|