@inhuman.tools/harness-tui 0.0.0-bootstrap.0 → 0.2.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 (167) hide show
  1. package/LICENSE.md +7 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/interpreter/ComputedExecBox.d.ts +12 -0
  7. package/dist/interpreter/ComputedExecBox.d.ts.map +1 -0
  8. package/dist/interpreter/ComputedExecBox.js +88 -0
  9. package/dist/interpreter/ComputedExecBox.js.map +1 -0
  10. package/dist/interpreter/imageCapability.d.ts +9 -0
  11. package/dist/interpreter/imageCapability.d.ts.map +1 -0
  12. package/dist/interpreter/imageCapability.js +49 -0
  13. package/dist/interpreter/imageCapability.js.map +1 -0
  14. package/dist/interpreter/rpcCapability.d.ts +11 -0
  15. package/dist/interpreter/rpcCapability.d.ts.map +1 -0
  16. package/dist/interpreter/rpcCapability.js +91 -0
  17. package/dist/interpreter/rpcCapability.js.map +1 -0
  18. package/dist/interpreter/uiCapability.d.ts +34 -0
  19. package/dist/interpreter/uiCapability.d.ts.map +1 -0
  20. package/dist/interpreter/uiCapability.js +207 -0
  21. package/dist/interpreter/uiCapability.js.map +1 -0
  22. package/dist/schemas/index.d.ts +2 -0
  23. package/dist/schemas/index.d.ts.map +1 -0
  24. package/dist/schemas/index.js +2 -0
  25. package/dist/schemas/index.js.map +1 -0
  26. package/dist/schemas/worker-boot.d.ts +14 -0
  27. package/dist/schemas/worker-boot.d.ts.map +1 -0
  28. package/dist/schemas/worker-boot.js +15 -0
  29. package/dist/schemas/worker-boot.js.map +1 -0
  30. package/dist/tui/ack-prompt.d.ts +53 -0
  31. package/dist/tui/ack-prompt.d.ts.map +1 -0
  32. package/dist/tui/ack-prompt.js +61 -0
  33. package/dist/tui/ack-prompt.js.map +1 -0
  34. package/dist/tui/agents-drawer.d.ts +47 -0
  35. package/dist/tui/agents-drawer.d.ts.map +1 -0
  36. package/dist/tui/agents-drawer.js +314 -0
  37. package/dist/tui/agents-drawer.js.map +1 -0
  38. package/dist/tui/ask-shortcuts.d.ts +59 -0
  39. package/dist/tui/ask-shortcuts.d.ts.map +1 -0
  40. package/dist/tui/ask-shortcuts.js +96 -0
  41. package/dist/tui/ask-shortcuts.js.map +1 -0
  42. package/dist/tui/channel.d.ts +59 -0
  43. package/dist/tui/channel.d.ts.map +1 -0
  44. package/dist/tui/channel.js +27 -0
  45. package/dist/tui/channel.js.map +1 -0
  46. package/dist/tui/host-verbs.d.ts +7 -0
  47. package/dist/tui/host-verbs.d.ts.map +1 -0
  48. package/dist/tui/host-verbs.js +19 -0
  49. package/dist/tui/host-verbs.js.map +1 -0
  50. package/dist/tui/host.d.ts +25 -0
  51. package/dist/tui/host.d.ts.map +1 -0
  52. package/dist/tui/host.js +380 -0
  53. package/dist/tui/host.js.map +1 -0
  54. package/dist/tui/omnibox-seat.d.ts +132 -0
  55. package/dist/tui/omnibox-seat.d.ts.map +1 -0
  56. package/dist/tui/omnibox-seat.js +182 -0
  57. package/dist/tui/omnibox-seat.js.map +1 -0
  58. package/dist/tui/paint-controller.d.ts +170 -0
  59. package/dist/tui/paint-controller.d.ts.map +1 -0
  60. package/dist/tui/paint-controller.js +965 -0
  61. package/dist/tui/paint-controller.js.map +1 -0
  62. package/dist/tui/paint-dom.d.ts +336 -0
  63. package/dist/tui/paint-dom.d.ts.map +1 -0
  64. package/dist/tui/paint-dom.js +709 -0
  65. package/dist/tui/paint-dom.js.map +1 -0
  66. package/dist/tui/paint-source.d.ts +57 -0
  67. package/dist/tui/paint-source.d.ts.map +1 -0
  68. package/dist/tui/paint-source.js +570 -0
  69. package/dist/tui/paint-source.js.map +1 -0
  70. package/dist/tui/paint-transport.d.ts +42 -0
  71. package/dist/tui/paint-transport.d.ts.map +1 -0
  72. package/dist/tui/paint-transport.js +207 -0
  73. package/dist/tui/paint-transport.js.map +1 -0
  74. package/dist/tui/paint-types.d.ts +15 -0
  75. package/dist/tui/paint-types.d.ts.map +1 -0
  76. package/dist/tui/paint-types.js +6 -0
  77. package/dist/tui/paint-types.js.map +1 -0
  78. package/dist/tui/paint-widgets.d.ts +94 -0
  79. package/dist/tui/paint-widgets.d.ts.map +1 -0
  80. package/dist/tui/paint-widgets.js +877 -0
  81. package/dist/tui/paint-widgets.js.map +1 -0
  82. package/dist/tui/parse-args.d.ts +3 -0
  83. package/dist/tui/parse-args.d.ts.map +1 -0
  84. package/dist/tui/parse-args.js +13 -0
  85. package/dist/tui/parse-args.js.map +1 -0
  86. package/dist/tui/permissions-view.d.ts +93 -0
  87. package/dist/tui/permissions-view.d.ts.map +1 -0
  88. package/dist/tui/permissions-view.js +174 -0
  89. package/dist/tui/permissions-view.js.map +1 -0
  90. package/dist/tui/present-visual/approve.d.ts +10 -0
  91. package/dist/tui/present-visual/approve.d.ts.map +1 -0
  92. package/dist/tui/present-visual/approve.js +156 -0
  93. package/dist/tui/present-visual/approve.js.map +1 -0
  94. package/dist/tui/present-visual/dump.d.ts +47 -0
  95. package/dist/tui/present-visual/dump.d.ts.map +1 -0
  96. package/dist/tui/present-visual/dump.js +144 -0
  97. package/dist/tui/present-visual/dump.js.map +1 -0
  98. package/dist/tui/present-visual/journey-teardown.d.ts +3 -0
  99. package/dist/tui/present-visual/journey-teardown.d.ts.map +1 -0
  100. package/dist/tui/present-visual/journey-teardown.js +188 -0
  101. package/dist/tui/present-visual/journey-teardown.js.map +1 -0
  102. package/dist/tui/present-visual/journey.d.ts +15 -0
  103. package/dist/tui/present-visual/journey.d.ts.map +1 -0
  104. package/dist/tui/present-visual/journey.js +88 -0
  105. package/dist/tui/present-visual/journey.js.map +1 -0
  106. package/dist/tui/present-visual/raster.d.ts +3 -0
  107. package/dist/tui/present-visual/raster.d.ts.map +1 -0
  108. package/dist/tui/present-visual/raster.js +75 -0
  109. package/dist/tui/present-visual/raster.js.map +1 -0
  110. package/dist/tui/queue-shortcuts.d.ts +13 -0
  111. package/dist/tui/queue-shortcuts.d.ts.map +1 -0
  112. package/dist/tui/queue-shortcuts.js +23 -0
  113. package/dist/tui/queue-shortcuts.js.map +1 -0
  114. package/dist/tui/read-widen.d.ts +14 -0
  115. package/dist/tui/read-widen.d.ts.map +1 -0
  116. package/dist/tui/read-widen.js +45 -0
  117. package/dist/tui/read-widen.js.map +1 -0
  118. package/dist/tui/rewind-chrome.d.ts +29 -0
  119. package/dist/tui/rewind-chrome.d.ts.map +1 -0
  120. package/dist/tui/rewind-chrome.js +77 -0
  121. package/dist/tui/rewind-chrome.js.map +1 -0
  122. package/dist/tui/rust-present.d.ts +37 -0
  123. package/dist/tui/rust-present.d.ts.map +1 -0
  124. package/dist/tui/rust-present.js +205 -0
  125. package/dist/tui/rust-present.js.map +1 -0
  126. package/dist/tui/spinner-phase.d.ts +24 -0
  127. package/dist/tui/spinner-phase.d.ts.map +1 -0
  128. package/dist/tui/spinner-phase.js +25 -0
  129. package/dist/tui/spinner-phase.js.map +1 -0
  130. package/dist/tui/statusline-path.d.ts +10 -0
  131. package/dist/tui/statusline-path.d.ts.map +1 -0
  132. package/dist/tui/statusline-path.js +42 -0
  133. package/dist/tui/statusline-path.js.map +1 -0
  134. package/dist/tui/sugarcoat-paint.d.ts +14 -0
  135. package/dist/tui/sugarcoat-paint.d.ts.map +1 -0
  136. package/dist/tui/sugarcoat-paint.js +146 -0
  137. package/dist/tui/sugarcoat-paint.js.map +1 -0
  138. package/dist/tui/tape-spans.d.ts +64 -0
  139. package/dist/tui/tape-spans.d.ts.map +1 -0
  140. package/dist/tui/tape-spans.js +93 -0
  141. package/dist/tui/tape-spans.js.map +1 -0
  142. package/dist/tui/tea.d.ts +75 -0
  143. package/dist/tui/tea.d.ts.map +1 -0
  144. package/dist/tui/tea.js +2952 -0
  145. package/dist/tui/tea.js.map +1 -0
  146. package/dist/tui/vt-paint.d.ts +12 -0
  147. package/dist/tui/vt-paint.d.ts.map +1 -0
  148. package/dist/tui/vt-paint.js +123 -0
  149. package/dist/tui/vt-paint.js.map +1 -0
  150. package/dist/tui/wait-phrase.d.ts +31 -0
  151. package/dist/tui/wait-phrase.d.ts.map +1 -0
  152. package/dist/tui/wait-phrase.js +26 -0
  153. package/dist/tui/wait-phrase.js.map +1 -0
  154. package/dist/tui/widget-host.d.ts +34 -0
  155. package/dist/tui/widget-host.d.ts.map +1 -0
  156. package/dist/tui/widget-host.js +80 -0
  157. package/dist/tui/widget-host.js.map +1 -0
  158. package/dist/tui/work-cells.d.ts +47 -0
  159. package/dist/tui/work-cells.d.ts.map +1 -0
  160. package/dist/tui/work-cells.js +606 -0
  161. package/dist/tui/work-cells.js.map +1 -0
  162. package/dist/tui/worker-entry.d.ts +2 -0
  163. package/dist/tui/worker-entry.d.ts.map +1 -0
  164. package/dist/tui/worker-entry.js +98 -0
  165. package/dist/tui/worker-entry.js.map +1 -0
  166. package/package.json +84 -4
  167. package/README.md +0 -1
