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,52 @@
|
|
|
1
|
+
import { type TuiInputEvent } from "./startup-tui.js";
|
|
2
|
+
import type { SessionDescriptor } from "./session/manifest.js";
|
|
3
|
+
import { type GitInfo } from "./git-info.js";
|
|
4
|
+
import { type UpdateInfo } from "./update-check.js";
|
|
5
|
+
export type ResumeChoice = {
|
|
6
|
+
mode: "resume";
|
|
7
|
+
session: SessionDescriptor;
|
|
8
|
+
} | {
|
|
9
|
+
mode: "new";
|
|
10
|
+
};
|
|
11
|
+
export interface ResumePickerOpts {
|
|
12
|
+
/** When true, the "Start new session" pseudo-row is preselected. */
|
|
13
|
+
preferNew?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ResumeTuiState {
|
|
16
|
+
sessions: SessionDescriptor[];
|
|
17
|
+
selectedIndex: number;
|
|
18
|
+
confirmDiscardFor: string | null;
|
|
19
|
+
errorMessage: string | null;
|
|
20
|
+
termRows: number;
|
|
21
|
+
termCols: number;
|
|
22
|
+
gitInfo: GitInfo | null;
|
|
23
|
+
updateBanner: UpdateInfo | null;
|
|
24
|
+
/**
|
|
25
|
+
* Last frame written to the terminal — used by `render` to dedupe identical
|
|
26
|
+
* paints. Scoped to state so each `showResumePicker` invocation starts fresh.
|
|
27
|
+
*/
|
|
28
|
+
lastDrawnOutput?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function buildInitialState(sessions: SessionDescriptor[], opts: ResumePickerOpts, rows: number, cols: number, gitInfo?: GitInfo | null): ResumeTuiState;
|
|
31
|
+
export declare function render(state: ResumeTuiState, out: NodeJS.WriteStream): void;
|
|
32
|
+
export type ResumeHandleResult = {
|
|
33
|
+
kind: "handled";
|
|
34
|
+
} | {
|
|
35
|
+
kind: "resume";
|
|
36
|
+
session: SessionDescriptor;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "new";
|
|
39
|
+
} | {
|
|
40
|
+
kind: "cancel";
|
|
41
|
+
};
|
|
42
|
+
export declare function handleEvent(state: ResumeTuiState, event: TuiInputEvent): Promise<ResumeHandleResult>;
|
|
43
|
+
export declare function showResumePicker(sessions: SessionDescriptor[], opts?: ResumePickerOpts, cwd?: string): Promise<ResumeChoice | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Reconcile fresh `listResumableSessions` output into `state.sessions`.
|
|
46
|
+
*
|
|
47
|
+
* Preserves in-memory row positions so a row's lock indicator can
|
|
48
|
+
* appear/disappear without the list visually jumping. Selection sticks to
|
|
49
|
+
* the same `sessionId` when possible.
|
|
50
|
+
*/
|
|
51
|
+
export declare function reconcileSessions(state: ResumeTuiState, fresh: SessionDescriptor[]): void;
|
|
52
|
+
//# sourceMappingURL=resume-tui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume-tui.d.ts","sourceRoot":"","sources":["../src/resume-tui.ts"],"names":[],"mappings":"AAKA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpE,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAEpB,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,GACvB,cAAc,CAYhB;AA0CD,wBAAgB,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,CAAC,WAAW,GAAG,IAAI,CA0E3E;AAID,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvB,wBAAsB,WAAW,CAC/B,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,kBAAkB,CAAC,CA6E7B;AAID,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,IAAI,GAAE,gBAAqB,EAC3B,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAuB9B;AAID;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,iBAAiB,EAAE,GACzB,IAAI,CAsCN"}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { visibleLength, padToWidth, bold, dim, reset, cyan, green, red, HIDE_CURSOR, ALT_SCREEN_ON, ALT_SCREEN_OFF, CSI, } from "./ansi.js";
|
|
2
|
+
import { TuiInputParser } from "./startup-tui.js";
|
|
3
|
+
import { createKeyEventSource } from "./terminal/key-event-source.js";
|
|
4
|
+
import { discardSession, listResumableSessions } from "./session/list.js";
|
|
5
|
+
import { getGitInfo } from "./git-info.js";
|
|
6
|
+
import { checkForUpdate } from "./update-check.js";
|
|
7
|
+
import { renderAppHeader, tildeify } from "./app-header.js";
|
|
8
|
+
// ─── State construction ──────────────────────────────────────────────
|
|
9
|
+
export function buildInitialState(sessions, opts, rows, cols, gitInfo) {
|
|
10
|
+
const newRowIndex = sessions.length;
|
|
11
|
+
return {
|
|
12
|
+
sessions,
|
|
13
|
+
selectedIndex: opts.preferNew ? newRowIndex : 0,
|
|
14
|
+
confirmDiscardFor: null,
|
|
15
|
+
errorMessage: null,
|
|
16
|
+
termRows: rows,
|
|
17
|
+
termCols: cols,
|
|
18
|
+
gitInfo: gitInfo ?? null,
|
|
19
|
+
updateBanner: null,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// ─── Helpers ─────────────────────────────────────────────────────────
|
|
23
|
+
function ageString(iso) {
|
|
24
|
+
const then = Date.parse(iso);
|
|
25
|
+
if (!Number.isFinite(then))
|
|
26
|
+
return "unknown";
|
|
27
|
+
const diffMs = Date.now() - then;
|
|
28
|
+
const s = Math.max(0, Math.floor(diffMs / 1000));
|
|
29
|
+
if (s < 60)
|
|
30
|
+
return `${s}s ago`;
|
|
31
|
+
const m = Math.floor(s / 60);
|
|
32
|
+
if (m < 60)
|
|
33
|
+
return `${m}m ago`;
|
|
34
|
+
const h = Math.floor(m / 60);
|
|
35
|
+
if (h < 24)
|
|
36
|
+
return `${h}h ago`;
|
|
37
|
+
const d = Math.floor(h / 24);
|
|
38
|
+
return `${d}d ago`;
|
|
39
|
+
}
|
|
40
|
+
function previewTask(text, max = 60) {
|
|
41
|
+
const oneLine = text
|
|
42
|
+
.replace(/\s*\n[\s]*/g, " ↵ ")
|
|
43
|
+
.replace(/\s+/g, " ")
|
|
44
|
+
.trim();
|
|
45
|
+
if (oneLine.length <= max)
|
|
46
|
+
return oneLine;
|
|
47
|
+
return oneLine.slice(0, max - 1) + "…";
|
|
48
|
+
}
|
|
49
|
+
function truncToCols(text, cols) {
|
|
50
|
+
if (visibleLength(text) <= cols)
|
|
51
|
+
return text;
|
|
52
|
+
// Best-effort truncate by visible characters (ignores ANSI codes width)
|
|
53
|
+
let out = "";
|
|
54
|
+
let vis = 0;
|
|
55
|
+
for (const ch of text) {
|
|
56
|
+
if (vis >= cols - 1)
|
|
57
|
+
break;
|
|
58
|
+
out += ch;
|
|
59
|
+
vis++;
|
|
60
|
+
}
|
|
61
|
+
return out + "…";
|
|
62
|
+
}
|
|
63
|
+
// ─── Rendering ───────────────────────────────────────────────────────
|
|
64
|
+
export function render(state, out) {
|
|
65
|
+
const cols = state.termCols;
|
|
66
|
+
const lines = [];
|
|
67
|
+
const pad = (s) => padToWidth(s, cols);
|
|
68
|
+
// Header
|
|
69
|
+
lines.push(...renderAppHeader(cols, state.gitInfo, state.updateBanner));
|
|
70
|
+
const sharedWorkdir = state.sessions[0]?.manifest.workdir;
|
|
71
|
+
if (sharedWorkdir) {
|
|
72
|
+
lines.push(pad(` ${tildeify(sharedWorkdir)}`));
|
|
73
|
+
}
|
|
74
|
+
lines.push(pad(` ${dim}Found ${state.sessions.length} resumable session${state.sessions.length === 1 ? "" : "s"}.${reset}`));
|
|
75
|
+
lines.push(pad(""));
|
|
76
|
+
// Session rows
|
|
77
|
+
state.sessions.forEach((session, idx) => {
|
|
78
|
+
const selected = idx === state.selectedIndex;
|
|
79
|
+
const marker = selected ? `${cyan}▸${reset}` : " ";
|
|
80
|
+
const m = session.manifest;
|
|
81
|
+
const taskPreview = previewTask(m.taskText);
|
|
82
|
+
const age = ageString(m.lastActivityAt);
|
|
83
|
+
const stepLabel = session.lastStepLabel ?? "waiting on first step";
|
|
84
|
+
// Locked rows render with a dim title even when selected, so it's
|
|
85
|
+
// visually obvious they cannot be acted on.
|
|
86
|
+
const titleStyle = (selected && !session.lock) ? `${bold}${green}` : dim;
|
|
87
|
+
const titleText = ` ${marker} ${titleStyle}${taskPreview || "(no task)"}${reset}`;
|
|
88
|
+
lines.push(pad(truncToCols(titleText, cols)));
|
|
89
|
+
const subParts = [];
|
|
90
|
+
subParts.push(`${dim}flow:${reset} ${m.flow.name}`);
|
|
91
|
+
subParts.push(`${dim}last:${reset} ${stepLabel}`);
|
|
92
|
+
subParts.push(`${dim}${age}${reset}`);
|
|
93
|
+
const subtitle = ` ${subParts.join(" ")}`;
|
|
94
|
+
lines.push(pad(truncToCols(subtitle, cols)));
|
|
95
|
+
if (!session.workdirExists) {
|
|
96
|
+
lines.push(pad(` ${red}[workdir missing — discard or recreate]${reset}`));
|
|
97
|
+
}
|
|
98
|
+
if (session.lock) {
|
|
99
|
+
const lockColor = selected ? red : dim;
|
|
100
|
+
lines.push(pad(` ${lockColor}[locked — running since ${ageString(session.lock.startedAt)}]${reset}`));
|
|
101
|
+
}
|
|
102
|
+
if (selected && state.confirmDiscardFor === session.sessionId) {
|
|
103
|
+
lines.push(pad(` ${red}${bold}Press d again to discard, any other key cancels${reset}`));
|
|
104
|
+
}
|
|
105
|
+
lines.push(pad(""));
|
|
106
|
+
});
|
|
107
|
+
// "Start new session" pseudo-row
|
|
108
|
+
const newIdx = state.sessions.length;
|
|
109
|
+
const newSelected = state.selectedIndex === newIdx;
|
|
110
|
+
const newMarker = newSelected ? `${cyan}▸${reset}` : " ";
|
|
111
|
+
const newStyle = newSelected ? `${bold}${green}` : bold;
|
|
112
|
+
lines.push(pad(` ${newMarker} ${newStyle}Start a new session${reset}`));
|
|
113
|
+
lines.push(pad(""));
|
|
114
|
+
if (state.errorMessage) {
|
|
115
|
+
lines.push(pad(` ${red}${state.errorMessage}${reset}`));
|
|
116
|
+
lines.push(pad(""));
|
|
117
|
+
}
|
|
118
|
+
// Footer
|
|
119
|
+
const footer = ` ${dim}↑↓${reset} Navigate ${dim}Enter${reset} Select ${dim}n${reset} New ${dim}d${reset} Discard ${dim}Esc${reset} Quit`;
|
|
120
|
+
lines.push(pad(footer));
|
|
121
|
+
const output = HIDE_CURSOR + `${CSI}H` + lines.join("\n") + `${CSI}J`;
|
|
122
|
+
if (output !== state.lastDrawnOutput) {
|
|
123
|
+
state.lastDrawnOutput = output;
|
|
124
|
+
out.write(output);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export async function handleEvent(state, event) {
|
|
128
|
+
if (event.type === "ctrl+c" || event.type === "escape") {
|
|
129
|
+
return { kind: "cancel" };
|
|
130
|
+
}
|
|
131
|
+
const lastIdx = state.sessions.length; // "new" row
|
|
132
|
+
const selectedSession = state.sessions[state.selectedIndex];
|
|
133
|
+
// Discard confirmation flow
|
|
134
|
+
if (state.confirmDiscardFor) {
|
|
135
|
+
if (event.type === "insert" && event.text === "d" && selectedSession?.sessionId === state.confirmDiscardFor) {
|
|
136
|
+
// Race-safety: a periodic refresh may have promoted this row to
|
|
137
|
+
// locked between the first and second `d`. Refuse the discard.
|
|
138
|
+
if (selectedSession.lock) {
|
|
139
|
+
state.confirmDiscardFor = null;
|
|
140
|
+
state.errorMessage = "Session is locked by another running poly-weaver process — cannot discard.";
|
|
141
|
+
return { kind: "handled" };
|
|
142
|
+
}
|
|
143
|
+
const target = selectedSession;
|
|
144
|
+
try {
|
|
145
|
+
await discardSession(target.persistentDir);
|
|
146
|
+
state.sessions = state.sessions.filter(s => s.sessionId !== target.sessionId);
|
|
147
|
+
if (state.selectedIndex >= state.sessions.length) {
|
|
148
|
+
state.selectedIndex = state.sessions.length; // land on "new" row
|
|
149
|
+
}
|
|
150
|
+
state.confirmDiscardFor = null;
|
|
151
|
+
state.errorMessage = null;
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
state.errorMessage = `Failed to discard: ${err instanceof Error ? err.message : err}`;
|
|
155
|
+
state.confirmDiscardFor = null;
|
|
156
|
+
}
|
|
157
|
+
return { kind: "handled" };
|
|
158
|
+
}
|
|
159
|
+
// Any other key cancels the armed state.
|
|
160
|
+
state.confirmDiscardFor = null;
|
|
161
|
+
return { kind: "handled" };
|
|
162
|
+
}
|
|
163
|
+
if (event.type === "up") {
|
|
164
|
+
if (state.selectedIndex > 0)
|
|
165
|
+
state.selectedIndex--;
|
|
166
|
+
state.errorMessage = null;
|
|
167
|
+
return { kind: "handled" };
|
|
168
|
+
}
|
|
169
|
+
if (event.type === "down") {
|
|
170
|
+
if (state.selectedIndex < lastIdx)
|
|
171
|
+
state.selectedIndex++;
|
|
172
|
+
state.errorMessage = null;
|
|
173
|
+
return { kind: "handled" };
|
|
174
|
+
}
|
|
175
|
+
if (event.type === "submit") {
|
|
176
|
+
if (state.selectedIndex === lastIdx)
|
|
177
|
+
return { kind: "new" };
|
|
178
|
+
if (selectedSession) {
|
|
179
|
+
if (selectedSession.lock) {
|
|
180
|
+
state.errorMessage = "Session is locked by another running poly-weaver process — wait for it to exit or pick another.";
|
|
181
|
+
return { kind: "handled" };
|
|
182
|
+
}
|
|
183
|
+
if (!selectedSession.workdirExists) {
|
|
184
|
+
state.errorMessage = "Workdir missing — discard the session or recreate the directory.";
|
|
185
|
+
return { kind: "handled" };
|
|
186
|
+
}
|
|
187
|
+
return { kind: "resume", session: selectedSession };
|
|
188
|
+
}
|
|
189
|
+
return { kind: "handled" };
|
|
190
|
+
}
|
|
191
|
+
if (event.type === "insert" && event.text === "n") {
|
|
192
|
+
return { kind: "new" };
|
|
193
|
+
}
|
|
194
|
+
if (event.type === "insert" && event.text === "d") {
|
|
195
|
+
if (selectedSession) {
|
|
196
|
+
if (selectedSession.lock) {
|
|
197
|
+
state.errorMessage = "Session is locked by another running poly-weaver process — cannot discard.";
|
|
198
|
+
return { kind: "handled" };
|
|
199
|
+
}
|
|
200
|
+
state.confirmDiscardFor = selectedSession.sessionId;
|
|
201
|
+
}
|
|
202
|
+
return { kind: "handled" };
|
|
203
|
+
}
|
|
204
|
+
return { kind: "handled" };
|
|
205
|
+
}
|
|
206
|
+
// ─── Main entry point ────────────────────────────────────────────────
|
|
207
|
+
export async function showResumePicker(sessions, opts = {}, cwd) {
|
|
208
|
+
const rows = process.stdout.rows ?? 24;
|
|
209
|
+
const cols = process.stdout.columns ?? 80;
|
|
210
|
+
const gitInfo = await getGitInfo(cwd ?? process.cwd());
|
|
211
|
+
const state = buildInitialState(sessions, opts, rows, cols, gitInfo);
|
|
212
|
+
process.stdout.write(ALT_SCREEN_ON);
|
|
213
|
+
let disposed = false;
|
|
214
|
+
void checkForUpdate().then((result) => {
|
|
215
|
+
if (disposed || !result)
|
|
216
|
+
return;
|
|
217
|
+
state.updateBanner = result;
|
|
218
|
+
state.lastDrawnOutput = undefined;
|
|
219
|
+
render(state, process.stdout);
|
|
220
|
+
});
|
|
221
|
+
try {
|
|
222
|
+
render(state, process.stdout);
|
|
223
|
+
return await inputLoop(state, cwd);
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
disposed = true;
|
|
227
|
+
process.stdout.write(ALT_SCREEN_OFF);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const REFRESH_INTERVAL_MS = 2000;
|
|
231
|
+
/**
|
|
232
|
+
* Reconcile fresh `listResumableSessions` output into `state.sessions`.
|
|
233
|
+
*
|
|
234
|
+
* Preserves in-memory row positions so a row's lock indicator can
|
|
235
|
+
* appear/disappear without the list visually jumping. Selection sticks to
|
|
236
|
+
* the same `sessionId` when possible.
|
|
237
|
+
*/
|
|
238
|
+
export function reconcileSessions(state, fresh) {
|
|
239
|
+
const freshById = new Map(fresh.map(s => [s.sessionId, s]));
|
|
240
|
+
const previousSelectedId = state.sessions[state.selectedIndex]?.sessionId;
|
|
241
|
+
// Drop sessions no longer in the fresh list; replace mutable fields on the rest.
|
|
242
|
+
const kept = [];
|
|
243
|
+
for (const existing of state.sessions) {
|
|
244
|
+
const updated = freshById.get(existing.sessionId);
|
|
245
|
+
if (!updated)
|
|
246
|
+
continue;
|
|
247
|
+
kept.push({
|
|
248
|
+
...existing,
|
|
249
|
+
lastStepLabel: updated.lastStepLabel,
|
|
250
|
+
workdirExists: updated.workdirExists,
|
|
251
|
+
manifest: updated.manifest,
|
|
252
|
+
lock: updated.lock,
|
|
253
|
+
});
|
|
254
|
+
freshById.delete(existing.sessionId);
|
|
255
|
+
}
|
|
256
|
+
// Append any genuinely new sessions at the bottom.
|
|
257
|
+
for (const fresh of freshById.values())
|
|
258
|
+
kept.push(fresh);
|
|
259
|
+
state.sessions = kept;
|
|
260
|
+
// Reposition the selection to the same sessionId if it still exists.
|
|
261
|
+
const newSelectedIdx = previousSelectedId
|
|
262
|
+
? kept.findIndex(s => s.sessionId === previousSelectedId)
|
|
263
|
+
: -1;
|
|
264
|
+
if (newSelectedIdx >= 0) {
|
|
265
|
+
state.selectedIndex = newSelectedIdx;
|
|
266
|
+
}
|
|
267
|
+
else if (state.selectedIndex > kept.length) {
|
|
268
|
+
state.selectedIndex = kept.length;
|
|
269
|
+
}
|
|
270
|
+
// Discard arming if the armed session is gone or now locked.
|
|
271
|
+
if (state.confirmDiscardFor) {
|
|
272
|
+
const armed = kept.find(s => s.sessionId === state.confirmDiscardFor);
|
|
273
|
+
if (!armed || armed.lock)
|
|
274
|
+
state.confirmDiscardFor = null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
async function inputLoop(state, workdir) {
|
|
278
|
+
const parser = new TuiInputParser();
|
|
279
|
+
const source = createKeyEventSource();
|
|
280
|
+
source.start();
|
|
281
|
+
return new Promise((resolve) => {
|
|
282
|
+
const handleResult = async (events) => {
|
|
283
|
+
for (const event of events) {
|
|
284
|
+
const result = await handleEvent(state, event);
|
|
285
|
+
switch (result.kind) {
|
|
286
|
+
case "resume":
|
|
287
|
+
cleanup();
|
|
288
|
+
resolve({ mode: "resume", session: result.session });
|
|
289
|
+
return true;
|
|
290
|
+
case "new":
|
|
291
|
+
cleanup();
|
|
292
|
+
resolve({ mode: "new" });
|
|
293
|
+
return true;
|
|
294
|
+
case "cancel":
|
|
295
|
+
cleanup();
|
|
296
|
+
resolve(null);
|
|
297
|
+
return true;
|
|
298
|
+
case "handled":
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
render(state, process.stdout);
|
|
303
|
+
return false;
|
|
304
|
+
};
|
|
305
|
+
const unsubscribe = source.onEvents((keys) => {
|
|
306
|
+
void handleResult(parser.mapKeys(keys));
|
|
307
|
+
});
|
|
308
|
+
const onResize = () => {
|
|
309
|
+
state.termRows = process.stdout.rows ?? 24;
|
|
310
|
+
state.termCols = process.stdout.columns ?? 80;
|
|
311
|
+
state.lastDrawnOutput = undefined;
|
|
312
|
+
render(state, process.stdout);
|
|
313
|
+
};
|
|
314
|
+
process.stdout.on("resize", onResize);
|
|
315
|
+
// Periodic refresh — surfaces lock transitions while the picker is open.
|
|
316
|
+
let refreshing = false;
|
|
317
|
+
const refreshTimer = setInterval(() => {
|
|
318
|
+
if (refreshing)
|
|
319
|
+
return;
|
|
320
|
+
refreshing = true;
|
|
321
|
+
(async () => {
|
|
322
|
+
try {
|
|
323
|
+
const fresh = await listResumableSessions(workdir);
|
|
324
|
+
reconcileSessions(state, fresh);
|
|
325
|
+
render(state, process.stdout);
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
/* refresh failures are non-fatal */
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
refreshing = false;
|
|
332
|
+
}
|
|
333
|
+
})();
|
|
334
|
+
}, REFRESH_INTERVAL_MS);
|
|
335
|
+
refreshTimer.unref?.();
|
|
336
|
+
function cleanup() {
|
|
337
|
+
clearInterval(refreshTimer);
|
|
338
|
+
unsubscribe();
|
|
339
|
+
source.stop();
|
|
340
|
+
process.stdout.removeListener("resize", onResize);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=resume-tui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume-tui.js","sourceRoot":"","sources":["../src/resume-tui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FlowTemplate } from "../flow/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Copy the flow's source factory file into the persistent session dir.
|
|
4
|
+
* The filename ends with `.mjs` so dynamic-import treats it as an ESM
|
|
5
|
+
* module regardless of any nearby `package.json` "type" field.
|
|
6
|
+
*/
|
|
7
|
+
export declare function captureFlowSnapshot(sourceFile: string, persistentDir: string): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Dynamic-import the saved flow source and invoke its default factory
|
|
10
|
+
* with the current DSL. The flow's *logic* is frozen at save time;
|
|
11
|
+
* DSL primitives come from the running poly-weaver.
|
|
12
|
+
*/
|
|
13
|
+
export declare function rehydrateFlow(persistentDir: string): Promise<FlowTemplate>;
|
|
14
|
+
//# sourceMappingURL=flow-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-snapshot.d.ts","sourceRoot":"","sources":["../../src/session/flow-snapshot.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAUhF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { copyFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { flowDSL } from "../dsl.js";
|
|
5
|
+
const SNAPSHOT_FILENAME = "flow-source.mjs";
|
|
6
|
+
/**
|
|
7
|
+
* Copy the flow's source factory file into the persistent session dir.
|
|
8
|
+
* The filename ends with `.mjs` so dynamic-import treats it as an ESM
|
|
9
|
+
* module regardless of any nearby `package.json` "type" field.
|
|
10
|
+
*/
|
|
11
|
+
export async function captureFlowSnapshot(sourceFile, persistentDir) {
|
|
12
|
+
await copyFile(sourceFile, join(persistentDir, SNAPSHOT_FILENAME));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Dynamic-import the saved flow source and invoke its default factory
|
|
16
|
+
* with the current DSL. The flow's *logic* is frozen at save time;
|
|
17
|
+
* DSL primitives come from the running poly-weaver.
|
|
18
|
+
*/
|
|
19
|
+
export async function rehydrateFlow(persistentDir) {
|
|
20
|
+
const url = pathToFileURL(join(persistentDir, SNAPSHOT_FILENAME)).href;
|
|
21
|
+
const mod = await import(url);
|
|
22
|
+
const factory = mod.default;
|
|
23
|
+
if (typeof factory !== "function") {
|
|
24
|
+
throw new Error(`Restored flow snapshot at ${persistentDir}/${SNAPSHOT_FILENAME} has no default-export factory function`);
|
|
25
|
+
}
|
|
26
|
+
return factory(flowDSL);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=flow-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-snapshot.js","sourceRoot":"","sources":["../../src/session/flow-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAE5C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,UAAkB,EAClB,aAAqB;IAErB,MAAM,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,aAAqB;IACvD,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC5B,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CACb,6BAA6B,aAAa,IAAI,iBAAiB,yCAAyC,CACzG,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAiB,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SessionDescriptor } from "./manifest.js";
|
|
2
|
+
/**
|
|
3
|
+
* Walk the sessions dir, return descriptors sorted by `lastActivityAt` desc.
|
|
4
|
+
*
|
|
5
|
+
* Side effects:
|
|
6
|
+
* - Drops `status: "complete"` sessions from the result.
|
|
7
|
+
* - Annotates live-locked sessions with a `lock` field (the picker
|
|
8
|
+
* disables Enter / discard on those rows).
|
|
9
|
+
* - Deletes (>7d stale) sessions in place.
|
|
10
|
+
*
|
|
11
|
+
* When `cwd` is provided, returns only sessions whose manifest `workdir`
|
|
12
|
+
* matches exactly (case-insensitive on win32).
|
|
13
|
+
*/
|
|
14
|
+
export declare function listResumableSessions(cwd?: string): Promise<SessionDescriptor[]>;
|
|
15
|
+
export declare function discardSession(persistentDir: string): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/session/list.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAqC,MAAM,eAAe,CAAC;AAO1F;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA0BtF;AAgDD,wBAAsB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzE"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { readdir, rm } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { getSessionsDir } from "../config.js";
|
|
4
|
+
import { dirExists, readJsonIfExists, stepFilename } from "./persistence.js";
|
|
5
|
+
import { readLiveLockSummary } from "./lock.js";
|
|
6
|
+
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
7
|
+
const normalizeForCompare = (p) => process.platform === "win32" ? resolve(p).toLowerCase() : resolve(p);
|
|
8
|
+
/**
|
|
9
|
+
* Walk the sessions dir, return descriptors sorted by `lastActivityAt` desc.
|
|
10
|
+
*
|
|
11
|
+
* Side effects:
|
|
12
|
+
* - Drops `status: "complete"` sessions from the result.
|
|
13
|
+
* - Annotates live-locked sessions with a `lock` field (the picker
|
|
14
|
+
* disables Enter / discard on those rows).
|
|
15
|
+
* - Deletes (>7d stale) sessions in place.
|
|
16
|
+
*
|
|
17
|
+
* When `cwd` is provided, returns only sessions whose manifest `workdir`
|
|
18
|
+
* matches exactly (case-insensitive on win32).
|
|
19
|
+
*/
|
|
20
|
+
export async function listResumableSessions(cwd) {
|
|
21
|
+
const sessionsDir = getSessionsDir();
|
|
22
|
+
let entries;
|
|
23
|
+
try {
|
|
24
|
+
entries = await readdir(sessionsDir);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
if (err.code === "ENOENT")
|
|
28
|
+
return [];
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
const normalizedFilterCwd = cwd === undefined ? undefined : normalizeForCompare(cwd);
|
|
33
|
+
const descriptors = (await Promise.all(entries.map((entry) => loadDescriptor(join(sessionsDir, entry), now, normalizedFilterCwd)))).filter((d) => d !== undefined);
|
|
34
|
+
descriptors.sort((a, b) => Date.parse(b.manifest.lastActivityAt) - Date.parse(a.manifest.lastActivityAt));
|
|
35
|
+
return descriptors;
|
|
36
|
+
}
|
|
37
|
+
async function loadDescriptor(persistentDir, now, normalizedFilterCwd) {
|
|
38
|
+
try {
|
|
39
|
+
const manifest = await readJsonIfExists(join(persistentDir, "manifest.json"));
|
|
40
|
+
if (!manifest)
|
|
41
|
+
return undefined;
|
|
42
|
+
const lastActivity = Date.parse(manifest.lastActivityAt);
|
|
43
|
+
if (Number.isFinite(lastActivity) && now - lastActivity > SEVEN_DAYS_MS) {
|
|
44
|
+
await rm(persistentDir, { recursive: true, force: true }).catch(() => { });
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
if (manifest.status === "complete")
|
|
48
|
+
return undefined;
|
|
49
|
+
if (normalizedFilterCwd !== undefined &&
|
|
50
|
+
normalizeForCompare(manifest.workdir) !== normalizedFilterCwd) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const [lockSummary, workdirExists, lastStepLabel] = await Promise.all([
|
|
54
|
+
readLiveLockSummary(persistentDir, manifest.createdAt),
|
|
55
|
+
dirExists(manifest.workdir),
|
|
56
|
+
readLastStepLabel(persistentDir, manifest.lastCompletedSeq),
|
|
57
|
+
]);
|
|
58
|
+
const descriptor = {
|
|
59
|
+
sessionId: manifest.sessionId,
|
|
60
|
+
persistentDir,
|
|
61
|
+
manifest,
|
|
62
|
+
workdirExists,
|
|
63
|
+
lastStepLabel,
|
|
64
|
+
};
|
|
65
|
+
if (lockSummary)
|
|
66
|
+
descriptor.lock = lockSummary;
|
|
67
|
+
return descriptor;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function discardSession(persistentDir) {
|
|
74
|
+
await rm(persistentDir, { recursive: true, force: true });
|
|
75
|
+
}
|
|
76
|
+
async function readLastStepLabel(persistentDir, lastCompletedSeq) {
|
|
77
|
+
if (lastCompletedSeq < 0)
|
|
78
|
+
return undefined;
|
|
79
|
+
try {
|
|
80
|
+
const entry = await readJsonIfExists(join(persistentDir, "steps", stepFilename(lastCompletedSeq)));
|
|
81
|
+
if (!entry)
|
|
82
|
+
return undefined;
|
|
83
|
+
return entry.role + (entry.variant ? `:${entry.variant}` : "");
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/session/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare function acquireLock(persistentDir: string, sessionCreatedAt: string): Promise<void>;
|
|
2
|
+
export declare function releaseLock(persistentDir: string): Promise<void>;
|
|
3
|
+
export interface LockSummary {
|
|
4
|
+
pid: number;
|
|
5
|
+
hostname: string;
|
|
6
|
+
startedAt: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Returns true when another live process likely holds the lock.
|
|
10
|
+
* - Missing lock → false.
|
|
11
|
+
* - Different host → true (defensive cross-host default).
|
|
12
|
+
* - Same host: `process.kill(pid, 0)` — ESRCH ⇒ false, EPERM ⇒ true, success ⇒ true.
|
|
13
|
+
* - Extra guard: if `lock.sessionCreatedAt !== manifestCreatedAt`, the lock is
|
|
14
|
+
* stale (inherited by an unrelated PID via PID reuse) → false.
|
|
15
|
+
* - PID-reuse guard: when the lock has a `processStartTime` and the current
|
|
16
|
+
* start time for `pid` is known and disagrees, the PID has been reused by
|
|
17
|
+
* an unrelated process → false.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isLockAlive(persistentDir: string, manifestCreatedAt: string): Promise<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* Single-read combined liveness check + summary for the picker. Returns
|
|
22
|
+
* `undefined` when the lock is absent or stale; returns the holder summary
|
|
23
|
+
* when alive.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readLiveLockSummary(persistentDir: string, manifestCreatedAt: string): Promise<LockSummary | undefined>;
|
|
26
|
+
//# sourceMappingURL=lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/session/lock.ts"],"names":[],"mappings":"AAwBA,wBAAsB,WAAW,CAC/B,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtE;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AA8BD;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,aAAa,EAAE,MAAM,EACrB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,OAAO,CAAC,CAIlB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAKlC"}
|