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.
- package/dist/ansi.d.ts +7 -0
- package/dist/ansi.d.ts.map +1 -1
- package/dist/ansi.js +30 -0
- package/dist/ansi.js.map +1 -1
- package/dist/app-header.d.ts +16 -0
- package/dist/app-header.d.ts.map +1 -0
- package/dist/app-header.js +74 -0
- package/dist/app-header.js.map +1 -0
- package/dist/cli.js +81 -59
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/dump/collector.d.ts +2 -1
- package/dist/dump/collector.d.ts.map +1 -1
- package/dist/dump/collector.js +1 -0
- package/dist/dump/collector.js.map +1 -1
- package/dist/dump/hotkey.d.ts +9 -30
- package/dist/dump/hotkey.d.ts.map +1 -1
- package/dist/dump/hotkey.js +15 -158
- package/dist/dump/hotkey.js.map +1 -1
- package/dist/dump/service.d.ts +3 -2
- package/dist/dump/service.d.ts.map +1 -1
- package/dist/dump/service.js +4 -1
- package/dist/dump/service.js.map +1 -1
- package/dist/dump/types.d.ts +5 -0
- package/dist/dump/types.d.ts.map +1 -1
- package/dist/flow/built-in/default-factory.d.ts +21 -0
- package/dist/flow/built-in/default-factory.d.ts.map +1 -0
- package/dist/flow/built-in/default-factory.js +155 -0
- package/dist/flow/built-in/default-factory.js.map +1 -0
- package/dist/flow/built-in/default.d.ts +4 -4
- package/dist/flow/built-in/default.d.ts.map +1 -1
- package/dist/flow/built-in/default.js +3 -141
- package/dist/flow/built-in/default.js.map +1 -1
- package/dist/flow/built-in/default.ts +5 -169
- package/dist/flow/built-in/why-so-serious-factory.d.ts +16 -0
- package/dist/flow/built-in/why-so-serious-factory.d.ts.map +1 -0
- package/dist/flow/built-in/why-so-serious-factory.js +187 -0
- package/dist/flow/built-in/why-so-serious-factory.js.map +1 -0
- package/dist/flow/built-in/why-so-serious.d.ts +3 -2
- package/dist/flow/built-in/why-so-serious.d.ts.map +1 -1
- package/dist/flow/built-in/why-so-serious.js +3 -164
- package/dist/flow/built-in/why-so-serious.js.map +1 -1
- package/dist/flow/custom/AUTHORING.md +13 -0
- package/dist/flow/custom/load.d.ts +16 -1
- package/dist/flow/custom/load.d.ts.map +1 -1
- package/dist/flow/custom/load.js +69 -18
- package/dist/flow/custom/load.js.map +1 -1
- package/dist/flow/dsl.js +1 -1
- package/dist/flow/dsl.js.map +1 -1
- package/dist/flow/executor.d.ts.map +1 -1
- package/dist/flow/executor.js +44 -8
- package/dist/flow/executor.js.map +1 -1
- package/dist/flow/types.d.ts +20 -2
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/flow/types.js.map +1 -1
- package/dist/flow-editor/tui.d.ts.map +1 -1
- package/dist/flow-editor/tui.js +9 -18
- package/dist/flow-editor/tui.js.map +1 -1
- package/dist/orchestrator.d.ts +43 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +230 -92
- package/dist/orchestrator.js.map +1 -1
- package/dist/providers/claude/completion-plan-mode.d.ts.map +1 -1
- package/dist/providers/claude/completion-plan-mode.js +5 -2
- package/dist/providers/claude/completion-plan-mode.js.map +1 -1
- package/dist/providers/claude/tool-tracking.d.ts +1 -0
- package/dist/providers/claude/tool-tracking.d.ts.map +1 -1
- package/dist/providers/claude/tool-tracking.js +3 -0
- package/dist/providers/claude/tool-tracking.js.map +1 -1
- package/dist/pty/spawn.d.ts.map +1 -1
- package/dist/pty/spawn.js +6 -1
- package/dist/pty/spawn.js.map +1 -1
- package/dist/pty/types.d.ts +7 -2
- package/dist/pty/types.d.ts.map +1 -1
- package/dist/resume-tui.d.ts +52 -0
- package/dist/resume-tui.d.ts.map +1 -0
- package/dist/resume-tui.js +344 -0
- package/dist/resume-tui.js.map +1 -0
- package/dist/session/flow-snapshot.d.ts +14 -0
- package/dist/session/flow-snapshot.d.ts.map +1 -0
- package/dist/session/flow-snapshot.js +28 -0
- package/dist/session/flow-snapshot.js.map +1 -0
- package/dist/session/list.d.ts +16 -0
- package/dist/session/list.d.ts.map +1 -0
- package/dist/session/list.js +89 -0
- package/dist/session/list.js.map +1 -0
- package/dist/session/lock.d.ts +26 -0
- package/dist/session/lock.d.ts.map +1 -0
- package/dist/session/lock.js +95 -0
- package/dist/session/lock.js.map +1 -0
- package/dist/session/manifest.d.ts +80 -0
- package/dist/session/manifest.d.ts.map +1 -0
- package/dist/session/manifest.js +2 -0
- package/dist/session/manifest.js.map +1 -0
- package/dist/session/persistence.d.ts +19 -0
- package/dist/session/persistence.d.ts.map +1 -0
- package/dist/session/persistence.js +68 -0
- package/dist/session/persistence.js.map +1 -0
- package/dist/session/process-start-time.d.ts +17 -0
- package/dist/session/process-start-time.d.ts.map +1 -0
- package/dist/session/process-start-time.js +99 -0
- package/dist/session/process-start-time.js.map +1 -0
- package/dist/session/restore.d.ts +31 -0
- package/dist/session/restore.d.ts.map +1 -0
- package/dist/session/restore.js +111 -0
- package/dist/session/restore.js.map +1 -0
- package/dist/session/resume.d.ts +5 -0
- package/dist/session/resume.d.ts.map +1 -0
- package/dist/session/resume.js +109 -0
- package/dist/session/resume.js.map +1 -0
- package/dist/session/session-store.d.ts +43 -0
- package/dist/session/session-store.d.ts.map +1 -0
- package/dist/session/session-store.js +134 -0
- package/dist/session/session-store.js.map +1 -0
- package/dist/startup-tui.d.ts +10 -11
- package/dist/startup-tui.d.ts.map +1 -1
- package/dist/startup-tui.js +25 -108
- package/dist/startup-tui.js.map +1 -1
- package/dist/status-bar.js +1 -26
- package/dist/status-bar.js.map +1 -1
- package/dist/terminal/host.d.ts +22 -9
- package/dist/terminal/host.d.ts.map +1 -1
- package/dist/terminal/host.js +67 -78
- package/dist/terminal/host.js.map +1 -1
- package/dist/terminal/input-router.d.ts +24 -103
- package/dist/terminal/input-router.d.ts.map +1 -1
- package/dist/terminal/input-router.js +63 -364
- package/dist/terminal/input-router.js.map +1 -1
- package/dist/terminal/key-event-source.d.ts +52 -0
- package/dist/terminal/key-event-source.d.ts.map +1 -0
- package/dist/terminal/key-event-source.js +31 -0
- package/dist/terminal/key-event-source.js.map +1 -0
- package/dist/terminal/key-to-bytes.d.ts +11 -0
- package/dist/terminal/key-to-bytes.d.ts.map +1 -0
- package/dist/terminal/key-to-bytes.js +81 -0
- package/dist/terminal/key-to-bytes.js.map +1 -0
- package/dist/terminal/koffi-loader.d.ts +14 -0
- package/dist/terminal/koffi-loader.d.ts.map +1 -1
- package/dist/terminal/koffi-loader.js.map +1 -1
- package/dist/terminal/render.d.ts +1 -2
- package/dist/terminal/render.d.ts.map +1 -1
- package/dist/terminal/render.js +1 -30
- package/dist/terminal/render.js.map +1 -1
- package/dist/terminal/stdin-byte-source.d.ts +27 -0
- package/dist/terminal/stdin-byte-source.d.ts.map +1 -0
- package/dist/terminal/stdin-byte-source.js +92 -0
- package/dist/terminal/stdin-byte-source.js.map +1 -0
- package/dist/terminal/win32-console-mode.d.ts.map +1 -1
- package/dist/terminal/win32-console-mode.js.map +1 -1
- package/dist/terminal/win32-console-source.d.ts +26 -0
- package/dist/terminal/win32-console-source.d.ts.map +1 -0
- package/dist/terminal/win32-console-source.js +275 -0
- package/dist/terminal/win32-console-source.js.map +1 -0
- package/dist/terminal/win32-key-translator.d.ts +26 -0
- package/dist/terminal/win32-key-translator.d.ts.map +1 -0
- package/dist/terminal/win32-key-translator.js +87 -0
- package/dist/terminal/win32-key-translator.js.map +1 -0
- package/dist/terminal-input.d.ts +10 -0
- package/dist/terminal-input.d.ts.map +1 -1
- package/dist/terminal-input.js +132 -113
- package/dist/terminal-input.js.map +1 -1
- package/dist/user/host-curate-prompt.d.ts +2 -1
- package/dist/user/host-curate-prompt.d.ts.map +1 -1
- package/dist/user/host-curate-prompt.js +13 -11
- package/dist/user/host-curate-prompt.js.map +1 -1
- package/dist/user/host-prompt.d.ts +4 -1
- package/dist/user/host-prompt.d.ts.map +1 -1
- package/dist/user/host-prompt.js +24 -6
- package/dist/user/host-prompt.js.map +1 -1
- package/dist/user/prompt.d.ts +7 -9
- package/dist/user/prompt.d.ts.map +1 -1
- package/dist/user/prompt.js +14 -23
- package/dist/user/prompt.js.map +1 -1
- 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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"}
|
package/dist/startup-tui.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
37
|
-
*
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAmC,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"startup-tui.d.ts","sourceRoot":"","sources":["../src/startup-tui.ts"],"names":[],"mappings":"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"}
|
package/dist/startup-tui.js
CHANGED
|
@@ -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 {
|
|
5
|
-
import {
|
|
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
|
-
*
|
|
23
|
-
*
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
496
|
-
|
|
431
|
+
const source = createKeyEventSource();
|
|
432
|
+
source.start();
|
|
497
433
|
return new Promise((resolve) => {
|
|
498
|
-
|
|
499
|
-
for (const event of
|
|
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
|
-
|
|
540
|
-
|
|
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
|
}
|