poly-weaver 0.7.1 → 0.8.0

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.
Files changed (177) hide show
  1. package/dist/ansi.d.ts +7 -0
  2. package/dist/ansi.d.ts.map +1 -1
  3. package/dist/ansi.js +30 -0
  4. package/dist/ansi.js.map +1 -1
  5. package/dist/app-header.d.ts +16 -0
  6. package/dist/app-header.d.ts.map +1 -0
  7. package/dist/app-header.js +74 -0
  8. package/dist/app-header.js.map +1 -0
  9. package/dist/cli.js +81 -59
  10. package/dist/cli.js.map +1 -1
  11. package/dist/config.d.ts +1 -0
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +6 -0
  14. package/dist/config.js.map +1 -1
  15. package/dist/dump/collector.d.ts +2 -1
  16. package/dist/dump/collector.d.ts.map +1 -1
  17. package/dist/dump/collector.js +1 -0
  18. package/dist/dump/collector.js.map +1 -1
  19. package/dist/dump/hotkey.d.ts +9 -30
  20. package/dist/dump/hotkey.d.ts.map +1 -1
  21. package/dist/dump/hotkey.js +15 -158
  22. package/dist/dump/hotkey.js.map +1 -1
  23. package/dist/dump/service.d.ts +3 -2
  24. package/dist/dump/service.d.ts.map +1 -1
  25. package/dist/dump/service.js +4 -1
  26. package/dist/dump/service.js.map +1 -1
  27. package/dist/dump/types.d.ts +5 -0
  28. package/dist/dump/types.d.ts.map +1 -1
  29. package/dist/flow/built-in/default-factory.d.ts +21 -0
  30. package/dist/flow/built-in/default-factory.d.ts.map +1 -0
  31. package/dist/flow/built-in/default-factory.js +155 -0
  32. package/dist/flow/built-in/default-factory.js.map +1 -0
  33. package/dist/flow/built-in/default.d.ts +4 -4
  34. package/dist/flow/built-in/default.d.ts.map +1 -1
  35. package/dist/flow/built-in/default.js +3 -141
  36. package/dist/flow/built-in/default.js.map +1 -1
  37. package/dist/flow/built-in/default.ts +5 -169
  38. package/dist/flow/built-in/why-so-serious-factory.d.ts +16 -0
  39. package/dist/flow/built-in/why-so-serious-factory.d.ts.map +1 -0
  40. package/dist/flow/built-in/why-so-serious-factory.js +187 -0
  41. package/dist/flow/built-in/why-so-serious-factory.js.map +1 -0
  42. package/dist/flow/built-in/why-so-serious.d.ts +3 -2
  43. package/dist/flow/built-in/why-so-serious.d.ts.map +1 -1
  44. package/dist/flow/built-in/why-so-serious.js +3 -164
  45. package/dist/flow/built-in/why-so-serious.js.map +1 -1
  46. package/dist/flow/custom/AUTHORING.md +13 -0
  47. package/dist/flow/custom/load.d.ts +16 -1
  48. package/dist/flow/custom/load.d.ts.map +1 -1
  49. package/dist/flow/custom/load.js +69 -18
  50. package/dist/flow/custom/load.js.map +1 -1
  51. package/dist/flow/dsl.js +1 -1
  52. package/dist/flow/dsl.js.map +1 -1
  53. package/dist/flow/executor.d.ts.map +1 -1
  54. package/dist/flow/executor.js +44 -8
  55. package/dist/flow/executor.js.map +1 -1
  56. package/dist/flow/types.d.ts +20 -2
  57. package/dist/flow/types.d.ts.map +1 -1
  58. package/dist/flow/types.js.map +1 -1
  59. package/dist/flow-editor/tui.d.ts.map +1 -1
  60. package/dist/flow-editor/tui.js +9 -18
  61. package/dist/flow-editor/tui.js.map +1 -1
  62. package/dist/orchestrator.d.ts +43 -0
  63. package/dist/orchestrator.d.ts.map +1 -1
  64. package/dist/orchestrator.js +230 -92
  65. package/dist/orchestrator.js.map +1 -1
  66. package/dist/providers/claude/completion-plan-mode.d.ts.map +1 -1
  67. package/dist/providers/claude/completion-plan-mode.js +5 -2
  68. package/dist/providers/claude/completion-plan-mode.js.map +1 -1
  69. package/dist/providers/claude/tool-tracking.d.ts +1 -0
  70. package/dist/providers/claude/tool-tracking.d.ts.map +1 -1
  71. package/dist/providers/claude/tool-tracking.js +3 -0
  72. package/dist/providers/claude/tool-tracking.js.map +1 -1
  73. package/dist/pty/spawn.d.ts.map +1 -1
  74. package/dist/pty/spawn.js +6 -1
  75. package/dist/pty/spawn.js.map +1 -1
  76. package/dist/pty/types.d.ts +7 -2
  77. package/dist/pty/types.d.ts.map +1 -1
  78. package/dist/resume-tui.d.ts +52 -0
  79. package/dist/resume-tui.d.ts.map +1 -0
  80. package/dist/resume-tui.js +344 -0
  81. package/dist/resume-tui.js.map +1 -0
  82. package/dist/session/flow-snapshot.d.ts +14 -0
  83. package/dist/session/flow-snapshot.d.ts.map +1 -0
  84. package/dist/session/flow-snapshot.js +28 -0
  85. package/dist/session/flow-snapshot.js.map +1 -0
  86. package/dist/session/list.d.ts +16 -0
  87. package/dist/session/list.d.ts.map +1 -0
  88. package/dist/session/list.js +89 -0
  89. package/dist/session/list.js.map +1 -0
  90. package/dist/session/lock.d.ts +26 -0
  91. package/dist/session/lock.d.ts.map +1 -0
  92. package/dist/session/lock.js +95 -0
  93. package/dist/session/lock.js.map +1 -0
  94. package/dist/session/manifest.d.ts +80 -0
  95. package/dist/session/manifest.d.ts.map +1 -0
  96. package/dist/session/manifest.js +2 -0
  97. package/dist/session/manifest.js.map +1 -0
  98. package/dist/session/persistence.d.ts +19 -0
  99. package/dist/session/persistence.d.ts.map +1 -0
  100. package/dist/session/persistence.js +68 -0
  101. package/dist/session/persistence.js.map +1 -0
  102. package/dist/session/process-start-time.d.ts +17 -0
  103. package/dist/session/process-start-time.d.ts.map +1 -0
  104. package/dist/session/process-start-time.js +99 -0
  105. package/dist/session/process-start-time.js.map +1 -0
  106. package/dist/session/restore.d.ts +31 -0
  107. package/dist/session/restore.d.ts.map +1 -0
  108. package/dist/session/restore.js +111 -0
  109. package/dist/session/restore.js.map +1 -0
  110. package/dist/session/resume.d.ts +5 -0
  111. package/dist/session/resume.d.ts.map +1 -0
  112. package/dist/session/resume.js +109 -0
  113. package/dist/session/resume.js.map +1 -0
  114. package/dist/session/session-store.d.ts +43 -0
  115. package/dist/session/session-store.d.ts.map +1 -0
  116. package/dist/session/session-store.js +134 -0
  117. package/dist/session/session-store.js.map +1 -0
  118. package/dist/startup-tui.d.ts +10 -11
  119. package/dist/startup-tui.d.ts.map +1 -1
  120. package/dist/startup-tui.js +25 -108
  121. package/dist/startup-tui.js.map +1 -1
  122. package/dist/status-bar.js +1 -26
  123. package/dist/status-bar.js.map +1 -1
  124. package/dist/terminal/host.d.ts +22 -9
  125. package/dist/terminal/host.d.ts.map +1 -1
  126. package/dist/terminal/host.js +67 -78
  127. package/dist/terminal/host.js.map +1 -1
  128. package/dist/terminal/input-router.d.ts +24 -103
  129. package/dist/terminal/input-router.d.ts.map +1 -1
  130. package/dist/terminal/input-router.js +63 -364
  131. package/dist/terminal/input-router.js.map +1 -1
  132. package/dist/terminal/key-event-source.d.ts +52 -0
  133. package/dist/terminal/key-event-source.d.ts.map +1 -0
  134. package/dist/terminal/key-event-source.js +31 -0
  135. package/dist/terminal/key-event-source.js.map +1 -0
  136. package/dist/terminal/key-to-bytes.d.ts +11 -0
  137. package/dist/terminal/key-to-bytes.d.ts.map +1 -0
  138. package/dist/terminal/key-to-bytes.js +81 -0
  139. package/dist/terminal/key-to-bytes.js.map +1 -0
  140. package/dist/terminal/koffi-loader.d.ts +14 -0
  141. package/dist/terminal/koffi-loader.d.ts.map +1 -1
  142. package/dist/terminal/koffi-loader.js.map +1 -1
  143. package/dist/terminal/render.d.ts +1 -2
  144. package/dist/terminal/render.d.ts.map +1 -1
  145. package/dist/terminal/render.js +1 -30
  146. package/dist/terminal/render.js.map +1 -1
  147. package/dist/terminal/stdin-byte-source.d.ts +27 -0
  148. package/dist/terminal/stdin-byte-source.d.ts.map +1 -0
  149. package/dist/terminal/stdin-byte-source.js +92 -0
  150. package/dist/terminal/stdin-byte-source.js.map +1 -0
  151. package/dist/terminal/win32-console-mode.d.ts.map +1 -1
  152. package/dist/terminal/win32-console-mode.js.map +1 -1
  153. package/dist/terminal/win32-console-source.d.ts +26 -0
  154. package/dist/terminal/win32-console-source.d.ts.map +1 -0
  155. package/dist/terminal/win32-console-source.js +275 -0
  156. package/dist/terminal/win32-console-source.js.map +1 -0
  157. package/dist/terminal/win32-key-translator.d.ts +26 -0
  158. package/dist/terminal/win32-key-translator.d.ts.map +1 -0
  159. package/dist/terminal/win32-key-translator.js +87 -0
  160. package/dist/terminal/win32-key-translator.js.map +1 -0
  161. package/dist/terminal-input.d.ts +10 -0
  162. package/dist/terminal-input.d.ts.map +1 -1
  163. package/dist/terminal-input.js +132 -113
  164. package/dist/terminal-input.js.map +1 -1
  165. package/dist/user/host-curate-prompt.d.ts +2 -1
  166. package/dist/user/host-curate-prompt.d.ts.map +1 -1
  167. package/dist/user/host-curate-prompt.js +13 -11
  168. package/dist/user/host-curate-prompt.js.map +1 -1
  169. package/dist/user/host-prompt.d.ts +4 -1
  170. package/dist/user/host-prompt.d.ts.map +1 -1
  171. package/dist/user/host-prompt.js +24 -6
  172. package/dist/user/host-prompt.js.map +1 -1
  173. package/dist/user/prompt.d.ts +7 -9
  174. package/dist/user/prompt.d.ts.map +1 -1
  175. package/dist/user/prompt.js +14 -23
  176. package/dist/user/prompt.js.map +1 -1
  177. package/package.json +1 -1
