linersh 0.5.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 (95) hide show
  1. package/README.md +168 -0
  2. package/bin/liner.js +126 -0
  3. package/dist/App.js +195 -0
  4. package/dist/App.js.map +1 -0
  5. package/dist/agents/detect.js +102 -0
  6. package/dist/agents/detect.js.map +1 -0
  7. package/dist/agents/events.js +8 -0
  8. package/dist/agents/events.js.map +1 -0
  9. package/dist/agents/jtbd-clarify.js +144 -0
  10. package/dist/agents/jtbd-clarify.js.map +1 -0
  11. package/dist/agents/parsers.js +316 -0
  12. package/dist/agents/parsers.js.map +1 -0
  13. package/dist/agents/prompts.js +301 -0
  14. package/dist/agents/prompts.js.map +1 -0
  15. package/dist/agents/run-log.js +71 -0
  16. package/dist/agents/run-log.js.map +1 -0
  17. package/dist/agents/runner.js +180 -0
  18. package/dist/agents/runner.js.map +1 -0
  19. package/dist/agents/types.js +2 -0
  20. package/dist/agents/types.js.map +1 -0
  21. package/dist/bin-resolver.js +92 -0
  22. package/dist/bin-resolver.js.map +1 -0
  23. package/dist/browser-support.js +62 -0
  24. package/dist/browser-support.js.map +1 -0
  25. package/dist/colors.js +105 -0
  26. package/dist/colors.js.map +1 -0
  27. package/dist/components/Header.js +17 -0
  28. package/dist/components/Header.js.map +1 -0
  29. package/dist/components/KeyHints.js +10 -0
  30. package/dist/components/KeyHints.js.map +1 -0
  31. package/dist/components/LabeledBox.js +53 -0
  32. package/dist/components/LabeledBox.js.map +1 -0
  33. package/dist/components/NextSteps.js +18 -0
  34. package/dist/components/NextSteps.js.map +1 -0
  35. package/dist/config.js +88 -0
  36. package/dist/config.js.map +1 -0
  37. package/dist/editor.js +40 -0
  38. package/dist/editor.js.map +1 -0
  39. package/dist/gates.js +121 -0
  40. package/dist/gates.js.map +1 -0
  41. package/dist/index.js +17 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/ipc.js +136 -0
  44. package/dist/ipc.js.map +1 -0
  45. package/dist/phases.js +348 -0
  46. package/dist/phases.js.map +1 -0
  47. package/dist/progress.js +185 -0
  48. package/dist/progress.js.map +1 -0
  49. package/dist/screens/AgentSetup.js +217 -0
  50. package/dist/screens/AgentSetup.js.map +1 -0
  51. package/dist/screens/BootSplash.js +159 -0
  52. package/dist/screens/BootSplash.js.map +1 -0
  53. package/dist/screens/BrowserSetup.js +181 -0
  54. package/dist/screens/BrowserSetup.js.map +1 -0
  55. package/dist/screens/CompileView.js +297 -0
  56. package/dist/screens/CompileView.js.map +1 -0
  57. package/dist/screens/FramingConfirmReview.js +193 -0
  58. package/dist/screens/FramingConfirmReview.js.map +1 -0
  59. package/dist/screens/Gate1Review.js +143 -0
  60. package/dist/screens/Gate1Review.js.map +1 -0
  61. package/dist/screens/Gate2Review.js +158 -0
  62. package/dist/screens/Gate2Review.js.map +1 -0
  63. package/dist/screens/ImportPrompt.js +65 -0
  64. package/dist/screens/ImportPrompt.js.map +1 -0
  65. package/dist/screens/LocalFilePicker.js +139 -0
  66. package/dist/screens/LocalFilePicker.js.map +1 -0
  67. package/dist/screens/NewMixtapeWizard.js +662 -0
  68. package/dist/screens/NewMixtapeWizard.js.map +1 -0
  69. package/dist/screens/NewProjectPrompt.js +66 -0
  70. package/dist/screens/NewProjectPrompt.js.map +1 -0
  71. package/dist/screens/PhaseRunner.js +1119 -0
  72. package/dist/screens/PhaseRunner.js.map +1 -0
  73. package/dist/screens/ProcessManifest.js +158 -0
  74. package/dist/screens/ProcessManifest.js.map +1 -0
  75. package/dist/screens/ProjectHub.js +546 -0
  76. package/dist/screens/ProjectHub.js.map +1 -0
  77. package/dist/screens/Settings.js +72 -0
  78. package/dist/screens/Settings.js.map +1 -0
  79. package/dist/screens/SourceModal.js +269 -0
  80. package/dist/screens/SourceModal.js.map +1 -0
  81. package/dist/screens/TapeBrowser.js +277 -0
  82. package/dist/screens/TapeBrowser.js.map +1 -0
  83. package/dist/screens/TapeDraftReview.js +440 -0
  84. package/dist/screens/TapeDraftReview.js.map +1 -0
  85. package/dist/screens/TapeEditor.js +310 -0
  86. package/dist/screens/TapeEditor.js.map +1 -0
  87. package/dist/screens/cassette-art.js +72 -0
  88. package/dist/screens/cassette-art.js.map +1 -0
  89. package/dist/store.js +10 -0
  90. package/dist/store.js.map +1 -0
  91. package/dist/types.js +3 -0
  92. package/dist/types.js.map +1 -0
  93. package/dist/yaml-io.js +345 -0
  94. package/dist/yaml-io.js.map +1 -0
  95. package/package.json +54 -0
