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.
@@ -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",
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 === "k") {
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