@@ -0,0 +1,109 @@
1
+ import { join } from "node:path";
2
+ import { readdir } from "node:fs/promises";
3
+ import { setProviderVersions } from "../providers/registry.js";
4
+ import { runPreflight, computePreflightNeeds } from "../preflight.js";
5
+ import { StatusBar } from "../status-bar.js";
6
+ import { DumpService } from "../dump/service.js";
7
+ import { getGitInfo } from "../git-info.js";
8
+ import { TerminalHost } from "../terminal/host.js";
9
+ import { BufferOrchestrationOutput, ConsoleOrchestrationOutput } from "../terminal/output.js";
10
+ import { CLEAR_SCREEN, CURSOR_HOME, SHOW_CURSOR } from "../ansi.js";
11
+ import { orchestrateWithTemplate, interpretOrchestrationResult, interpretOrchestrationError, } from "../orchestrator.js";
12
+ import { rehydrateFlow } from "./flow-snapshot.js";
13
+ import { readJsonIfExists } from "./persistence.js";
14
+ export async function runResumedSession(session, pkgVersion) {
15
+ const persistentDir = session.persistentDir;
16
+ const manifest = session.manifest;
17
+ if (manifest.status === "complete") {
18
+ return { exitCode: 1, exitMessage: `\nSession ${session.sessionId} is already complete.` };
19
+ }
20
+ const steps = new Map();
21
+ try {
22
+ const stepFiles = (await readdir(join(persistentDir, "steps")))
23
+ .filter(f => f.endsWith(".json"));
24
+ const entries = await Promise.all(stepFiles.map(f => readJsonIfExists(join(persistentDir, "steps", f))));
25
+ for (const entry of entries) {
26
+ if (entry)
27
+ steps.set(entry.seq, entry);
28
+ }
29
+ }
30
+ catch (err) {
31
+ if (err.code !== "ENOENT")
32
+ throw err;
33
+ }
34
+ // Rehydrate the flow template from the snapshot
35
+ const template = await rehydrateFlow(persistentDir);
36
+ // Re-run preflight against the resumed session's params
37
+ const preflight = await runPreflight(computePreflightNeeds({
38
+ planner: String(manifest.flow.params.planner),
39
+ reviewer: String(manifest.flow.params.reviewer),
40
+ implementor: String(manifest.flow.params.implementor),
41
+ simplifier: manifest.flow.params.simplifier
42
+ ? String(manifest.flow.params.simplifier)
43
+ : undefined,
44
+ planOnly: !!manifest.flow.params.planOnly,
45
+ }));
46
+ setProviderVersions(preflight.versions);
47
+ if (!preflight.ok) {
48
+ return {
49
+ exitCode: 1,
50
+ exitMessage: "\nPreflight checks failed on resume:\n" + preflight.errors.map(e => ` ${e}`).join("\n"),
51
+ };
52
+ }
53
+ const hostMode = process.stdin.isTTY === true && process.stdout.isTTY === true;
54
+ const statusBar = new StatusBar(undefined, { hostManaged: hostMode });
55
+ statusBar.init();
56
+ const gitInfo = await getGitInfo(manifest.workdir);
57
+ if (gitInfo)
58
+ statusBar.setGitInfo(gitInfo);
59
+ const dumpService = process.stdin.isTTY ? new DumpService(pkgVersion, statusBar) : undefined;
60
+ let terminalHost;
61
+ let bufferOutput;
62
+ if (hostMode) {
63
+ bufferOutput = new BufferOrchestrationOutput();
64
+ terminalHost = new TerminalHost({
65
+ statusBar,
66
+ output: bufferOutput,
67
+ onDump: dumpService ? () => { void dumpService.trigger(); } : undefined,
68
+ });
69
+ terminalHost.start();
70
+ }
71
+ const orchestrationOutput = bufferOutput ?? new ConsoleOrchestrationOutput();
72
+ const resumeFrom = {
73
+ sessionId: manifest.sessionId,
74
+ createdAt: manifest.createdAt,
75
+ persistentDir,
76
+ manifest,
77
+ steps,
78
+ };
79
+ let outcome = { exitCode: 0, exitMessage: "" };
80
+ try {
81
+ const result = await orchestrateWithTemplate({
82
+ template,
83
+ paramValues: manifest.flow.params,
84
+ task: manifest.taskText,
85
+ workdir: manifest.workdir,
86
+ opinionless: manifest.options.opinionless,
87
+ yolo: manifest.options.yolo,
88
+ statusBar,
89
+ dumpService,
90
+ output: orchestrationOutput,
91
+ terminalHost,
92
+ resumeFrom,
93
+ polyWeaverVersion: pkgVersion,
94
+ });
95
+ outcome = interpretOrchestrationResult(result);
96
+ }
97
+ catch (err) {
98
+ outcome = interpretOrchestrationError(err);
99
+ }
100
+ finally {
101
+ terminalHost?.stop();
102
+ statusBar.destroy();
103
+ if (process.stdout.isTTY) {
104
+ process.stdout.write(CLEAR_SCREEN + CURSOR_HOME + SHOW_CURSOR);
105
+ }
106
+ }
107
+ return outcome;
108
+ }
109
+ //# sourceMappingURL=resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/session/resume.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { StepRecord } from "../dump/types.js";
2
+ import type { StepContext } from "../flow/types.js";
3
+ import type { SessionManifest } from "./manifest.js";
4
+ /**
5
+ * Per-step persistent checkpoint writer.
6
+ *
7
+ * Subscribes to `ctx.onStepCompleted` alongside `DumpService`. On every step
8
+ * boundary, snapshots the **full** artifact store (so artifacts mutated outside
9
+ * `step.writes` — notably TASK after incorporateFeedback — survive a resume).
10
+ */
11
+ export declare class SessionStore {
12
+ private readonly persistentDir;
13
+ private ctx;
14
+ private manifest;
15
+ constructor(persistentDir: string, manifest: SessionManifest);
16
+ /**
17
+ * Create directories and write the initial manifest atomically. Should be
18
+ * called exactly once per fresh session (resumed sessions re-use the
19
+ * existing manifest in place — see {@link initForResume}).
20
+ */
21
+ init(): Promise<void>;
22
+ /** For resumed sessions: ensure subdirs exist, but don't overwrite manifest. */
23
+ initForResume(): Promise<void>;
24
+ bindContext(ctx: StepContext): void;
25
+ getDir(): string;
26
+ /**
27
+ * Subscribed to ctx.onStepCompleted. Captures a full snapshot of
28
+ * ctx.artifacts plus counters.
29
+ */
30
+ readonly onStepCompleted: (record: StepRecord) => Promise<void>;
31
+ /** Mark this session complete so the picker hides it; pruner deletes after 7d. */
32
+ markComplete(): Promise<void>;
33
+ /** Build an ArtifactRef for one artifact, copying any file blob into the persistent dir. */
34
+ private snapshotArtifact;
35
+ /**
36
+ * Build a per-step input/output ref. Prefer the already-snapshotted artifact
37
+ * store entry (so persistentPath matches), but fall back to a minimal ref
38
+ * derived from the dump snapshot if the artifact wasn't in `ctx.artifacts`
39
+ * for some reason.
40
+ */
41
+ private refFromStoreKey;
42
+ }
43
+ //# sourceMappingURL=session-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/session/session-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAY,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE9D,OAAO,KAAK,EAAe,eAAe,EAAoB,MAAM,eAAe,CAAC;AAEpF;;;;;;GAMG;AACH,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAJhC,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,QAAQ,CAAkB;gBAGf,aAAa,EAAE,MAAM,EACtC,QAAQ,EAAE,eAAe;IAK3B;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,gFAAgF;IAC1E,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAKpC,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IAInC,MAAM,IAAI,MAAM;IAIhB;;;OAGG;IACH,QAAQ,CAAC,eAAe,GAAU,QAAQ,UAAU,KAAG,OAAO,CAAC,IAAI,CAAC,CA2ClE;IAEF,kFAAkF;IAC5E,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IASnC,4FAA4F;YAC9E,gBAAgB;IA2B9B;;;;;OAKG;IACH,OAAO,CAAC,eAAe;CAWxB"}
@@ -0,0 +1,134 @@
1
+ import { copyFile } from "node:fs/promises";
2
+ import { extname, join } from "node:path";
3
+ import { atomicWriteJson, ensureDir, stepFilename } from "./persistence.js";
4
+ /**
5
+ * Per-step persistent checkpoint writer.
6
+ *
7
+ * Subscribes to `ctx.onStepCompleted` alongside `DumpService`. On every step
8
+ * boundary, snapshots the **full** artifact store (so artifacts mutated outside
9
+ * `step.writes` — notably TASK after incorporateFeedback — survive a resume).
10
+ */
11
+ export class SessionStore {
12
+ persistentDir;
13
+ ctx;
14
+ manifest;
15
+ constructor(persistentDir, manifest) {
16
+ this.persistentDir = persistentDir;
17
+ this.manifest = manifest;
18
+ }
19
+ /**
20
+ * Create directories and write the initial manifest atomically. Should be
21
+ * called exactly once per fresh session (resumed sessions re-use the
22
+ * existing manifest in place — see {@link initForResume}).
23
+ */
24
+ async init() {
25
+ await ensureDir(this.persistentDir);
26
+ await ensureDir(join(this.persistentDir, "artifacts"));
27
+ await ensureDir(join(this.persistentDir, "steps"));
28
+ await atomicWriteJson(join(this.persistentDir, "manifest.json"), this.manifest);
29
+ }
30
+ /** For resumed sessions: ensure subdirs exist, but don't overwrite manifest. */
31
+ async initForResume() {
32
+ await ensureDir(join(this.persistentDir, "artifacts"));
33
+ await ensureDir(join(this.persistentDir, "steps"));
34
+ }
35
+ bindContext(ctx) {
36
+ this.ctx = ctx;
37
+ }
38
+ getDir() {
39
+ return this.persistentDir;
40
+ }
41
+ /**
42
+ * Subscribed to ctx.onStepCompleted. Captures a full snapshot of
43
+ * ctx.artifacts plus counters.
44
+ */
45
+ onStepCompleted = async (record) => {
46
+ if (!this.ctx)
47
+ return;
48
+ const seq = record.seq;
49
+ const artifactStore = {};
50
+ for (const [storeKey, artifact] of this.ctx.artifacts.entries()) {
51
+ artifactStore[storeKey] = await this.snapshotArtifact(seq, storeKey, artifact);
52
+ }
53
+ const inputs = {};
54
+ for (const [alias, snap] of Object.entries(record.inputs)) {
55
+ inputs[alias] = this.refFromStoreKey(artifactStore, snap.artifactName, snap);
56
+ }
57
+ const outputs = {};
58
+ for (const [alias, snap] of Object.entries(record.outputs)) {
59
+ outputs[alias] = this.refFromStoreKey(artifactStore, snap.artifactName, snap);
60
+ }
61
+ const entry = {
62
+ seq,
63
+ stepId: record.stepId,
64
+ role: record.role,
65
+ driver: record.driver,
66
+ phaseLabel: record.phaseLabel,
67
+ inputs,
68
+ outputs,
69
+ artifactStore,
70
+ loopIterations: Object.fromEntries(this.ctx.loopIterations),
71
+ loopCycle: Object.fromEntries(this.ctx.loopCycle),
72
+ totalIterations: this.ctx.totalIterations,
73
+ nextClarificationNumber: this.ctx.nextClarificationNumber,
74
+ sessionIds: Object.fromEntries(this.ctx.sessionIds),
75
+ completedAt: new Date().toISOString(),
76
+ };
77
+ await atomicWriteJson(join(this.persistentDir, "steps", stepFilename(seq)), entry);
78
+ this.manifest = {
79
+ ...this.manifest,
80
+ lastCompletedSeq: seq,
81
+ lastActivityAt: entry.completedAt,
82
+ };
83
+ await atomicWriteJson(join(this.persistentDir, "manifest.json"), this.manifest);
84
+ };
85
+ /** Mark this session complete so the picker hides it; pruner deletes after 7d. */
86
+ async markComplete() {
87
+ this.manifest = {
88
+ ...this.manifest,
89
+ status: "complete",
90
+ lastActivityAt: new Date().toISOString(),
91
+ };
92
+ await atomicWriteJson(join(this.persistentDir, "manifest.json"), this.manifest);
93
+ }
94
+ /** Build an ArtifactRef for one artifact, copying any file blob into the persistent dir. */
95
+ async snapshotArtifact(seq, storeKey, artifact) {
96
+ const ref = { storeKey };
97
+ if (artifact.file) {
98
+ const ext = extname(artifact.file);
99
+ const safeKey = storeKey.replace(/[^A-Za-z0-9._-]/g, "_");
100
+ const dest = join(this.persistentDir, "artifacts", `step-${String(seq).padStart(4, "0")}-${safeKey}${ext}`);
101
+ try {
102
+ await copyFile(artifact.file, dest);
103
+ ref.persistentPath = dest;
104
+ }
105
+ catch {
106
+ // Source may have been cleaned up; fall through with text/data only.
107
+ }
108
+ }
109
+ if (artifact.text !== undefined)
110
+ ref.text = artifact.text;
111
+ if (artifact.data !== undefined)
112
+ ref.dataJson = JSON.stringify(artifact.data);
113
+ if (artifact.meta !== undefined)
114
+ ref.meta = artifact.meta;
115
+ return ref;
116
+ }
117
+ /**
118
+ * Build a per-step input/output ref. Prefer the already-snapshotted artifact
119
+ * store entry (so persistentPath matches), but fall back to a minimal ref
120
+ * derived from the dump snapshot if the artifact wasn't in `ctx.artifacts`
121
+ * for some reason.
122
+ */
123
+ refFromStoreKey(artifactStore, storeKey, fallback) {
124
+ if (artifactStore[storeKey])
125
+ return artifactStore[storeKey];
126
+ const ref = { storeKey };
127
+ if (fallback.text !== undefined)
128
+ ref.text = fallback.text;
129
+ if (fallback.dataJson !== undefined)
130
+ ref.dataJson = fallback.dataJson;
131
+ return ref;
132
+ }
133
+ }
134
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/session/session-store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { CliOptions } from "./config.js";
2
2
  import type { FlowTemplate } from "./flow/types.js";
