pi-jar 0.1.0 → 0.1.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/extensions/index.ts +74 -53
- package/package.json +1 -1
- package/src/advisor.ts +30 -6
- package/src/animations.ts +1 -1
- package/src/changes.ts +58 -17
- package/src/compact-tools.ts +62 -18
- package/src/composer.ts +32 -17
- package/src/delegate.ts +38 -9
- package/src/diff-view.ts +25 -3
- package/src/goal-loop.ts +34 -9
- package/src/goals.ts +13 -2
- package/src/history-ui.ts +2 -1
- package/src/info-panels.ts +19 -7
- package/src/mascot.ts +14 -0
- package/src/plan.ts +36 -10
- package/src/prompt-search.ts +25 -8
- package/src/quota.ts +14 -4
- package/src/session-branch.ts +24 -0
- package/src/session-gallery.ts +2 -2
- package/src/session-ui.ts +15 -6
- package/src/shells.ts +78 -23
- package/src/side-model.ts +14 -2
- package/src/status.ts +34 -24
- package/src/suggest.ts +6 -25
- package/src/task-tool.ts +35 -11
- package/src/tasks.ts +24 -7
- package/src/usage.ts +2 -1
package/src/tasks.ts
CHANGED
|
@@ -22,6 +22,18 @@ export type TodoEvent =
|
|
|
22
22
|
const validId = (id: unknown): id is string => typeof id === "string" && /^[a-zA-Z0-9-]{1,64}$/.test(id);
|
|
23
23
|
const validTitle = (title: unknown): title is string => typeof title === "string" && title.length <= 256 && !!cleanText(title, 120);
|
|
24
24
|
const validStatus = (status: unknown): status is TodoStatus => TODO_STATUSES.includes(status as TodoStatus);
|
|
25
|
+
const validWrite = (event: Record<string, unknown>): boolean => {
|
|
26
|
+
if (event.v !== 1 || event.op !== "write" || !Array.isArray(event.items) || event.items.length > MAX_TODOS) return false;
|
|
27
|
+
const ids = new Set<string>();
|
|
28
|
+
let running = 0;
|
|
29
|
+
for (const raw of event.items as unknown[]) {
|
|
30
|
+
const item = raw as Record<string, unknown> | null;
|
|
31
|
+
if (!item || !validId(item.id) || !validTitle(item.title) || !validStatus(item.status) || ids.has(item.id)) return false;
|
|
32
|
+
ids.add(item.id);
|
|
33
|
+
if (item.status === "in_progress" && ++running > 1) return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
};
|
|
25
37
|
const make = (id: string, title: string, status: TodoStatus, activeForm?: unknown, details?: unknown): Todo => ({
|
|
26
38
|
id, title: cleanText(title, 120), status, done: status === "completed",
|
|
27
39
|
...(typeof activeForm === "string" && cleanText(activeForm, 80) ? { activeForm: cleanText(activeForm, 80) } : {}),
|
|
@@ -50,14 +62,12 @@ export class TodoStore {
|
|
|
50
62
|
const event = raw as Record<string, unknown>;
|
|
51
63
|
if (event.v !== 1) return false;
|
|
52
64
|
if (event.op === "write") {
|
|
53
|
-
if (!
|
|
65
|
+
if (!validWrite(event)) return false;
|
|
54
66
|
const next = new Map<string, Todo>();
|
|
55
67
|
for (const raw of event.items as unknown[]) {
|
|
56
|
-
const item = raw as Record<string, unknown
|
|
57
|
-
|
|
58
|
-
next.set(item.id, make(item.id, item.title, item.status, item.activeForm, this.items.get(item.id)?.details));
|
|
68
|
+
const item = raw as Record<string, unknown>;
|
|
69
|
+
next.set(item.id as string, make(item.id as string, item.title as string, item.status as TodoStatus, item.activeForm, this.items.get(item.id as string)?.details));
|
|
59
70
|
}
|
|
60
|
-
if ([...next.values()].filter((item) => item.status === "in_progress").length > 1) return false;
|
|
61
71
|
this.items = next;
|
|
62
72
|
return true;
|
|
63
73
|
}
|
|
@@ -86,11 +96,18 @@ export class TodoStore {
|
|
|
86
96
|
}
|
|
87
97
|
restore(branch: readonly unknown[]): void {
|
|
88
98
|
this.items.clear();
|
|
89
|
-
|
|
99
|
+
// Walk the transcript once from newest to oldest, collecting only task events. A valid full
|
|
100
|
+
// write is a checkpoint, so everything before it is irrelevant.
|
|
101
|
+
const replay: unknown[] = [];
|
|
102
|
+
for (let index = branch.length - 1; index >= 0; index--) {
|
|
103
|
+
const raw = branch[index];
|
|
90
104
|
if (!raw || typeof raw !== "object") continue;
|
|
91
105
|
const entry = raw as Record<string, unknown>;
|
|
92
|
-
if (entry.type
|
|
106
|
+
if (entry.type !== "custom" || entry.customType !== TASK_ENTRY) continue;
|
|
107
|
+
replay.push(entry.data);
|
|
108
|
+
if (entry.data && typeof entry.data === "object" && validWrite(entry.data as Record<string, unknown>)) break;
|
|
93
109
|
}
|
|
110
|
+
for (let index = replay.length - 1; index >= 0; index--) this.apply(replay[index]);
|
|
94
111
|
}
|
|
95
112
|
private commit(event: TodoEvent): boolean {
|
|
96
113
|
const before = new Map([...this.items].map(([id, item]) => [id, { ...item }]));
|
package/src/usage.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { sessionBranch } from "./session-branch.ts";
|
|
1
2
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
3
|
|
|
3
4
|
/** Sum the active session branch, not all historical branches, using Pi's reported monetary cost. */
|
|
4
5
|
export function sessionCost(ctx: Pick<ExtensionContext, "sessionManager">): number {
|
|
5
6
|
let total = 0;
|
|
6
|
-
for (const entry of ctx.sessionManager.getBranch
|
|
7
|
+
for (const entry of sessionBranch(ctx) as ReturnType<typeof ctx.sessionManager.getBranch>) {
|
|
7
8
|
if (entry.type !== "message" || entry.message.role !== "assistant") continue;
|
|
8
9
|
const value = entry.message.usage.cost.total;
|
|
9
10
|
if (Number.isFinite(value) && value >= 0) total += value;
|