pi-thread-engine 0.4.3 → 0.4.4
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 +28 -2
- package/package.json +1 -1
- package/src/dashboard.ts +10 -3
package/extensions/index.ts
CHANGED
|
@@ -18,6 +18,30 @@ import { ThreadRegistry, formatElapsed } from "../src/core/registry.js";
|
|
|
18
18
|
import { ThreadExecutor } from "../src/core/executor.js";
|
|
19
19
|
import { createDashboard } from "../src/dashboard.js";
|
|
20
20
|
import type { Thread, ThreadType, Story, StoryPhase } from "../src/core/types.js";
|
|
21
|
+
import { writeFileSync } from "fs";
|
|
22
|
+
import { join } from "path";
|
|
23
|
+
|
|
24
|
+
// ── Export helper ───────────────────────────────────────────
|
|
25
|
+
function exportThread(id: string, r: ThreadRegistry, cwd: string): string | null {
|
|
26
|
+
const t = r.get(id);
|
|
27
|
+
const s = r.getStory(id);
|
|
28
|
+
if (!t && !s) return null;
|
|
29
|
+
const md = ["# pi-thread-engine Export"];
|
|
30
|
+
const ts = new Date().toISOString().slice(0, 19).replace(/[T:]/g, "-");
|
|
31
|
+
const fn = "thread-" + id + "-" + ts + ".md";
|
|
32
|
+
const outPath = join(cwd, fn);
|
|
33
|
+
if (s) { md.push("## Story: " + s.id); md.push("Goal: " + s.goal); }
|
|
34
|
+
if (t) {
|
|
35
|
+
const sum = r.summarize(t);
|
|
36
|
+
md.push("## " + sum.id + ": " + sum.type + " - " + sum.label);
|
|
37
|
+
for (const tk of t.tasks) {
|
|
38
|
+
const snip = tk.result ? tk.result.slice(0, 200).replace(/\n/g, " ") : tk.error ? "ERROR: " + tk.error.slice(0, 200) : "(no result)";
|
|
39
|
+
md.push("- " + tk.id + " [" + tk.state + "]: " + snip);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
writeFileSync(outPath, md.join("\n"), "utf8");
|
|
43
|
+
return outPath;
|
|
44
|
+
}
|
|
21
45
|
|
|
22
46
|
export default function (pi: ExtensionAPI) {
|
|
23
47
|
const registry = new ThreadRegistry();
|
|
@@ -235,7 +259,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
235
259
|
() => done(),
|
|
236
260
|
(id) => { registry.kill(id); ctx.ui.notify(`Killed ${id}`, "warning"); tui.requestRender(); },
|
|
237
261
|
(id) => { const t = registry.get(id); if (t) { ctx.ui.notify(`Thread ${id}: ${t.tasks.map((tk) => `${tk.id}: ${tk.result?.slice(0,100) ?? tk.error ?? "(pending)"}`).join("\n")}`, "info"); } },
|
|
238
|
-
(id, message) => { executor.injectReply(id, message); ctx.ui.notify(`Replied to ${id}: ${message.slice(0, 50)}...`, "info"); tui.requestRender(); }
|
|
262
|
+
(id, message) => { executor.injectReply(id, message); ctx.ui.notify(`Replied to ${id}: ${message.slice(0, 50)}...`, "info"); tui.requestRender(); },
|
|
263
|
+
(id) => { const p = exportThread(id, registry, ctx.cwd); if (p) ctx.ui.notify(`Exported to ${p}`, "info"); }
|
|
239
264
|
);
|
|
240
265
|
return { render: (w: number) => dashboard.render(w), invalidate: () => dashboard.invalidate(), handleInput: (data: string) => { dashboard.handleInput(data); tui.requestRender(); } };
|
|
241
266
|
});
|
|
@@ -265,7 +290,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
265
290
|
executor.injectReply(id, message);
|
|
266
291
|
ctx.ui.notify(`Replied to ${id}: ${message.slice(0, 50)}...`, "info");
|
|
267
292
|
tui.requestRender();
|
|
268
|
-
}
|
|
293
|
+
},
|
|
294
|
+
(id) => { const p = exportThread(id, registry, ctx.cwd); if (p) ctx.ui.notify(`Exported to ${p}`, "info"); }
|
|
269
295
|
);
|
|
270
296
|
|
|
271
297
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-thread-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Thread-Based Engineering for pi — all 7 thread types + stories + fusion + zero-touch + TUI dashboard. Based on @IndyDevDan framework from agenticengineer.com.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/dashboard.ts
CHANGED
|
@@ -36,7 +36,8 @@ export function createDashboard(
|
|
|
36
36
|
onClose: () => void,
|
|
37
37
|
onKill?: (id: string) => void,
|
|
38
38
|
onReview?: (id: string) => void,
|
|
39
|
-
onReply?: (id: string, message: string) => void
|
|
39
|
+
onReply?: (id: string, message: string) => void,
|
|
40
|
+
onExport?: (id: string) => void
|
|
40
41
|
) {
|
|
41
42
|
let selected = 0;
|
|
42
43
|
let expanded: string | null = null;
|
|
@@ -281,7 +282,13 @@ export function createDashboard(
|
|
|
281
282
|
}
|
|
282
283
|
return;
|
|
283
284
|
}
|
|
284
|
-
if (data === "
|
|
285
|
+
if (data === "e") {
|
|
286
|
+
const sel = getSelected();
|
|
287
|
+
if (sel) { onExport?.(groups[sel.group].rows[sel.row].id); cachedWidth = undefined; }
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
{
|
|
285
292
|
const sel = getSelected();
|
|
286
293
|
if (sel) { onKill?.(groups[sel.group].rows[sel.row].id); cachedWidth = undefined; }
|
|
287
294
|
return;
|
|
@@ -377,7 +384,7 @@ export function createDashboard(
|
|
|
377
384
|
lines.push(theme.fg("dim", ` ${tw(border, width)}`));
|
|
378
385
|
const help = showSearch
|
|
379
386
|
? tw(`Search: ${searchQuery}_ Enter done Esc cancel`, width - 4)
|
|
380
|
-
: tw("nav=↑↓ exp=Enter rep=i srch=/ kill=k rev=r prune=p quit=q", width - 4);
|
|
387
|
+
: tw("nav=↑↓ exp=Enter rep=i srch=/ kill=k rev=r export=e prune=p quit=q", width - 4);
|
|
381
388
|
lines.push(theme.fg("dim", ` ${help}`));
|
|
382
389
|
lines.push("");
|
|
383
390
|
|