3
+ import type { TerminalKey } from "./terminal-input.js";
3
4
  import type { GitInfo } from "./git-info.js";
4
5
  import { type UpdateInfo } from "./update-check.js";
5
6
  import { type ConfigField } from "./preview-panel.js";
@@ -33,15 +34,16 @@ export type TuiInputEvent = {
33
34
  type: "ctrl+c";
34
35
  };
35
36
  /**
36
- * TUI input parser wraps {@link TerminalKeyParser} via composition and
37
- * maps {@link TerminalKey} {@link TuiInputEvent}.
37
+ * Stateless mapper from `TerminalKey` events to {@link TuiInputEvent}
38
+ * domain events for the startup TUI / flow editor. Consumes events
39
+ * produced by the `KeyEventSource` byte/FFI pipeline.
38
40
  */
39
41
  export declare class TuiInputParser {
40
- private parser;
41
- constructor(escapeTimeoutMs?: number);
42
- parseChunk(chunk: Buffer): TuiInputEvent[];
43
- onDeferredEvents(cb: (events: TuiInputEvent[]) => void): void;
44
- cancelPendingEscape(): void;
42
+ /**
43
+ * Map a stream of `TerminalKey[]` (from `KeyEventSource`) into TUI
44
+ * input events.
45
+ */
46
+ mapKeys(keys: TerminalKey[]): TuiInputEvent[];
45
47
  private mapKey;
46
48
  }