@@ -0,0 +1,144 @@
1
+ /**
2
+ * One-shot present. Stdin is a single JSON object (no length prefix).
3
+ * Stdout is a dump. The release binary reads stdin until EOF.
4
+ */
5
+ import { spawnSync } from "node:child_process";
6
+ import { dirname, join, resolve } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { getSnapshot } from "mobx-state-tree";
9
+ export const PRESENT_NOW_MS = 1_700_000_000_000;
10
+ const presentDir = dirname(fileURLToPath(import.meta.url));
11
+ const RELEASE_QD = join(presentDir, "../../../../quickdraw/rust/qd/target/release/qd");
12
+ const STDOUT_CAP = 32 * 1024 * 1024;
13
+ function qdBin() {
14
+ const override = process.env.QD_BIN;
15
+ if (override !== undefined && override !== "")
16
+ return resolve(override);
17
+ return RELEASE_QD;
18
+ }
19
+ function isRecord(value) {
20
+ return typeof value === "object" && value !== null && !Array.isArray(value);
21
+ }
22
+ function isInk(value) {
23
+ return value === "primary" || value === "secondary" || value === "rising" || value === "ghost" || value === "whisper";
24
+ }
25
+ function isOptionalString(value) {
26
+ return value === undefined || typeof value === "string";
27
+ }
28
+ function isOptionalNumber(value) {
29
+ return value === undefined || typeof value === "number";
30
+ }
31
+ function isArrayOf(value, item) {
32
+ if (!Array.isArray(value))
33
+ return false;
34
+ for (const entry of value) {
35
+ if (!item(entry))
36
+ return false;
37
+ }
38
+ return true;
39
+ }
40
+ function isPosted(value) {
41
+ if (!isRecord(value))
42
+ return false;
43
+ return (typeof value.kind === "string" &&
44
+ isOptionalString(value.key) &&
45
+ isOptionalNumber(value.delta) &&
46
+ isOptionalNumber(value.cols) &&
47
+ isOptionalNumber(value.rows));
48
+ }
49
+ function isRun(value) {
50
+ if (!isRecord(value))
51
+ return false;
52
+ return (typeof value.y === "number" &&
53
+ typeof value.x === "number" &&
54
+ typeof value.text === "string" &&
55
+ typeof value.role === "string" &&
56
+ isInk(value.ink) &&
57
+ typeof value.dim === "boolean");
58
+ }
59
+ function isHex(value) {
60
+ if (typeof value !== "string" || value.length !== 7 || value.charAt(0) !== "#")
61
+ return false;
62
+ for (const ch of value.slice(1)) {
63
+ const digit = (ch >= "0" && ch <= "9") || (ch >= "a" && ch <= "f");
64
+ if (!digit)
65
+ return false;
66
+ }
67
+ return true;
68
+ }
69
+ function isFill(value) {
70
+ if (!isRecord(value))
71
+ return false;
72
+ return typeof value.y === "number" && typeof value.x === "number" && typeof value.w === "number" && isHex(value.bg);
73
+ }
74
+ function isInkRun(value) {
75
+ if (!isRecord(value))
76
+ return false;
77
+ return (typeof value.y === "number" && typeof value.x === "number" && typeof value.text === "string" && isHex(value.fg));
78
+ }
79
+ function pictureOf(value, item, label) {
80
+ if (value === undefined)
81
+ return [];
82
+ if (!isArrayOf(value, item))
83
+ throw new Error(`${label} is not a list`);
84
+ return value;
85
+ }
86
+ function clip(text) {
87
+ const trimmed = text.trim();
88
+ if (trimmed.length <= 400)
89
+ return trimmed;
90
+ return `${trimmed.slice(0, 400)}…`;
91
+ }
92
+ export function parseDump(text, label) {
93
+ let parsed;
94
+ try {
95
+ parsed = JSON.parse(text);
96
+ }
97
+ catch (error) {
98
+ const detail = error instanceof Error ? error.message : "invalid json";
99
+ throw new Error(`${label} is not json: ${detail}`, { cause: error });
100
+ }
101
+ if (!isRecord(parsed) || !isArrayOf(parsed.posted, isPosted) || !isArrayOf(parsed.runs, isRun)) {
102
+ throw new Error(`${label} is not a dump: ${clip(text)}`);
103
+ }
104
+ return {
105
+ posted: parsed.posted,
106
+ runs: parsed.runs,
107
+ fills: pictureOf(parsed.fills, isFill, `${label} fills`),
108
+ inks: pictureOf(parsed.inks, isInkRun, `${label} inks`),
109
+ };
110
+ }
111
+ function exitHow(status, signal) {
112
+ if (status === null)
113
+ return `signal ${signal ?? "unknown"}`;
114
+ return `exit ${status}`;
115
+ }
116
+ export async function presentDump(tea, opts) {
117
+ tea.flushPaint();
118
+ const bin = qdBin();
119
+ const input = JSON.stringify({
120
+ cols: opts?.cols ?? tea.cols,
121
+ rows: opts?.rows ?? tea.rows,
122
+ nowMs: opts?.nowMs ?? PRESENT_NOW_MS,
123
+ paint: JSON.stringify({
124
+ kind: "paint_init",
125
+ epoch: "visual",
126
+ snapshot: getSnapshot(tea.paintRoot),
127
+ }),
128
+ input: opts?.input ?? [],
129
+ });
130
+ const child = spawnSync(bin, ["dump"], {
131
+ input,
132
+ encoding: "utf8",
133
+ maxBuffer: STDOUT_CAP,
134
+ });
135
+ if (child.error)
136
+ throw new Error(`qd dump failed (${bin}): ${child.error.message}`);
137
+ if (child.status !== 0) {
138
+ const stderr = child.stderr.trim();
139
+ const tail = stderr === "" ? "" : `\n${stderr}`;
140
+ throw new Error(`qd dump ${exitHow(child.status, child.signal)} (${bin})${tail}`);
141
+ }
142
+ return parseDump(child.stdout, "qd dump stdout");
143
+ }
144
+ //# sourceMappingURL=dump.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dump.js","sourceRoot":"","sources":["../../../src/tui/present-visual/dump.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function writeJourneyPage(): string;
2
+ export declare function teardown(): void;
3
+ //# sourceMappingURL=journey-teardown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journey-teardown.d.ts","sourceRoot":"","sources":["../../../src/tui/present-visual/journey-teardown.ts"],"names":[],"mappings":"AA6LA,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAED,wBAAgB,QAAQ,IAAI,IAAI,CAG/B"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Writes journey/index.html after the visual project finishes.
3
+ * Each test file is one strip. Frames stay in the order the file ran them.
4
+ */
5
+ import { readdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { journeyDir } from "./journey.js";
8
+ const STORY_ORDER = [
9
+ "omnibox",
10
+ "tape",
11
+ "work",
12
+ "agents",
13
+ "rewind",
14
+ "catalog-frames",
15
+ "catalog-shell",
16
+ "catalog-scheme",
17
+ "catalog-observe",
18
+ "catalog-mutate",
19
+ "catalog-foreign",
20
+ "catalog-license",
21
+ "catalog-rewind",
22
+ "catalog-compact",
23
+ "catalog-tape-fuse",
24
+ ];
25
+ const STORY_LABEL = {
26
+ omnibox: "Omnibox",
27
+ tape: "Tape",
28
+ work: "Work",
29
+ agents: "Agents",
30
+ rewind: "Rewind",
31
+ "catalog-frames": "Frames",
32
+ "catalog-shell": "Shell",
33
+ "catalog-scheme": "Scheme",
34
+ "catalog-observe": "Observe",
35
+ "catalog-mutate": "Mutate",
36
+ "catalog-foreign": "Foreign",
37
+ "catalog-license": "License",
38
+ "catalog-rewind": "Rewind steps",
39
+ "catalog-compact": "Compact",
40
+ "catalog-tape-fuse": "Tape fuse",
41
+ };
42
+ function isRecord(value) {
43
+ return typeof value === "object" && value !== null && !Array.isArray(value);
44
+ }
45
+ function readBeat(file) {
46
+ let parsed;
47
+ try {
48
+ parsed = JSON.parse(readFileSync(file, "utf8"));
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ if (!isRecord(parsed))
54
+ return undefined;
55
+ const { order, phase, title, ok, missed, png } = parsed;
56
+ if (typeof order !== "number" || typeof phase !== "string" || typeof title !== "string")
57
+ return undefined;
58
+ if (typeof ok !== "boolean" || typeof png !== "string" || !Array.isArray(missed))
59
+ return undefined;
60
+ const lines = [];
61
+ for (const line of missed) {
62
+ if (typeof line !== "string")
63
+ return undefined;
64
+ lines.push(line);
65
+ }
66
+ return { order, phase, title, ok, missed: lines, png };
67
+ }
68
+ function storyBeats(story) {
69
+ let names;
70
+ try {
71
+ names = readdirSync(join(journeyDir, story));
72
+ }
73
+ catch {
74
+ return [];
75
+ }
76
+ const beats = [];
77
+ for (const name of names) {
78
+ if (!name.endsWith(".json"))
79
+ continue;
80
+ const beat = readBeat(join(journeyDir, story, name));
81
+ if (beat !== undefined)
82
+ beats.push(beat);
83
+ }
84
+ beats.sort((a, b) => a.order - b.order);
85
+ return beats;
86
+ }
87
+ function escapeHtml(value) {
88
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
89
+ }
90
+ function beatFigure(story, beat) {
91
+ const klass = beat.ok ? "beat" : "beat gap";
92
+ const mark = beat.ok ? "" : `<p class="mark">open law</p>`;
93
+ const missed = beat.missed.length === 0
94
+ ? ""
95
+ : `<ul class="missed">${beat.missed.map((line) => `<li>${escapeHtml(line)}</li>`).join("")}</ul>`;
96
+ const src = `${escapeHtml(story)}/${escapeHtml(beat.png)}`;
97
+ return `<figure class="${klass}">
98
+ <a href="${src}"><img src="${src}" alt="${escapeHtml(beat.title)}"></a>
99
+ <figcaption>
100
+ <p class="title">${escapeHtml(beat.title)}</p>
101
+ <p class="phase">${escapeHtml(beat.phase)}</p>
102
+ ${mark}
103
+ ${missed}
104
+ </figcaption>
105
+ </figure>`;
106
+ }
107
+ function countLabel(n, singular, plural) {
108
+ return `${n} ${n === 1 ? singular : plural}`;
109
+ }
110
+ function storySection(story, beats) {
111
+ const label = STORY_LABEL[story] ?? story;
112
+ const open = beats.filter((beat) => !beat.ok).length;
113
+ const frames = countLabel(beats.length, "frame", "frames");
114
+ const laws = countLabel(open, "open law", "open laws");
115
+ const tally = open === 0 ? frames : `${frames} · ${laws}`;
116
+ return `<section id="${escapeHtml(story)}">
117
+ <h2>${escapeHtml(label)}</h2>
118
+ <p class="tally">${tally}</p>
119
+ <div class="strip">${beats.map((beat) => beatFigure(story, beat)).join("\n")}</div>
120
+ </section>`;
121
+ }
122
+ function page(stories) {
123
+ const nav = stories
124
+ .map(({ story }) => `<a href="#${escapeHtml(story)}">${escapeHtml(STORY_LABEL[story] ?? story)}</a>`)
125
+ .join("");
126
+ const body = stories.map(({ story, beats }) => storySection(story, beats)).join("\n");
127
+ return `<!doctype html>
128
+ <html lang="en">
129
+ <meta charset="utf-8">
130
+ <meta name="viewport" content="width=device-width, initial-scale=1">
131
+ <title>qd journeys</title>
132
+ <style>
133
+ :root { color-scheme: dark; }
134
+ body { margin: 0; background: #121212; color: #e6e6e6; font: 15px/1.45 ui-sans-serif, system-ui, sans-serif; }
135
+ header, section { padding: 28px 32px; }
136
+ section { padding-top: 8px; }
137
+ h1 { margin: 0 0 8px; font-size: 22px; font-weight: 600; }
138
+ h2 { margin: 0; font-size: 16px; font-weight: 600; }
139
+ .lede, .tally, .phase { color: #9a9a9a; }
140
+ .lede { max-width: 68ch; margin: 0 0 16px; }
141
+ nav { display: flex; gap: 16px; }
142
+ nav a { color: #d7d7d7; }
143
+ .tally { margin: 4px 0 12px; }
144
+ .strip { display: flex; gap: 20px; overflow-x: auto; align-items: flex-start; padding-bottom: 12px; }
145
+ figure { margin: 0; flex: 0 0 auto; width: min(520px, 78vw); }
146
+ img { width: 100%; height: auto; display: block; background: #1b1b1b; border-radius: 8px; }
147
+ figcaption { margin-top: 8px; }
148
+ .title { margin: 0; font-weight: 600; }
149
+ .phase, .mark { margin: 2px 0 0; }
150
+ .mark { color: #e7a0a0; }
151
+ .gap img { outline: 1px solid #8f4d4d; outline-offset: 2px; }
152
+ .missed { margin: 6px 0 0; padding-left: 18px; color: #bdbdbd; font-family: ui-monospace, monospace; font-size: 12px; }
153
+ </style>
154
+ <header>
155
+ <h1>qd journeys</h1>
156
+ <p class="lede">Each strip is one test file. Frames stay in the order that file asserts them. A red outline means that frame's law is still open. The assertion stays JSON.</p>
157
+ <nav>${nav}</nav>
158
+ </header>
159
+ ${body}
160
+ </html>
161
+ `;
162
+ }
163
+ function orderedStories() {
164
+ let names;
165
+ try {
166
+ names = readdirSync(journeyDir, { withFileTypes: true })
167
+ .filter((entry) => entry.isDirectory())
168
+ .map((entry) => entry.name);
169
+ }
170
+ catch {
171
+ return [];
172
+ }
173
+ const rank = new Map(STORY_ORDER.map((story, index) => [story, index]));
174
+ return names.sort((a, b) => (rank.get(a) ?? 100) - (rank.get(b) ?? 100) || a.localeCompare(b));
175
+ }
176
+ export function writeJourneyPage() {
177
+ const stories = orderedStories()
178
+ .map((story) => ({ story, beats: storyBeats(story) }))
179
+ .filter((entry) => entry.beats.length > 0);
180
+ const file = join(journeyDir, "index.html");
181
+ writeFileSync(file, page(stories));
182
+ return file;
183
+ }
184
+ export function teardown() {
185
+ const file = writeJourneyPage();
186
+ console.log(`journey ${file}`);
187
+ }
188
+ //# sourceMappingURL=journey-teardown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journey-teardown.js","sourceRoot":"","sources":["../../../src/tui/present-visual/journey-teardown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { Dump } from "./dump.js";
2
+ export type BeatNote = {
3
+ order: number;
4
+ phase: string;
5
+ title: string;
6
+ ok: boolean;
7
+ missed: string[];
8
+ png: string;
9
+ };
10
+ export declare const journeyDir: string;
11
+ /** Writes the frame even when the beat fails. A raster error does not replace the assertion. */
12
+ export declare function noteBeat(phase: string, dump: Dump, cols: number, rows: number, ok: boolean, missed: readonly string[]): Promise<void>;
13
+ /** A frame that is already a PNG. Used when the walk painted through the JS raster. */
14
+ export declare function notePng(phase: string, png: Buffer, ok: boolean, missed: readonly string[]): Promise<void>;
15
+ //# sourceMappingURL=journey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journey.d.ts","sourceRoot":"","sources":["../../../src/tui/present-visual/journey.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAGF,eAAO,MAAM,UAAU,QAA8B,CAAC;AA2DtD,gGAAgG;AAChG,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,OAAO,EACX,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,uFAAuF;AACvF,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/G"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * One frame per asserted beat, grouped by the test file.
3
+ * The page is for eyes. The dump JSON stays the assertion.
4
+ */
5
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
6
+ import { basename, dirname, join } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { writeRunsPng } from "./raster.js";
9
+ const presentDir = dirname(fileURLToPath(import.meta.url));
10
+ export const journeyDir = join(presentDir, "journey");
11
+ const beatCount = new Map();
12
+ const opened = new Set();
13
+ function isRecord(value) {
14
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15
+ }
16
+ function readState(value) {
17
+ if (!isRecord(value))
18
+ return { testPath: "", title: "" };
19
+ return {
20
+ testPath: typeof value.testPath === "string" ? value.testPath : "",
21
+ title: typeof value.currentTestName === "string" ? value.currentTestName : "",
22
+ };
23
+ }
24
+ function asCaller(value) {
25
+ if (typeof value !== "function" || !("getState" in value))
26
+ return undefined;
27
+ const getState = value.getState;
28
+ if (typeof getState !== "function")
29
+ return undefined;
30
+ return { getState: () => getState.call(value) };
31
+ }
32
+ async function callerBeat() {
33
+ const spec = "vitest";
34
+ const loaded = await import(spec);
35
+ const state = readState(asCaller(isRecord(loaded) ? loaded.expect : undefined)?.getState());
36
+ const file = basename(state.testPath);
37
+ const name = file.endsWith(".test.ts") ? file.slice(0, -".test.ts".length) : "beats";
38
+ // The old screenshot walks share basenames with this directory (`rewind`).
39
+ const story = state.testPath.includes("/__visual__/") ? `catalog-${name}` : name;
40
+ return { story, title: state.title };
41
+ }
42
+ function openStory(story) {
43
+ if (opened.has(story))
44
+ return;
45
+ opened.add(story);
46
+ rmSync(join(journeyDir, story), { recursive: true, force: true });
47
+ mkdirSync(join(journeyDir, story), { recursive: true });
48
+ }
49
+ function reserveBeat(story, title, phase, ok, missed) {
50
+ openStory(story);
51
+ const order = (beatCount.get(story) ?? 0) + 1;
52
+ beatCount.set(story, order);
53
+ const png = `${String(order).padStart(2, "0")}-${phase}.png`;
54
+ return { order, phase, title: title === "" ? phase : title, ok, missed: [...missed], png };
55
+ }
56
+ function writeNote(story, note) {
57
+ const json = note.png.endsWith(".png") ? `${note.png.slice(0, -".png".length)}.json` : `${note.png}.json`;
58
+ writeFileSync(join(journeyDir, story, json), `${JSON.stringify(note)}\n`);
59
+ }
60
+ /** Writes the frame even when the beat fails. A raster error does not replace the assertion. */
61
+ export async function noteBeat(phase, dump, cols, rows, ok, missed) {
62
+ try {
63
+ const caller = await callerBeat();
64
+ const note = reserveBeat(caller.story, caller.title, phase, ok, missed);
65
+ const dir = join(journeyDir, caller.story);
66
+ await writeRunsPng(join(dir, note.png), dump, cols, rows);
67
+ writeNote(caller.story, note);
68
+ }
69
+ catch (error) {
70
+ const detail = error instanceof Error ? error.message : "journey frame failed";
71
+ console.error(`journey ${phase}: ${detail}`);
72
+ }
73
+ }
74
+ /** A frame that is already a PNG. Used when the walk painted through the JS raster. */
75
+ export async function notePng(phase, png, ok, missed) {
76
+ try {
77
+ const caller = await callerBeat();
78
+ const note = reserveBeat(caller.story, caller.title, phase, ok, missed);
79
+ const dir = join(journeyDir, caller.story);
80
+ writeFileSync(join(dir, note.png), png);
81
+ writeNote(caller.story, note);
82
+ }
83
+ catch (error) {
84
+ const detail = error instanceof Error ? error.message : "journey frame failed";
85
+ console.error(`journey ${phase}: ${detail}`);
86
+ }
87
+ }
88
+ //# sourceMappingURL=journey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journey.js","sourceRoot":"","sources":["../../../src/tui/present-visual/journey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Dump } from "./dump.js";
2
+ export declare function writeRunsPng(file: string, dump: Dump, cols: number, rows: number): Promise<void>;
3
+ //# sourceMappingURL=raster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raster.d.ts","sourceRoot":"","sources":["../../../src/tui/present-visual/raster.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,WAAW,CAAC;AAiEhD,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBtG"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Review raster of a present dump.
3
+ * Fills and inks are the resolved cell colors, the same ones `bufferToPng` draws.
4
+ * A dump without them falls back to `resolveStyle` on role and prominence.
5
+ */
6
+ import { mkdirSync, writeFileSync } from "node:fs";
7
+ import { dirname, join } from "node:path";
8
+ import { fileURLToPath, pathToFileURL } from "node:url";
9
+ import { createBuffer, put } from "@inhuman.tools/quickdraw/buffer";
10
+ import { FgP } from "@inhuman.tools/quickdraw/lexicon";
11
+ import { defaultTheme, resolveStyle } from "@inhuman.tools/quickdraw/theme";
12
+ const presentDir = dirname(fileURLToPath(import.meta.url));
13
+ const INK_RGB = {
14
+ primary: { r: 255, g: 255, b: 255 },
15
+ secondary: { r: 0xbb, g: 0xbb, b: 0xbb },
16
+ rising: { r: 0x88, g: 0xcc, b: 0xff },
17
+ ghost: { r: 0x66, g: 0x66, b: 0x66 },
18
+ whisper: { r: 0x44, g: 0x44, b: 0x44 },
19
+ };
20
+ const INK_PROMINENCE = {
21
+ primary: FgP.primary,
22
+ secondary: FgP.secondary,
23
+ rising: FgP.rising,
24
+ ghost: FgP.ghost,
25
+ whisper: FgP.whisper,
26
+ };
27
+ /** Rewind content fade. Used only when the dump has no resolved ink. */
28
+ const DIM_REGION = 0.45;
29
+ function isRecord(value) {
30
+ return typeof value === "object" && value !== null && !Array.isArray(value);
31
+ }
32
+ function rgbOf(hex) {
33
+ const n = Number.parseInt(hex.slice(1), 16);
34
+ return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
35
+ }
36
+ function fgOf(run) {
37
+ const solved = resolveStyle({ role: run.role, prominence: INK_PROMINENCE[run.ink], regionProminence: run.dim ? DIM_REGION : 1 }, { theme: defaultTheme, depth: "truecolor" });
38
+ return solved.fgRgb ?? INK_RGB[run.ink];
39
+ }
40
+ function isPngRaster(value) {
41
+ return isRecord(value) && typeof value.bufferToPng === "function";
42
+ }
43
+ let rasterPromise;
44
+ function loadRaster() {
45
+ rasterPromise ??= importRaster();
46
+ return rasterPromise;
47
+ }
48
+ async function importRaster() {
49
+ // bufferToPng is not a package export. The built module walks up to fonts/.
50
+ const file = join(presentDir, "../../../../quickdraw/dist/runtime/screenshot.js");
51
+ const loaded = await import(pathToFileURL(file).href);
52
+ if (!isPngRaster(loaded))
53
+ throw new Error(`quickdraw bufferToPng missing at ${file}`);
54
+ return loaded;
55
+ }
56
+ export async function writeRunsPng(file, dump, cols, rows) {
57
+ const raster = await loadRaster();
58
+ const buf = createBuffer(cols, rows);
59
+ for (const fill of dump.fills) {
60
+ put(buf, fill.x, fill.y, " ".repeat(fill.w), { bgRgb: rgbOf(fill.bg) });
61
+ }
62
+ if (dump.inks.length > 0) {
63
+ for (const ink of dump.inks) {
64
+ put(buf, ink.x, ink.y, ink.text, { fgRgb: rgbOf(ink.fg) });
65
+ }
66
+ }
67
+ else {
68
+ for (const run of dump.runs) {
69
+ put(buf, run.x, run.y, run.text, { fgRgb: fgOf(run) });
70
+ }
71
+ }
72
+ mkdirSync(dirname(file), { recursive: true });
73
+ writeFileSync(file, raster.bufferToPng(buf, defaultTheme.groundHex));
74
+ }
75
+ //# sourceMappingURL=raster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raster.js","sourceRoot":"","sources":["../../../src/tui/present-visual/raster.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAU5E,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE3D,MAAM,OAAO,GAAqB;IAChC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE;IACnC,SAAS,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE;IACxC,MAAM,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE;IACrC,KAAK,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE;IACpC,OAAO,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE;CACvC,CAAC;AAEF,MAAM,cAAc,GAAwB;IAC1C,OAAO,EAAE,GAAG,CAAC,OAAO;IACpB,SAAS,EAAE,GAAG,CAAC,SAAS;IACxB,MAAM,EAAE,GAAG,CAAC,MAAM;IAClB,KAAK,EAAE,GAAG,CAAC,KAAK;IAChB,OAAO,EAAE,GAAG,CAAC,OAAO;CACrB,CAAC;AAEF,wEAAwE;AACxE,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,KAAK,CAAC,GAAW;IACxB,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,IAAI,CAAC,GAAQ;IACpB,MAAM,MAAM,GAAG,YAAY,CACzB,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,gBAAgB,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,EACnG,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,CAC5C,CAAC;IACF,OAAO,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC;AACpE,CAAC;AAED,IAAI,aAA6C,CAAC;AAElD,SAAS,UAAU;IACjB,aAAa,KAAK,YAAY,EAAE,CAAC;IACjC,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,KAAK,UAAU,YAAY;IACzB,4EAA4E;IAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,kDAAkD,CAAC,CAAC;IAClF,MAAM,MAAM,GAAY,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/D,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC;IACtF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,IAAU,EAAE,IAAY,EAAE,IAAY;IACrF,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IACD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Busy-turn omnibox hint. Slash and ask covers own their own chords;
3
+ * this list is only the leftover draft face.
4
+ */
5
+ import { type SuperKey } from "@inhuman.tools/harness-model";
6
+ import type { ChromeHotkey } from "@inhuman.tools/quickdraw/layout";
7
+ export declare function busyDraftShortcuts(input: {
8
+ readonly draft: string;
9
+ readonly queued: number;
10
+ readonly retrying?: boolean;
11
+ readonly superKey?: SuperKey;
12
+ }): ChromeHotkey[] | undefined;
13
+ //# sourceMappingURL=queue-shortcuts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-shortcuts.d.ts","sourceRoot":"","sources":["../../src/tui/queue-shortcuts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAQpE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B,GAAG,YAAY,EAAE,GAAG,SAAS,CAU7B"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Busy-turn omnibox hint. Slash and ask covers own their own chords;
3
+ * this list is only the leftover draft face.
4
+ */
5
+ import { parseSuperKey } from "@inhuman.tools/harness-model";
6
+ import { HOTKEY_EVENT, superChord } from "./ask-shortcuts.js";
7
+ function hk(key, action, event) {
8
+ return { key, action, event };
9
+ }
10
+ export function busyDraftShortcuts(input) {
11
+ const retry = hk(superChord("Enter", parseSuperKey(input.superKey)), "retry now", HOTKEY_EVENT.retry);
12
+ if (input.draft.trim() !== "")
13
+ return [hk("Enter", "queue message", HOTKEY_EVENT.queueMessage)];
14
+ if (input.queued > 0) {
15
+ const steer = hk("Enter", "steer first", HOTKEY_EVENT.steerFirst);
16
+ const retract = { key: "Esc", action: "retract last queued" };
17
+ return input.retrying === true ? [steer, retry, retract] : [steer, retract];
18
+ }
19
+ if (input.retrying === true)
20
+ return [retry];
21
+ return undefined;
22
+ }
23
+ //# sourceMappingURL=queue-shortcuts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-shortcuts.js","sourceRoot":"","sources":["../../src/tui/queue-shortcuts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAAiB,MAAM,8BAA8B,CAAC;AAG5E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE9D,SAAS,EAAE,CAAC,GAAW,EAAE,MAAc,EAAE,KAAa;IACpD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAKlC;IACC,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACtG,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC;IAChG,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;QAC9D,OAAO,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,14 @@
1
+ export type FileReadWiden = {
2
+ readonly path: string;
3
+ readonly label: string;
4
+ };
5
+ /** One directory up. Undefined at `.` / `/` / `$HOME` / a volume root. */
6
+ export declare function fileReadParent(prepared: string): string | undefined;
7
+ export declare function fileReadWidenLabel(rootPath: string, parent: string): string;
8
+ /**
9
+ * Suggest `parent(prepared)` when another observed extra-root read shares
10
+ * that parent (or *is* that parent). `observed` is allowlist keys plus
11
+ * other in-flight read paths — not denials.
12
+ */
13
+ export declare function fileReadWiden(rootPath: string, prepared: string, observed: readonly string[]): FileReadWiden | undefined;
14
+ //# sourceMappingURL=read-widen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-widen.d.ts","sourceRoot":"","sources":["../../src/tui/read-widen.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUnE;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG3E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,aAAa,GAAG,SAAS,CAM3B"}