pi-posthorse 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/package.json +1 -1
- package/src/history-entries.ts +9 -6
- package/src/history-search.ts +2 -2
- package/src/history.ts +17 -11
- package/src/session-files.ts +7 -2
package/README.md
CHANGED
|
@@ -17,12 +17,12 @@ Required qualification targets: latest stable official Pi and latest maintained
|
|
|
17
17
|
|
|
18
18
|
## Install
|
|
19
19
|
|
|
20
|
-
Posthorse `0.8.
|
|
20
|
+
Posthorse `0.8.2` requires Pi `>=1.0.0`. Update the host before installing this release; do not activate it on an older live fork.
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
pi install npm:pi-posthorse@0.8.
|
|
24
|
-
pi install git:github.com/fitchmultz/pi-posthorse@v0.8.
|
|
25
|
-
pi -e npm:pi-posthorse@0.8.
|
|
23
|
+
pi install npm:pi-posthorse@0.8.2 # from npm
|
|
24
|
+
pi install git:github.com/fitchmultz/pi-posthorse@v0.8.2 # from Git
|
|
25
|
+
pi -e npm:pi-posthorse@0.8.2 # try it for one run without installing
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
Omit the version or tag to follow the latest release.
|
package/package.json
CHANGED
package/src/history-entries.ts
CHANGED
|
@@ -213,7 +213,8 @@ export function toWindowedEntry(
|
|
|
213
213
|
images: imagesOf(entryContent(entry)),
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
|
-
|
|
216
|
+
/** Window ancestry is metadata-only; extracting text/images is a separate operation. */
|
|
217
|
+
export function windowProjection(): (entry: EntryLike) => string {
|
|
217
218
|
const windows = new Map<string, string>();
|
|
218
219
|
return (entry) => {
|
|
219
220
|
const inherited = windows.get(entry.parentId ?? "") ?? "initial";
|
|
@@ -221,13 +222,15 @@ export function windowProjection(): (entry: EntryLike) => WindowedEntry | undefi
|
|
|
221
222
|
if (entry.id !== undefined && entry.id !== "") {
|
|
222
223
|
windows.set(entry.id, windowId);
|
|
223
224
|
}
|
|
224
|
-
return
|
|
225
|
+
return windowId;
|
|
225
226
|
};
|
|
226
227
|
}
|
|
227
|
-
export function*
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
export function* reverseWindowEntries(entries: readonly EntryLike[]): Generator<WindowedEntry> {
|
|
229
|
+
// Preserve parent-relative window labels without normalizing the whole branch.
|
|
230
|
+
// ponytail: ancestry still scans metadata; a native window-aware iterator could remove that cost.
|
|
231
|
+
const windows = entries.map(windowProjection());
|
|
232
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
233
|
+
const item = toWindowedEntry(entries[i], windows[i]);
|
|
231
234
|
if (item !== undefined) {
|
|
232
235
|
yield item;
|
|
233
236
|
}
|
package/src/history-search.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type HistoryHit,
|
|
8
8
|
type ProjectedEntry,
|
|
9
9
|
} from "./contracts.ts";
|
|
10
|
-
import { historyHit, seenText,
|
|
10
|
+
import { historyHit, seenText, reverseWindowEntries } from "./history-entries.ts";
|
|
11
11
|
import { shortKey } from "./message-text.ts";
|
|
12
12
|
import {
|
|
13
13
|
filesContaining,
|
|
@@ -267,7 +267,7 @@ function branchMatches(
|
|
|
267
267
|
accumulator: SearchProgress,
|
|
268
268
|
): number {
|
|
269
269
|
let skipped = 0;
|
|
270
|
-
for (const item of
|
|
270
|
+
for (const item of reverseWindowEntries(source.branch())) {
|
|
271
271
|
const hit = historyHit(item, query);
|
|
272
272
|
if (hit === undefined) {
|
|
273
273
|
continue;
|
package/src/history.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
|
|
|
3
3
|
import { Type } from "typebox";
|
|
4
4
|
import { toolCards } from "../ui.ts";
|
|
5
5
|
import { requireValue, type PolicyContext, type WindowedEntry } from "./contracts.ts";
|
|
6
|
-
import {
|
|
6
|
+
import { toWindowedEntry, windowProjection } from "./history-entries.ts";
|
|
7
7
|
import { historyReadPage, searchPage } from "./history-pages.ts";
|
|
8
8
|
import { historyMatches, type HistorySource } from "./history-search.ts";
|
|
9
9
|
import type { PageAccess } from "./paging.ts";
|
|
@@ -17,18 +17,26 @@ function entryReference(id: string): { readonly entryId: string; readonly fileKe
|
|
|
17
17
|
fileKey: separator < 0 ? undefined : id.slice(separator + 1),
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
+
function branchEntry(source: HistorySource, id: string): WindowedEntry | undefined {
|
|
21
|
+
const project = windowProjection();
|
|
22
|
+
for (const entry of source.branch()) {
|
|
23
|
+
const windowId = project(entry);
|
|
24
|
+
const item = entry.id === id ? toWindowedEntry(entry, windowId) : undefined;
|
|
25
|
+
if (item !== undefined) {
|
|
26
|
+
return item;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
20
31
|
async function findEntry(
|
|
21
32
|
source: HistorySource,
|
|
22
33
|
id: string,
|
|
23
34
|
signal?: AbortSignal,
|
|
24
35
|
): Promise<LocatedEntry> {
|
|
25
36
|
const { entryId, fileKey } = entryReference(id);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return { item, source: "" };
|
|
30
|
-
}
|
|
31
|
-
}
|
|
37
|
+
const current = fileKey === undefined ? branchEntry(source, entryId) : undefined;
|
|
38
|
+
if (current !== undefined) {
|
|
39
|
+
return { item: current, source: "" };
|
|
32
40
|
}
|
|
33
41
|
const candidates =
|
|
34
42
|
fileKey === undefined && /^[\w-]+$/.test(entryId)
|
|
@@ -42,10 +50,8 @@ async function findEntry(
|
|
|
42
50
|
fileKey,
|
|
43
51
|
candidates: candidates === undefined ? undefined : (candidate) => candidates.has(candidate),
|
|
44
52
|
})) {
|
|
45
|
-
for await (const item of sessionWindowEntries(file, signal)) {
|
|
46
|
-
|
|
47
|
-
return { item, source: relative(source.dir, file) };
|
|
48
|
-
}
|
|
53
|
+
for await (const item of sessionWindowEntries(file, signal, entryId)) {
|
|
54
|
+
return { item, source: relative(source.dir, file) };
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
57
|
throw new Error(
|
package/src/session-files.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type WindowedEntry,
|
|
12
12
|
} from "./contracts.ts";
|
|
13
13
|
import { lfLines } from "./files.ts";
|
|
14
|
-
import { windowProjection } from "./history-entries.ts";
|
|
14
|
+
import { toWindowedEntry, windowProjection } from "./history-entries.ts";
|
|
15
15
|
import { shortKey } from "./message-text.ts";
|
|
16
16
|
|
|
17
17
|
function execFileText(
|
|
@@ -141,6 +141,7 @@ function parsedEntry(line: string): EntryLike | undefined {
|
|
|
141
141
|
export async function* sessionWindowEntries(
|
|
142
142
|
file: string,
|
|
143
143
|
signal?: AbortSignal,
|
|
144
|
+
entryId?: string,
|
|
144
145
|
): AsyncGenerator<WindowedEntry> {
|
|
145
146
|
if (!existsSync(file)) {
|
|
146
147
|
return;
|
|
@@ -151,7 +152,11 @@ export async function* sessionWindowEntries(
|
|
|
151
152
|
if (entry === undefined) {
|
|
152
153
|
continue;
|
|
153
154
|
}
|
|
154
|
-
const
|
|
155
|
+
const windowId = project(entry);
|
|
156
|
+
if (entryId !== undefined && entry.id !== entryId) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const item = toWindowedEntry(entry, windowId);
|
|
155
160
|
if (item !== undefined) {
|
|
156
161
|
yield item;
|
|
157
162
|
}
|