47
49
  export type { ConfigField } from "./preview-panel.js";
@@ -64,10 +66,7 @@ export interface TuiState {
64
66
  flowSectionHeight: number;
65
67
  templateIndex: number;
66
68
  taskRequired: boolean;
67
- updateBanner: {
68
- current: string;
69
- latest: string;
70
- } | null;
69
+ updateBanner: UpdateInfo | null;
71
70
  }
72
71
  export declare function buildInitialState(defaults: Partial<CliOptions>, rows: number, cols: number, gitInfo?: GitInfo | null): TuiState;
73
72
  /** Compute available editor height. */
@@ -1 +1 @@
1
- {"version":3,"file":"startup-tui.d.ts","sourceRoot":"","sources":["../src/startup-tui.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"startup-tui.d.ts","sourceRoot":"","sources":["../src/startup-tui.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,11 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
3
  import { flowReadsTask } from "./flow/inspect.js";
4
- import { TerminalKeyParser } from "./terminal-input.js";
5
- import { visibleLength, padToWidth, bold, dim, reset, cyan, green, red, yellow, HIDE_CURSOR, ALT_SCREEN_ON, ALT_SCREEN_OFF, CSI, } from "./ansi.js";
4
+ import { createKeyEventSource } from "./terminal/key-event-source.js";
5
+ import { padToWidth, bold, dim, reset, cyan, red, yellow, HIDE_CURSOR, ALT_SCREEN_ON, ALT_SCREEN_OFF, CSI, } from "./ansi.js";
6
6
  import { getGitInfo } from "./git-info.js";
7
- import { branchAnimalEmoji } from "./status-bar.js";
8
- import { APP_VERSION } from "./version.js";
9
7
  import { checkForUpdate } from "./update-check.js";
8
+ import { renderAppHeader, shouldShowBanner, tildeify } from "./app-header.js";
10
9
  import { buildFieldsForTemplate as buildFieldsForTemplateBase, configRowCount, handleFieldEvent, renderConfigFields, renderFlowSection, renderEditorLines, handleTextEditorEvent, computeFlowSectionHeight, } from "./preview-panel.js";
11
10
  let flowTemplates = [];
12
11
  let flowBuiltinCount = 0;
@@ -19,26 +18,17 @@ export function setFlowTemplates(templates, builtinCount = templates.length, cus
19
18
  maxFlowNameLen = Math.max(0, ...templates.map((template) => template.name.length));
20
19
  }
21
20
  /**
22
- * TUI input parser wraps {@link TerminalKeyParser} via composition and
23
- * maps {@link TerminalKey} {@link TuiInputEvent}.
21
+ * Stateless mapper from `TerminalKey` events to {@link TuiInputEvent}
22
+ * domain events for the startup TUI / flow editor. Consumes events
23
+ * produced by the `KeyEventSource` byte/FFI pipeline.
24
24
  */
25
25
  export class TuiInputParser {
26
- parser;
27
- constructor(escapeTimeoutMs) {
28
- this.parser = new TerminalKeyParser(escapeTimeoutMs);
29
- }
30
- parseChunk(chunk) {
31
- return this.parser.parseChunk(chunk).flatMap((key) => this.mapKey(key));
32
- }
33
- onDeferredEvents(cb) {
34
- this.parser.onDeferredKeys((keys) => {
35
- const events = keys.flatMap((k) => this.mapKey(k));
36
- if (events.length > 0)
37
- cb(events);
38
- });
39
- }
40
- cancelPendingEscape() {
41
- this.parser.cancelPendingEscape();
26
+ /**
27
+ * Map a stream of `TerminalKey[]` (from `KeyEventSource`) into TUI
28
+ * input events.
29
+ */
30
+ mapKeys(keys) {
31
+ return keys.flatMap((k) => this.mapKey(k));
42
32
  }
43
33
  mapKey(key) {
44
34
  switch (key.kind) {
@@ -82,27 +72,19 @@ export class TuiInputParser {
82
72
  if (key.keyCode === 3)
83
73
  return [{ type: "ctrl+c" }];
84
74
  return [];
75
+ case "raw":
76
+ // Unmapped VT frames are not meaningful to the TUI. The host
77
+ // (when present) is responsible for forwarding them to a child
78
+ // PTY; the startup TUI is not connected to one.
79
+ return [];
85
80
  default:
86
81
  return [];
87
82
  }
88
83
  }
89
84
  }
90
85
  // ─── Constants ───────────────────────────────────────────────────────────
91
- /**
92
- * Whether the update banner should be rendered.
93
- * Suppressed when terminal is too narrow to fit the full banner text.
94
- */
95
- function shouldShowBanner(state, cols) {
96
- if (!state.updateBanner)
97
- return false;
98
- // Visible text: " Update available: v{cur} → v{latest} Run: npm i -g poly-weaver"
99
- // = 2 + "Update available: " (19) + "v" + cur + " → " (3) + "v" + latest + " Run: " (7) + "npm i -g poly-weaver" (20)
100
- // = 52 + cur.length + latest.length
101
- const visLen = 52 + state.updateBanner.current.length + state.updateBanner.latest.length;
102
- return visLen <= cols;
103
- }
104
86
  function headerRows(state, cols) {
105
- return shouldShowBanner(state, cols) ? 3 : 2;
87
+ return shouldShowBanner(state.updateBanner, cols) ? 3 : 2;
106
88
  }
107
89
  const SEPARATOR_ROWS = 2; // margin line (config/flow) + separator (flow/task)
108
90
  const TASK_LABEL_ROWS = 1;
@@ -116,17 +98,6 @@ function getActiveTemplate(state) {
116
98
  ensureTemplates();
117
99
  return flowTemplates[state.templateIndex];
118
100
  }
119
- function tildeify(dir) {
120
- const normalizedDir = dir.replace(/\\/g, "/");
121
- const normalizedHome = homedir().replace(/\\/g, "/");
122
- if (normalizedDir === normalizedHome) {
123
- return "~";
124
- }
125
- if (normalizedDir.startsWith(`${normalizedHome}/`)) {
126
- return `~${normalizedDir.slice(normalizedHome.length)}`;
127
- }
128
- return normalizedDir;
129
- }
130
101
  function buildOriginOpts(state) {
131
102
  const isBuiltin = state.templateIndex < flowBuiltinCount;
132
103
  return {
@@ -243,42 +214,7 @@ export function render(state, out) {
243
214
  const lines = [];
244
215
  const pad = (s) => padToWidth(s, cols);
245
216
  // Header
246
- const title = ` ${bold}${cyan}poly-weaver v${APP_VERSION}${reset}`;
247
- if (state.gitInfo) {
248
- const animal = branchAnimalEmoji(state.gitInfo.branch);
249
- const wt = state.gitInfo.isWorktree ? " 🌲" : "";
250
- const gitSeg = `${animal} ${state.gitInfo.branch}${wt}`;
251
- const titleVisible = visibleLength(title);
252
- const gitSegVisible = visibleLength(gitSeg);
253
- if (titleVisible + 2 + gitSegVisible <= cols - 2) {
254
- lines.push(pad(`${title} ${dim}${gitSeg}${reset}`));
255
- }
256
- else {
257
- const maxBranch = cols - titleVisible - visibleLength(`${animal} ${wt}`) - 4;
258
- if (maxBranch >= 4) {
259
- const truncated = state.gitInfo.branch.slice(0, maxBranch - 1) + "…";
260
- const truncSeg = `${animal} ${truncated}${wt}`;
261
- lines.push(pad(`${title} ${dim}${truncSeg}${reset}`));
262
- }
263
- else {
264
- lines.push(pad(title));
265
- }
266
- }
267
- }
268
- else {
269
- lines.push(pad(title));
270
- }
271
- // Update notification banner (between title and separator)
272
- if (shouldShowBanner(state, cols)) {
273
- const { current, latest } = state.updateBanner;
274
- const bannerText = ` ${dim}Update available:${reset} ` +
275
- `${yellow}v${current}${reset} ` +
276
- `${dim}\u2192${reset} ` +
277
- `${green}v${latest}${reset} ` +
278
- `${dim}Run:${reset} ${cyan}npm i -g poly-weaver${reset}`;
279
- lines.push(pad(bannerText));
280
- }
281
- lines.push(pad(` ${"━".repeat(Math.max(0, cols - 4))}`));
217
+ lines.push(...renderAppHeader(cols, state.gitInfo, state.updateBanner));
282
218
  // Config panel (shared)
283
219
  lines.push(...renderConfigFields(state.fields, state.configIndex, state.zone === "config", cols));
284
220
  // Flow diagram section (shared)
@@ -492,11 +428,11 @@ export async function showStartupTui(defaults) {
492
428
  }
493
429
  async function inputLoop(state, workdir) {
494
430
  const parser = new TuiInputParser();
495
- process.stdin.setRawMode(true);
496
- process.stdin.resume();
431
+ const source = createKeyEventSource();
432
+ source.start();
497
433
  return new Promise((resolve) => {
498
- parser.onDeferredEvents((events) => {
499
- for (const event of events) {
434
+ const unsubscribe = source.onEvents((keys) => {
435
+ for (const event of parser.mapKeys(keys)) {
500
436
  const result = handleEvent(state, event);
501
437
  if (result === "start") {
502
438
  cleanup();
@@ -511,23 +447,6 @@ async function inputLoop(state, workdir) {
511
447
  }
512
448
  render(state, process.stdout);
513
449
  });
514
- const onData = (chunk) => {
515
- for (const event of parser.parseChunk(chunk)) {
516
- const result = handleEvent(state, event);
517
- if (result === "start") {
518
- cleanup();
519
- resolve(buildCliOptions(state, workdir));
520
- return;
521
- }
522
- else if (result === "cancel") {
523
- cleanup();
524
- resolve(null);
525
- return;
526
- }
527
- }
528
- render(state, process.stdout);
529
- };
530
- process.stdin.on("data", onData);
531
450
  const onResize = () => {
532
451
  state.termRows = process.stdout.rows ?? 24;
533
452
  state.termCols = process.stdout.columns ?? 80;
@@ -536,11 +455,9 @@ async function inputLoop(state, workdir) {
536
455
  };
537
456
  process.stdout.on("resize", onResize);
538
457
  function cleanup() {
539
- parser.cancelPendingEscape();
540
- process.stdin.removeListener("data", onData);
458
+ unsubscribe();
459
+ source.stop();
541
460
  process.stdout.removeListener("resize", onResize);
542
- process.stdin.setRawMode(false);
543
- process.stdin.resume();
544
461
  }
545
462
  });
546
463
  }