@@ -0,0 +1,185 @@
1
+ // A single source of truth for "how far has the curator walked through the
2
+ // methodology" — replaces the swiss-cheese per-artifact status detection
3
+ // that produced check-marks out of order whenever a previous run or
4
+ // hand-edit had touched a later artifact first.
5
+ //
6
+ // The file is dead-simple: one integer plus a timestamp.
7
+ //
8
+ // { "step": 4, "lastTouched": "2026-05-19T22:00:00.000Z" }
9
+ //
10
+ // `step` is the count of completed phases. With 11 phases in PHASE_ORDER,
11
+ // step ranges 0..11:
12
+ //
13
+ // 0 → nothing done; user is currently on PHASE_ORDER[0] (Framing)
14
+ // N → N phases done; user is currently on PHASE_ORDER[N]
15
+ // 11 → everything (including optional Phase 8) done
16
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import { projectFolder } from "./yaml-io.js";
19
+ const PROGRESS_FILE = ".liner-progress.json";
20
+ /** Walk order. Position in this array IS the step value the user is "on". */
21
+ export const PHASE_ORDER = [
22
+ "framing",
23
+ "gate0",
24
+ "candidates",
25
+ "gate1",
26
+ "evaluation",
27
+ "quality",
28
+ "gate2",
29
+ "synthesis",
30
+ "assembly",
31
+ "compile",
32
+ "empirical",
33
+ ];
34
+ export const TOTAL_STEPS = PHASE_ORDER.length;
35
+ export function readProgress(folder) {
36
+ const path = join(folder, PROGRESS_FILE);
37
+ if (!existsSync(path)) {
38
+ return { step: 0, lastTouched: new Date().toISOString() };
39
+ }
40
+ try {
41
+ const raw = JSON.parse(readFileSync(path, "utf8"));
42
+ return {
43
+ step: typeof raw.step === "number"
44
+ ? Math.max(0, Math.min(TOTAL_STEPS, Math.floor(raw.step)))
45
+ : 0,
46
+ lastTouched: typeof raw.lastTouched === "string"
47
+ ? raw.lastTouched
48
+ : new Date().toISOString(),
49
+ };
50
+ }
51
+ catch {
52
+ return { step: 0, lastTouched: new Date().toISOString() };
53
+ }
54
+ }
55
+ export function writeProgress(folder, state) {
56
+ const path = join(folder, PROGRESS_FILE);
57
+ writeFileSync(path, JSON.stringify(state, null, 2) + "\n", "utf8");
58
+ }
59
+ export function progressFileExists(folder) {
60
+ return existsSync(join(folder, PROGRESS_FILE));
61
+ }
62
+ /**
63
+ * Advance the progress cursor when a phase completes. Idempotent: calling
64
+ * twice for the same phase is a no-op. Calling for a phase that isn't the
65
+ * current one is also a no-op (we don't skip ahead silently).
66
+ */
67
+ export function markPhaseComplete(folder, phaseId) {
68
+ const current = readProgress(folder);
69
+ const expected = PHASE_ORDER.indexOf(phaseId);
70
+ if (expected === -1)
71
+ return current;
72
+ if (current.step !== expected) {
73
+ // Out of sync — caller is asking us to advance from somewhere we aren't.
74
+ // Don't move the cursor. Caller should reconcile before retrying.
75
+ return current;
76
+ }
77
+ const next = {
78
+ step: Math.min(TOTAL_STEPS, current.step + 1),
79
+ lastTouched: new Date().toISOString(),
80
+ };
81
+ writeProgress(folder, next);
82
+ return next;
83
+ }
84
+ /**
85
+ * One-time inference for projects that predate progress.json. Walks
86
+ * PHASE_ORDER and finds the longest consecutive prefix of "done" phases,
87
+ * then commits that as the starting step.
88
+ *
89
+ * "Done" here uses the same artifact heuristics that drove status in the
90
+ * old per-phase model — so a project where the agent ran Phase 1 and Phase 2
91
+ * before this rewrite migrates to step = 2 cleanly. Out-of-order artifacts
92
+ * (Phase 7 done but Phase 2 empty) are ignored — the consecutive-prefix
93
+ * rule reflects what the curator has *actually walked through*, not what
94
+ * files happen to be on disk.
95
+ */
96
+ export function migrateProgress(folder, tape) {
97
+ const project = projectFolder(folder);
98
+ const gateState = readGateStateInline(folder);
99
+ let step = 0;
100
+ for (const phaseId of PHASE_ORDER) {
101
+ if (!isPhaseComplete(phaseId, folder, project, tape, gateState))
102
+ break;
103
+ step++;
104
+ }
105
+ const state = {
106
+ step,
107
+ lastTouched: new Date().toISOString(),
108
+ };
109
+ writeProgress(folder, state);
110
+ return state;
111
+ }
112
+ function readGateStateInline(folder) {
113
+ // Cheap re-read — kept local to avoid a circular import with phases.ts.
114
+ const path = join(folder, ".liner-gates.json");
115
+ if (!existsSync(path)) {
116
+ return { gate0Accepted: false, gate1Accepted: false, gate2Accepted: false };
117
+ }
118
+ try {
119
+ const raw = JSON.parse(readFileSync(path, "utf8"));
120
+ return {
121
+ gate0Accepted: Boolean(raw.gate0Accepted),
122
+ gate1Accepted: Boolean(raw.gate1Accepted),
123
+ gate2Accepted: Boolean(raw.gate2Accepted),
124
+ };
125
+ }
126
+ catch {
127
+ return { gate0Accepted: false, gate1Accepted: false, gate2Accepted: false };
128
+ }
129
+ }
130
+ function isPhaseComplete(phaseId, folder, project, tape, gates) {
131
+ switch (phaseId) {
132
+ case "framing":
133
+ return artifactHasRealContent(join(folder, "working/01-jtbd-and-knowledge-map.md")) &&
134
+ Boolean(tape.jtbd?.trim());
135
+ case "gate0":
136
+ return gates.gate0Accepted;
137
+ case "candidates":
138
+ return artifactHasRealContent(join(folder, "working/02-candidate-longlist.md"));
139
+ case "gate1":
140
+ return gates.gate1Accepted;
141
+ case "evaluation":
142
+ return artifactHasRealContent(join(folder, "working/03-evaluation.yaml"));
143
+ case "quality":
144
+ return artifactHasRealContent(join(folder, "working/04-quality-checks.md"));
145
+ case "gate2":
146
+ return gates.gate2Accepted;
147
+ case "synthesis": {
148
+ if (!existsSync(project.synthesisPath))
149
+ return false;
150
+ const text = readFileSync(project.synthesisPath, "utf8");
151
+ return text.trim().length > 0 && !text.includes("Replace this placeholder");
152
+ }
153
+ case "assembly":
154
+ return tape.sources.length > 0;
155
+ case "compile":
156
+ return existsSync(project.mixtapePath);
157
+ case "empirical":
158
+ return artifactHasRealContent(join(folder, "working/05-empirical-test.md"));
159
+ }
160
+ }
161
+ const PLACEHOLDER_MARKERS = [
162
+ "TODO — a single specific sentence",
163
+ // Knowledge-map section placeholder — survives the wizard's JTBD pre-fill
164
+ // (which only strips the JTBD-specific TODO above) and gets removed by
165
+ // Phase 1 when the agent writes real sections. Without this marker, the
166
+ // freshly-pre-filled working/01 would falsely register as "Framing done."
167
+ "TODO — Phase 1 replaces this",
168
+ "Quantity over precision",
169
+ "candidates: []",
170
+ "Run each test deliberately",
171
+ ];
172
+ function artifactHasRealContent(path) {
173
+ if (!existsSync(path))
174
+ return false;
175
+ const text = readFileSync(path, "utf8");
176
+ const trimmed = text.trim();
177
+ if (trimmed.length === 0)
178
+ return false;
179
+ for (const marker of PLACEHOLDER_MARKERS) {
180
+ if (text.includes(marker))
181
+ return false;
182
+ }
183
+ return true;
184
+ }
185
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,217 @@
1
+ import React, { useMemo, useState } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { Header } from "../components/Header.js";
4
+ import { KeyHints } from "../components/KeyHints.js";
5
+ import { LabeledBox } from "../components/LabeledBox.js";
6
+ import { useApp } from "../store.js";
7
+ import { detectAgents, KNOWN_AGENTS } from "../agents/detect.js";
8
+ import { readConfig, writeConfig } from "../config.js";
9
+ import { CURRENT, ERROR, HEADING, STRUCTURE, SUCCESS } from "../colors.js";
10
+ // One-time picker for "which AI agent should drive the methodology phases?"
11
+ // — runs as the first screen on a fresh install when both Claude Code and
12
+ // Codex are present, and is reachable later via the splash Settings entry.
13
+ //
14
+ // Persists the choice to ~/.liner/config.yaml (via the config module). The
15
+ // LINER_AGENT env var still overrides — power users / CI keep the escape
16
+ // hatch. The mid-phase picker becomes dead code in practice but stays bound
17
+ // as a defensive fallback (e.g. config file disappears, env var names a
18
+ // non-installed agent).
19
+ /**
20
+ * Source of truth for what the screen says about each agent. Kept inline so
21
+ * the copy lives with the screen that shows it, rather than in agents/types
22
+ * (which is where the cold type lives).
23
+ */
24
+ const AGENT_BLURBS = {
25
+ claude: {
26
+ tagline: "Anthropic's Claude Code — strong at long-context tasks and at writing prose.",
27
+ install: "npm install -g @anthropic-ai/claude-code",
28
+ },
29
+ codex: {
30
+ tagline: "OpenAI Codex — fast for code-heavy phases, snappy on shorter prompts.",
31
+ install: "see https://github.com/openai/codex",
32
+ },
33
+ };
34
+ export function AgentSetup() {
35
+ const app = useApp();
36
+ const installed = useMemo(() => detectAgents(), []);
37
+ const config = useMemo(() => readConfig(), []);
38
+ // Agents the TUI knows about but didn't find on this machine. Surfaced as
39
+ // a footer so a user with (e.g.) Codex installed via fnm but unreachable
40
+ // from the TUI's PATH has a concrete unblock path rather than just "not
41
+ // detected." The KNOWN_AGENTS catalog is the single source of truth.
42
+ const undetected = useMemo(() => KNOWN_AGENTS.filter((meta) => !installed.some((a) => a.id === meta.id)), [installed]);
43
+ // Where the cursor lands by default: the currently-configured agent if
44
+ // it's installed, otherwise the first one. New installs start at index 0.
45
+ const initialIndex = useMemo(() => {
46
+ if (config.agent) {
47
+ const idx = installed.findIndex((a) => a.id === config.agent);
48
+ if (idx >= 0)
49
+ return idx;
50
+ }
51
+ return 0;
52
+ }, [installed, config.agent]);
53
+ const [cursor, setCursor] = useState(initialIndex);
54
+ const [error, setError] = useState(null);
55
+ /** Return to wherever launched this screen. First-run has an empty back
56
+ * stack, so back() falls through to the browser. From the splash settings
57
+ * entry, back() pops to the splash. */
58
+ function done() {
59
+ app.back();
60
+ }
61
+ function pick(agent) {
62
+ try {
63
+ writeConfig({ agent: agent.id });
64
+ app.setNotification({
65
+ kind: "info",
66
+ message: `Agent set to ${agent.name}. Change anytime from the splash menu.`,
67
+ });
68
+ done();
69
+ }
70
+ catch (e) {
71
+ setError(`Could not write config: ${e.message}`);
72
+ }
73
+ }
74
+ function clearChoice() {
75
+ try {
76
+ writeConfig({ agent: null });
77
+ app.setNotification({
78
+ kind: "info",
79
+ message: "Cleared agent preference. The mid-phase picker will appear when needed.",
80
+ });
81
+ done();
82
+ }
83
+ catch (e) {
84
+ setError(`Could not write config: ${e.message}`);
85
+ }
86
+ }
87
+ useInput((input, key) => {
88
+ if (installed.length === 0) {
89
+ if (key.escape || input === "b")
90
+ done();
91
+ return;
92
+ }
93
+ if (key.upArrow || input === "k") {
94
+ setCursor((c) => Math.max(0, c - 1));
95
+ }
96
+ else if (key.downArrow || input === "j") {
97
+ setCursor((c) => Math.min(installed.length - 1, c + 1));
98
+ }
99
+ else if (key.return || input === " ") {
100
+ const agent = installed[cursor];
101
+ if (agent)
102
+ pick(agent);
103
+ }
104
+ else if (input === "u" && config.agent) {
105
+ clearChoice();
106
+ }
107
+ else if (key.escape || input === "b") {
108
+ done();
109
+ }
110
+ });
111
+ // Zero-agent state: instructions, no picker. User can't proceed without
112
+ // an agent for methodology phases — but they can still browse compiled
113
+ // mixtapes, so we let them through to the browser.
114
+ if (installed.length === 0) {
115
+ return (React.createElement(Box, { flexDirection: "column" },
116
+ React.createElement(Header, { title: "choose your AI agent", subtitle: "first-run setup" }),
117
+ React.createElement(Box, { marginBottom: 1 },
118
+ React.createElement(LabeledBox, { label: "no agent installed", color: ERROR },
119
+ React.createElement(Text, { color: ERROR, bold: true }, "Neither Claude Code nor Codex was found on your PATH."),
120
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
121
+ React.createElement(Text, null, "Liner can run the methodology with either:"),
122
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
123
+ React.createElement(Text, null,
124
+ " ",
125
+ React.createElement(Text, { color: STRUCTURE, bold: true }, "Claude Code"),
126
+ React.createElement(Text, { dimColor: true },
127
+ " — ",
128
+ AGENT_BLURBS.claude.install)),
129
+ React.createElement(Text, null,
130
+ " ",
131
+ React.createElement(Text, { color: STRUCTURE, bold: true }, "OpenAI Codex"),
132
+ React.createElement(Text, { dimColor: true },
133
+ " — ",
134
+ AGENT_BLURBS.codex.install)))),
135
+ React.createElement(Box, { marginTop: 1 },
136
+ React.createElement(Text, { dimColor: true },
137
+ "You can still browse compiled mixtapes without an agent \u2014 just press ",
138
+ React.createElement(Text, { color: STRUCTURE }, "esc"),
139
+ " to continue.")))),
140
+ React.createElement(KeyHints, { hints: [{ key: "esc", label: "skip to browser" }] })));
141
+ }
142
+ return (React.createElement(Box, { flexDirection: "column" },
143
+ React.createElement(Header, { title: "choose your AI agent", subtitle: config.agent
144
+ ? `current: ${config.agent} · change anytime`
145
+ : "first-run setup · pick once, change anytime" }),
146
+ React.createElement(Box, { marginBottom: 1, flexDirection: "column" },
147
+ React.createElement(Text, { color: HEADING, bold: true }, "Which agent should drive the methodology?"),
148
+ React.createElement(Box, { marginTop: 1 },
149
+ React.createElement(Text, { dimColor: true }, "Liner spawns the agent CLI for each methodology phase (framing, candidate discovery, evaluation, \u2026). Both options run the same skill bundle and produce the same artifacts \u2014 pick the one you already use, or default to whichever is faster on your hardware. You can change this later from the splash menu's Settings entry."))),
150
+ React.createElement(Box, { marginBottom: 1 },
151
+ React.createElement(LabeledBox, { label: "installed agents", color: STRUCTURE }, installed.map((agent, i) => {
152
+ const active = i === cursor;
153
+ const blurb = AGENT_BLURBS[agent.id];
154
+ const isConfigured = config.agent === agent.id;
155
+ return (React.createElement(Box, { key: agent.id, flexDirection: "column", marginBottom: i === installed.length - 1 ? 0 : 1 },
156
+ React.createElement(Box, null,
157
+ React.createElement(Text, { color: active ? CURRENT : undefined, bold: active }, active ? "> " : " "),
158
+ React.createElement(Text, { color: STRUCTURE }, `[${i + 1}]`),
159
+ React.createElement(Text, null, " "),
160
+ React.createElement(Text, { color: active ? CURRENT : undefined, bold: active }, agent.name),
161
+ isConfigured ? (React.createElement(Text, { color: SUCCESS }, " · current")) : null),
162
+ blurb ? (React.createElement(Box, { paddingLeft: 6 },
163
+ React.createElement(Text, { dimColor: true }, blurb.tagline))) : null,
164
+ React.createElement(Box, { paddingLeft: 6 },
165
+ React.createElement(Text, { dimColor: true }, agent.bin))));
166
+ }))),
167
+ React.createElement(Box, { marginBottom: 1 },
168
+ React.createElement(Text, { color: STRUCTURE }, "enter"),
169
+ React.createElement(Text, { dimColor: true }, ` → pick ${installed[cursor]?.name ?? "agent"} and continue`)),
170
+ undetected.length > 0 ? (React.createElement(Box, { marginBottom: 1 },
171
+ React.createElement(LabeledBox, { label: "not detected", color: STRUCTURE },
172
+ React.createElement(Text, { dimColor: true },
173
+ undetected.length === 1
174
+ ? `${undetected[0].name} isn't on Liner's PATH right now.`
175
+ : `${undetected.map((u) => u.name).join(" and ")} aren't on Liner's PATH right now.`,
176
+ " ",
177
+ "If you have one installed but it's not showing up \u2014 usually fnm / nvm / asdf shims that aren't loaded in the launcher's environment \u2014 try one of:"),
178
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
179
+ React.createElement(Text, { dimColor: true },
180
+ " • ",
181
+ "Restart the TUI from a shell where",
182
+ " ",
183
+ React.createElement(Text, { color: STRUCTURE },
184
+ "which ",
185
+ undetected[0].id),
186
+ " ",
187
+ "returns a path."),
188
+ React.createElement(Text, { dimColor: true },
189
+ " • ",
190
+ "Set",
191
+ " ",
192
+ React.createElement(Text, { color: STRUCTURE },
193
+ undetected[0].envVar,
194
+ "=/full/path/to/",
195
+ undetected[0].id),
196
+ " ",
197
+ "in your shell config (or pass it inline:",
198
+ " ",
199
+ React.createElement(Text, { color: STRUCTURE },
200
+ undetected[0].envVar,
201
+ "=\u2026 npm run dev"),
202
+ ")."),
203
+ React.createElement(Text, { dimColor: true },
204
+ " • ",
205
+ "If you don't have it installed yet:",
206
+ " ",
207
+ React.createElement(Text, { color: STRUCTURE }, AGENT_BLURBS[undetected[0].id]?.install ?? "(install instructions vary)")))))) : null,
208
+ error ? (React.createElement(Box, { marginBottom: 1 },
209
+ React.createElement(Text, { color: ERROR }, error))) : null,
210
+ React.createElement(KeyHints, { hints: [
211
+ { key: "↑↓", label: "select" },
212
+ { key: "enter", label: "pick + save" },
213
+ ...(config.agent ? [{ key: "u", label: "clear preference" }] : []),
214
+ { key: "esc", label: "skip" },
215
+ ] })));
216
+ }
217
+ //# sourceMappingURL=AgentSetup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentSetup.js","sourceRoot":"","sources":["../../src/screens/AgentSetup.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import React, { useMemo, useState } from "react";
2
+ import { Box, Text, useInput, useStdout } from "ink";
3
+ import BigText from "ink-big-text";
4
+ import Gradient from "ink-gradient";
5
+ import { useApp } from "../store.js";
6
+ import { CURRENT, HEADING, PALETTE, STRUCTURE } from "../colors.js";
7
+ import { SMALL_CASSETTE_ROWS, SMALL_CASSETTE_WIDTH, } from "./cassette-art.js";
8
+ // First-paint splash. An ASCII-art logo (rendered as foreground text in the
9
+ // brand color) above a real interactive launch menu. Arrows move the
10
+ // selection; Enter activates it; `n` / `i` / `o` are direct hotkeys.
11
+ //
12
+ // The compact (~66×19) cassette is the default — it fits comfortably in
13
+ // every reasonable terminal width and the visual balance against the menu
14
+ // rows below is tighter than the maximalist 100×29 version. The full
15
+ // CASSETTE_ROWS export still lives in cassette-art.ts for any future
16
+ // "show the big one" affordance, but the splash never auto-promotes.
17
+ // Skipped via `shouldShowSplash()` when stdout isn't a TTY or
18
+ // LINER_NO_SPLASH is set.
19
+ const VERSION = "0.5.0"; // mirrors package.json — header pin tracked in TUI-BACKLOG
20
+ const ITEMS = [
21
+ { action: "new", hotkey: "n", label: "New mixtape", hint: "open the curation wizard" },
22
+ { action: "import", hotkey: "i", label: "Import archive", hint: "load a .mixtape file" },
23
+ { action: "open", hotkey: "o", label: "Open existing", hint: "browse your mixtapes folder" },
24
+ { action: "settings", hotkey: "s", label: "Settings", hint: "change AI agent" },
25
+ ];
26
+ export function BootSplash() {
27
+ const app = useApp();
28
+ const { stdout } = useStdout();
29
+ const cols = stdout?.columns ?? 80;
30
+ // Show the compact cassette whenever it fits; fall back to the wordmark
31
+ // on terminals too narrow for it.
32
+ const showCassette = cols >= SMALL_CASSETTE_WIDTH;
33
+ const [selected, setSelected] = useState(0);
34
+ function dispatch(action) {
35
+ switch (action) {
36
+ case "new":
37
+ app.navigate({ kind: "newProject" });
38
+ return;
39
+ case "import":
40
+ app.navigate({ kind: "import" });
41
+ return;
42
+ case "open":
43
+ app.navigate({ kind: "browser" });
44
+ return;
45
+ case "settings":
46
+ app.navigate({ kind: "agentSetup" });
47
+ return;
48
+ }
49
+ }
50
+ useInput((input, key) => {
51
+ if (key.upArrow || input === "k") {
52
+ setSelected((i) => (i - 1 + ITEMS.length) % ITEMS.length);
53
+ }
54
+ else if (key.downArrow || input === "j") {
55
+ setSelected((i) => (i + 1) % ITEMS.length);
56
+ }
57
+ else if (input === "n") {
58
+ dispatch("new");
59
+ }
60
+ else if (input === "i") {
61
+ dispatch("import");
62
+ }
63
+ else if (input === "o") {
64
+ dispatch("open");
65
+ }
66
+ else if (input === "s") {
67
+ dispatch("settings");
68
+ }
69
+ else if (key.return || input === " ") {
70
+ dispatch(ITEMS[selected].action);
71
+ }
72
+ else if (key.escape) {
73
+ dispatch("open");
74
+ }
75
+ });
76
+ return (React.createElement(Box, { flexDirection: "column", paddingY: 1 },
77
+ showCassette ? (React.createElement(CassetteLogo, { rows: SMALL_CASSETTE_ROWS })) : (React.createElement(Gradient, { name: "vice" },
78
+ React.createElement(BigText, { text: "liner", font: "block" }))),
79
+ React.createElement(Box, { flexDirection: "column", paddingLeft: 2, marginTop: showCassette ? 1 : -1 },
80
+ React.createElement(Box, null,
81
+ React.createElement(Text, { color: STRUCTURE, bold: true }, "liner"),
82
+ React.createElement(Text, { dimColor: true }, " \u00B7 curate AI-ready mixtapes from any set of sources")),
83
+ React.createElement(Text, { dimColor: true },
84
+ "v",
85
+ VERSION)),
86
+ React.createElement(Box, { flexDirection: "column", paddingLeft: 2, marginTop: 1 },
87
+ React.createElement(Text, { color: HEADING, bold: true }, "Get started"),
88
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, ITEMS.map((item, i) => (React.createElement(MenuRow, { key: item.action, item: item, active: i === selected }))))),
89
+ React.createElement(Box, { marginTop: 1, paddingLeft: 2 },
90
+ React.createElement(Text, { dimColor: true }, "\u2191\u2193 navigate \u00B7 "),
91
+ React.createElement(Text, { color: STRUCTURE }, "enter"),
92
+ React.createElement(Text, { dimColor: true }, " select \u00B7 "),
93
+ React.createElement(Text, { color: STRUCTURE }, "[n]"),
94
+ React.createElement(Text, { dimColor: true }, " "),
95
+ React.createElement(Text, { color: STRUCTURE }, "[i]"),
96
+ React.createElement(Text, { dimColor: true }, " "),
97
+ React.createElement(Text, { color: STRUCTURE }, "[o]"),
98
+ React.createElement(Text, { dimColor: true }, " "),
99
+ React.createElement(Text, { color: STRUCTURE }, "[s]"),
100
+ React.createElement(Text, { dimColor: true }, " direct shortcuts"))));
101
+ }
102
+ /**
103
+ * Render the ASCII cassette logo with every non-space character painted in
104
+ * a randomly-chosen palette color. The randomization is computed once per
105
+ * mount (via useMemo) — re-randomizing on every re-render would flicker.
106
+ *
107
+ * For perf we group consecutive characters that landed on the same color
108
+ * into runs so each row ships a handful of `Text` nodes instead of one per
109
+ * character — Ink mounts a separate element per `<Text>`, and 66 elements
110
+ * × 19 rows × every re-paint adds up.
111
+ *
112
+ * Spaces are emitted as their own color-less run so we don't burn nodes
113
+ * coloring invisible cells.
114
+ */
115
+ function CassetteLogo({ rows }) {
116
+ const colored = useMemo(() => rows.map(colorizeRow), [rows]);
117
+ return (React.createElement(Box, { flexDirection: "column" }, colored.map((runs, rowIdx) => (React.createElement(Box, { key: rowIdx }, runs.map((run, runIdx) => (React.createElement(Text, { key: runIdx, color: run.color }, run.chars))))))));
118
+ }
119
+ function colorizeRow(row) {
120
+ const runs = [];
121
+ for (const ch of row) {
122
+ // Spaces don't need coloring — collapse them into uncolored runs so we
123
+ // don't allocate a random color per blank cell.
124
+ const color = ch === " " ? undefined : PALETTE[Math.floor(Math.random() * PALETTE.length)];
125
+ const tail = runs[runs.length - 1];
126
+ if (tail && tail.color === color) {
127
+ tail.chars += ch;
128
+ }
129
+ else {
130
+ runs.push({ color, chars: ch });
131
+ }
132
+ }
133
+ return runs;
134
+ }
135
+ function MenuRow({ item, active }) {
136
+ // ASCII ">" is guaranteed single-cell. The unicode ▶ glyph renders
137
+ // double-wide in many terminal fonts, which made the inactive rows shift
138
+ // every time the user moved the selection. Using a fixed two-char prefix
139
+ // ("> " or " ") keeps every row anchored at the same column.
140
+ return (React.createElement(Box, null,
141
+ React.createElement(Text, { color: active ? CURRENT : undefined, bold: active }, active ? "> " : " "),
142
+ React.createElement(Text, { color: STRUCTURE }, `[${item.hotkey}]`),
143
+ React.createElement(Text, null, " "),
144
+ React.createElement(Text, { color: active ? CURRENT : undefined, bold: active }, item.label.padEnd(18, " ")),
145
+ React.createElement(Text, { dimColor: true }, item.hint)));
146
+ }
147
+ export function shouldShowSplash() {
148
+ if (process.env["LINER_NO_SPLASH"])
149
+ return false;
150
+ if (!process.stdout.isTTY)
151
+ return false;
152
+ // Narrow terminals (< 60 cols) can't render the big-text wordmark well —
153
+ // skip rather than show a clipped logo.
154
+ const cols = process.stdout.columns ?? 80;
155
+ if (cols < 60)
156
+ return false;
157
+ return true;
158
+ }
159
+ //# sourceMappingURL=BootSplash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BootSplash.js","sourceRoot":"","sources":["../../src/screens/BootSplash.tsx"],"names":[],"mappings":"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"}