linersh 0.5.7 → 1.0.1

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 (97) hide show
  1. package/README.md +84 -159
  2. package/bin/liner.js +89 -44
  3. package/cli-update-docs/README.md +6 -6
  4. package/cli-update-docs/SKILL.md +72 -37
  5. package/cli-update-docs/quality-check-tests.md +256 -8
  6. package/cli-update-docs/source-finding-tactics.md +140 -3
  7. package/cli-update-docs/source-quality-hierarchy.md +83 -0
  8. package/cli-update-docs/synthesis-guidance.md +19 -5
  9. package/dist/agents/artifact-validation.js +440 -0
  10. package/dist/agents/artifact-validation.js.map +1 -0
  11. package/dist/agents/candidate-longlist.js +100 -0
  12. package/dist/agents/candidate-longlist.js.map +1 -0
  13. package/dist/agents/detect.js +3 -2
  14. package/dist/agents/detect.js.map +1 -1
  15. package/dist/agents/evaluation-assembly.js +270 -0
  16. package/dist/agents/evaluation-assembly.js.map +1 -0
  17. package/dist/agents/headless-runner.js +227 -0
  18. package/dist/agents/headless-runner.js.map +1 -0
  19. package/dist/agents/jtbd-clarify.js +42 -41
  20. package/dist/agents/jtbd-clarify.js.map +1 -1
  21. package/dist/agents/models.js +6 -7
  22. package/dist/agents/models.js.map +1 -1
  23. package/dist/agents/prompts.js +220 -20
  24. package/dist/agents/prompts.js.map +1 -1
  25. package/dist/agents/runner.js +462 -21
  26. package/dist/agents/runner.js.map +1 -1
  27. package/dist/phases.js +13 -13
  28. package/dist/phases.js.map +1 -1
  29. package/dist/source-inbox.js +297 -0
  30. package/dist/source-inbox.js.map +1 -0
  31. package/dist/version.js +3 -9
  32. package/dist/version.js.map +1 -1
  33. package/dist/yaml-io.js +42 -11
  34. package/dist/yaml-io.js.map +1 -1
  35. package/package.json +26 -23
  36. package/cli-update-docs/ABOUT.md +0 -69
  37. package/cli-update-docs/AI-HANDOFF.md +0 -241
  38. package/cli-update-docs/CURATION.md +0 -261
  39. package/cli-update-docs/JOB-STORY-MIGRATION.md +0 -99
  40. package/cli-update-docs/JTBD-MASTER-PROMPT-ABOUT.md +0 -133
  41. package/cli-update-docs/JTBD-MASTER-PROMPT.md +0 -147
  42. package/cli-update-docs/LINER-MASTER.md +0 -546
  43. package/cli-update-docs/MIXTAPE-FORMAT.md +0 -398
  44. package/cli-update-docs/PLATFORM.md +0 -210
  45. package/cli-update-docs/TUI-BACKLOG.md +0 -155
  46. package/dist/App.js +0 -220
  47. package/dist/App.js.map +0 -1
  48. package/dist/colors.js +0 -132
  49. package/dist/colors.js.map +0 -1
  50. package/dist/components/Header.js +0 -15
  51. package/dist/components/Header.js.map +0 -1
  52. package/dist/components/KeyHints.js +0 -17
  53. package/dist/components/KeyHints.js.map +0 -1
  54. package/dist/components/LabeledBox.js +0 -53
  55. package/dist/components/LabeledBox.js.map +0 -1
  56. package/dist/components/NextSteps.js +0 -18
  57. package/dist/components/NextSteps.js.map +0 -1
  58. package/dist/index.js +0 -17
  59. package/dist/index.js.map +0 -1
  60. package/dist/screens/AgentSetup.js +0 -224
  61. package/dist/screens/AgentSetup.js.map +0 -1
  62. package/dist/screens/BootSplash.js +0 -163
  63. package/dist/screens/BootSplash.js.map +0 -1
  64. package/dist/screens/CompileView.js +0 -567
  65. package/dist/screens/CompileView.js.map +0 -1
  66. package/dist/screens/FramingConfirmReview.js +0 -197
  67. package/dist/screens/FramingConfirmReview.js.map +0 -1
  68. package/dist/screens/Gate1Review.js +0 -147
  69. package/dist/screens/Gate1Review.js.map +0 -1
  70. package/dist/screens/Gate2Review.js +0 -162
  71. package/dist/screens/Gate2Review.js.map +0 -1
  72. package/dist/screens/ImportPrompt.js +0 -173
  73. package/dist/screens/ImportPrompt.js.map +0 -1
  74. package/dist/screens/JsSetup.js +0 -77
  75. package/dist/screens/JsSetup.js.map +0 -1
  76. package/dist/screens/LocalFilePicker.js +0 -139
  77. package/dist/screens/LocalFilePicker.js.map +0 -1
  78. package/dist/screens/NewMixtapeWizard.js +0 -662
  79. package/dist/screens/NewMixtapeWizard.js.map +0 -1
  80. package/dist/screens/PhaseRunner.js +0 -1203
  81. package/dist/screens/PhaseRunner.js.map +0 -1
  82. package/dist/screens/ProcessManifest.js +0 -160
  83. package/dist/screens/ProcessManifest.js.map +0 -1
  84. package/dist/screens/ProjectHub.js +0 -557
  85. package/dist/screens/ProjectHub.js.map +0 -1
  86. package/dist/screens/SourceModal.js +0 -269
  87. package/dist/screens/SourceModal.js.map +0 -1
  88. package/dist/screens/TapeBrowser.js +0 -312
  89. package/dist/screens/TapeBrowser.js.map +0 -1
  90. package/dist/screens/TapeDraftReview.js +0 -444
  91. package/dist/screens/TapeDraftReview.js.map +0 -1
  92. package/dist/screens/TapeEditor.js +0 -310
  93. package/dist/screens/TapeEditor.js.map +0 -1
  94. package/dist/screens/cassette-art.js +0 -72
  95. package/dist/screens/cassette-art.js.map +0 -1
  96. package/dist/store.js +0 -10
  97. package/dist/store.js.map +0 -1
package/README.md CHANGED
@@ -1,197 +1,122 @@
1
- # Liner TUI
1
+ # Liner NPM Shim And Runner Package
2
2
 
3
- Interactive authoring UI for [Liner](../..) — create, edit, compile, and share mixtape **project folders** from the keyboard.
3
+ This package is still named `linersh` because it owns the published `liner`
4
+ binary. It is no longer the React/Ink TUI implementation.
4
5
 
5
- A *tape file* (`tape.yaml`) is the recipe. A *mixtape* is the project folder Liner builds from it. The TUI is for authoring: it scaffolds folders, edits tapes, surfaces the synthesis status, then runs `liner compile` to produce the consumable `MIXTAPE.md` + `sources/` artifacts.
6
+ Active responsibilities:
7
+
8
+ - `bin/liner.js`: npm binary shim
9
+ - Go TUI launcher for `packages/go-tui/` in development
10
+ - TypeScript headless methodology runner under `src/agents/`
11
+ - packaged curation skill bundle copied from `../../docs/curation-skill/` into
12
+ `cli-update-docs/`
13
+ - optional per-platform packages that contain the native CLI and Go TUI
14
+ binaries for installed users
15
+
16
+ The old React/Ink TUI has been decommissioned and is no longer part of the
17
+ active package shape. `LINER_TUI=ink` intentionally fails with a decommissioning
18
+ message.
6
19
 
7
20
  ## Install
8
21
 
9
22
  ```sh
10
- # One-shot:
11
23
  npx linersh
12
-
13
- # Persistent:
14
- npm install -g linersh # adds `liner` to PATH
24
+ npm install -g linersh
15
25
  liner
16
26
  ```
17
27
 
18
- The npm package includes the TUI and resolves the Python core from a per-platform optional package (`linersh-<platform>-<arch>`). With no arguments, `liner` opens the TUI. CLI subcommands such as `liner setup-js`, `liner compile`, `liner share`, and `liner status` pass through to the bundled core.
28
+ With no arguments, `liner` launches the Go TUI. CLI subcommands such as
29
+ `liner compile`, `liner share`, `liner import`, `liner status`, and
30
+ `liner setup-js` pass through to the Python core. If you are using one-shot
31
+ `npx` instead of a global install, pass subcommands through the package:
32
+ `npx --yes linersh@latest setup-js` or
33
+ `npx --yes linersh@latest uninstall --yes`.
19
34
 
20
- For JavaScript-rendered pages, run the setup command from the same npm install:
35
+ ## Try It Cleanly
21
36
 
22
- ```sh
23
- liner setup-js
24
- ```
25
-
26
- That command is idempotent and downloads the Playwright browser used for `render: js` and automatic JS-wall fallback (about 150MB). The TUI also offers this during first-run onboarding, and again from compile results if a source needs JS rendering. For debugging or local development, `LINER_BIN=/path/to/liner liner` overrides the bundled binary.
27
-
28
- To reset a machine for clean testing, run:
37
+ For a regular-user smoke test without touching your real Liner workspace:
29
38
 
30
39
  ```sh
31
- liner uninstall --yes
32
- ```
33
-
34
- This removes `~/.liner`, Playwright's Chromium cache, and npm's `_npx` execution cache. It does not delete your mixtape project folders. If you installed Liner globally, also run `npm uninstall -g linersh`.
40
+ tmp=$(mktemp -d)
41
+ home="$tmp/home"
42
+ cache="$tmp/npm-cache"
43
+ projects="$tmp/projects"
44
+ mkdir -p "$home" "$cache" "$projects"
35
45
 
36
- ## Run
46
+ HOME="$home" npm_config_cache="$cache" LINER_DIR="$projects" npx --yes linersh@latest --version
47
+ HOME="$home" npm_config_cache="$cache" LINER_DIR="$projects" npx --yes linersh@latest
37
48
 
38
- ```sh
39
- cd ~/projects/my-thing
40
- liner
49
+ rm -rf "$tmp"
41
50
  ```
42
51
 
43
- The TUI looks for (and creates) a `./mixtapes/` folder in your current directory. Each subdirectory inside it is a mixtape project folder (must contain a `tape.yaml`).
52
+ The second command opens the Go TUI. Create a test Liner Project, build the
53
+ corpus with your configured local Claude or Codex runner, then run Create
54
+ Operating Layer. Because `HOME`, the npm cache, and `LINER_DIR` all point inside
55
+ `$tmp`, cleanup is just `rm -rf "$tmp"`.
56
+
57
+ ## Run Locally
44
58
 
45
- Override the workspace with `LINER_DIR`:
59
+ From the repo root:
46
60
 
47
61
  ```sh
48
- LINER_DIR=~/mixtapes liner
62
+ npm --prefix packages/tui run dev
49
63
  ```
50
64
 
51
- ## Keys
52
-
53
- ### Browser
54
- | Key | Action |
55
- |---|---|
56
- | `↑` `↓` or `j` `k` | move selection |
57
- | `enter` or `o` | open the selected mixtape hub |
58
- | `e` | open the selected mixtape source editor |
59
- | `n` | new mixtape (prompts for slug) |
60
- | `c` | compile selected |
61
- | `s` | share selected (zip to `.mixtape`) |
62
- | `i` | import a `.mixtape` archive |
63
- | `d` | delete selected folder (with confirm) |
64
- | `r` | refresh |
65
- | `q` | quit |
66
-
67
- ### Project Hub
68
- | Key | Action |
69
- |---|---|
70
- | `↑` `↓` | select phase |
71
- | `enter` | run/open the selected phase's primary action |
72
- | `e` | edit the selected artifact by hand |
73
- | `p` | open the process manifest |
74
- | `s` | share the mixtape |
75
- | `o` | open the project folder |
76
- | `esc` | back |
77
- | `q` | quit |
78
-
79
- Completed mixtapes land in a ready state. If `MIXTAPE.md` is current, pressing `enter` on Compile opens the existing compile result instead of fetching sources again. Press `r` from the compile result screen to explicitly re-run/retry.
80
-
81
- ### Source Editor
82
- | Key | Action |
83
- |---|---|
84
- | `t` `d` `u` | edit title / description / curator |
85
- | `m` | toggle mode (`quick` ⇄ `methodology`) |
86
- | `g` | edit JTBD (job-to-be-done) |
87
- | `E` | open `synthesis.md` in `$EDITOR` |
88
- | `↑` `↓` | select source |
89
- | `a` `e` `x` | add / edit / remove source |
90
- | `K` `J` | reorder selected source up/down |
91
- | `s` | save `tape.yaml` |
92
- | `c` | save + compile (blocked if synthesis is empty or still a placeholder) |
93
- | `esc` | back (warns on unsaved changes) |
94
-
95
- A soft warning appears when any source is missing a curator note. Notes are load-bearing — see [CURATION.md](https://liner.sh) §6.
96
-
97
- #### Local sources
98
-
99
- `local_file` sources reference content you've placed under `<project>/personal/` — book chapter PDFs, Reader-Mode-saved articles, exported HIG pages. Use them for material that isn't on the public web or that lives behind a paywall you have legitimate access to.
100
-
101
- Workflow:
102
-
103
- 1. Save the file into `<project>/personal/`. The TUI creates the folder lazily — the file picker offers a "new file (paste path)" option that you can use after saving the file manually with your OS file manager.
104
- 2. Add a source in the editor; press `T` in the source modal to switch the type to `local_file`.
105
- 3. Pick the file via the picker; supply a `citation` (author, title, publication, date — the AI uses this to weight the source).
106
- 4. Compile. The CLI extracts the content (PDFs via `pdfplumber`, HTML via the same readability pipeline as web sources, `.md`/`.txt` as-is).
107
-
108
- `liner share` includes `personal/` by default. Pass `--no-personal` (or use the corresponding TUI flag) to exclude it — required for any tape intended as a library submission.
109
-
110
- The synthesis indicator shows one of:
111
- - `✗ missing` — `liner compile` will hard-fail
112
- - `⚠ placeholder` — file exists but still has the boilerplate from `liner init`
113
- - `⚠ empty` — file exists but is empty
114
- - `✓ N chars` — ready to compile
115
-
116
- ### Source modal
117
- | Key | Action |
118
- |---|---|
119
- | `↑` `↓` | move between fields |
120
- | `enter` | edit the focused field (or open the file picker on the path field for `local_file` sources) |
121
- | `tab` | next field while editing |
122
- | `T` | toggle source type (`web` ⇄ `local_file`) |
123
- | `R` | toggle `render: server` ⇄ `render: js` (web sources only) |
124
- | `p` | toggle required/optional |
125
- | `s` | save source |
126
- | `esc` | cancel |
127
-
128
- For `web` sources the URL is the load-bearing field; the type is auto-detected as `youtube` or `web`. For `local_file` sources the modal shows `path`, `citation`, `note`, `section`, `priority` — pick the path via the file picker (lists files under `personal/`, with a "paste path" affordance for new files).
129
-
130
- ### Compile
131
- | Key | Action |
132
- |---|---|
133
- | `↑` `↓` | scroll sources |
134
- | `pgup` `pgdn` | jump through sources |
135
- | `j` | install JS rendering support when the result says it is needed |
136
- | `esc` | cancel running compile |
137
- | `y` | copy compiled `MIXTAPE.md` to clipboard (`pbcopy` / `xclip`) |
138
- | `s` | share the compiled mixtape (zip to `.mixtape`) |
139
- | `o` | open the project folder |
140
- | `r` | retry failed sources / re-run compile |
141
- | `b` | back to hub |
142
- | `q` | quit |
143
-
144
- The compile writes `MIXTAPE.md` and `sources/NN-<slug>.md` files directly into the project folder. A partial compile is still treated as a usable finished state when `MIXTAPE.md` is written; the hub shows "compiled with warnings" and the compile result screen lists the remaining warnings. There's nothing to "save" afterwards — the artifacts are already on disk.
145
-
146
- ## Uninstalling
147
-
148
- The TUI ships in the same `linersh` package as the CLI. For npm/npx installs, use the package uninstaller:
65
+ From this package:
149
66
 
150
67
  ```sh
151
- liner uninstall
152
- liner uninstall --yes
68
+ npm run dev
153
69
  ```
154
70
 
155
- It removes `~/.liner`, Playwright's Chromium cache, and npm's `_npx` execution cache. Your mixtape project folders are left alone. If you installed Liner globally, also run `npm uninstall -g linersh`. See the root [README — Uninstalling](../../README.md#uninstalling) for the manual recipe.
156
-
157
- ## Develop
71
+ Override the projects folder:
158
72
 
159
73
  ```sh
160
- cd packages/tui
161
- npm install
162
- npm run dev # tsx (no watch — Ctrl+C and re-run after code changes)
163
- npm run dev:built # builds, then runs the compiled output (closer to ship)
164
- npm run typecheck
165
- npm test # vitest
166
- npm run build # emits dist/
74
+ LINER_DIR=/path/to/projects node bin/liner.js
167
75
  ```
168
76
 
169
- **Why no `tsx watch`?** `tsx watch` keeps the TTY in raw mode for its own restart UI (Enter to restart, "rs" to force, Esc to clear). Ink TUIs also want raw stdin, and the two collide — typed characters get eaten, the app gets surprise-restarted, screens flicker. For interactive UIs, restart manually after code changes.
170
-
171
- In dev, the bin-resolver tries `LINER_BIN`, the bundled optional package, the repo-local `.venv/bin/liner`, then `liner` on `$PATH`. To point at a specific binary:
77
+ Override the Python/core binary:
172
78
 
173
79
  ```sh
174
- LINER_BIN=/path/to/liner npm run dev
80
+ LINER_BIN=/absolute/path/to/liner node bin/liner.js
175
81
  ```
176
82
 
177
- ## Architecture
83
+ ## Build And Test
178
84
 
85
+ ```sh
86
+ npm run build
87
+ npm run build:go
88
+ npm run build:package
89
+ npm test
179
90
  ```
180
- BootSplash ─────► TapeBrowser ──────► ProjectHub ──────┐
181
- │ │
182
- │ ImportPrompt ─────┤
183
- │ │
184
- ├────► NewProjectWizard ─────┤
185
- │ │
186
- ├────► TapeEditor ⇄ SourceModal
187
- │ │
188
- ├────► PhaseRunner / gates / draft review
189
- │ │
190
- └────► CompileView (streams NDJSON from `liner compile --emit-events`)
191
- ```
192
-
193
- State is global via `AppContext`. YAML is parsed and re-written in Node via the `yaml` package's `Document` API so user-written block comments survive edits. All folder operations (`init`, `compile`, `share`, `import`, `list`) go through the Python CLI as subprocesses — the TUI never reimplements them.
194
-
195
- The CLI's `compile --emit-events` streams NDJSON progress events to stdout; the TUI parses each line and updates per-source state live. The final `result` event reports the produced folder, `MIXTAPE.md` path, and per-source file paths.
196
91
 
197
- The same NDJSON protocol will power the planned MCP server, which calls into the same Python core directly without going through the CLI.
92
+ Notes:
93
+
94
+ - `build` compiles the TypeScript headless runner and shared runner utilities.
95
+ - `build:go` compiles `../go-tui/cmd/liner-tui` into `bin/liner-tui` for local
96
+ development.
97
+ - `build:package` runs both.
98
+ - Release packaging is verified with `npm run acceptance:go -- release-smoke`,
99
+ which packs a local platform package plus the main `linersh` package and
100
+ installs both into a clean consumer project.
101
+
102
+ ## Useful Environment Variables
103
+
104
+ - `LINER_DIR=/path/to/projects`: change the projects folder.
105
+ - `LINER_BIN=/path/to/liner`: force the Python/core binary.
106
+ - `LINER_GO_TUI_BIN=/path/to/liner-tui`: force the Go TUI binary.
107
+ - `LINER_HEADLESS_RUNNER=/path/to/headless-runner.js`: force the methodology
108
+ runner script.
109
+ - `LINER_AGENT=codex|claude`: override the agent selected by Liner config.
110
+ - `LINER_TUI=go`: accepted for compatibility, but no longer required.
111
+
112
+ ## Developer Gotchas
113
+
114
+ - Rebuild `bin/liner-tui` after Go changes or the npm shim may launch an older
115
+ binary.
116
+ - Rebuild `dist/` after TypeScript runner changes or methodology will fail.
117
+ - The published main package intentionally excludes `bin/liner-tui`; installed
118
+ users get the native TUI from `linersh-<platform>-<arch>`.
119
+ - If Project Health says `status failed`, check the resolved core. Older bundled
120
+ cores may reject `--no-write`; the Go wrapper has a fallback, but direct
121
+ `node bin/liner.js status ... --no-write` can still fail until platform cores
122
+ are refreshed.
package/bin/liner.js CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  // Entry shim for `npx linersh` / `liner`.
3
3
  //
4
- // No args: launch the Ink TUI from dist/.
4
+ // No args: launch the selected TUI.
5
+ // unset -> launch the Charm Go TUI
6
+ // LINER_TUI=go -> launch the Charm Go TUI explicitly
5
7
  // CLI args: forward to the bundled Python core (or LINER_BIN/dev fallback).
6
8
  //
7
9
  // This lets the npm package expose one binary name while still supporting
@@ -41,6 +43,7 @@ const CLI_COMMANDS = new Set([
41
43
  "clone",
42
44
  "setup-js",
43
45
  "list",
46
+ "skills",
44
47
  "cache",
45
48
  "manifest",
46
49
  "status",
@@ -66,44 +69,69 @@ if (wantsCli(argv)) {
66
69
  process.exit(code ?? 1);
67
70
  });
68
71
  } else {
69
- // Enter the terminal's alternate screen buffer before launching Ink.
70
- //
71
- // Every Ink screen that changes total render height between frames (each
72
- // wizard step, each PhaseRunner stream event, each gate transition) was
73
- // committing older frames to the user's scrollback — producing stacked
74
- // duplicated headers above the visible content. The alternate buffer has
75
- // no scrollback by definition, so the bug class is eliminated.
76
- //
77
- // Trade-off: on exit, the TUI vanishes and the terminal returns to its
78
- // pre-launch state. Post-exit context lives in `.liner-runs/` and
79
- // `MIXTAPE.md`, which are the intended sources of truth anyway.
80
- //
81
- // Only enter alt-screen on a real TTY; piped/redirected stdout shouldn't
82
- // receive raw escape sequences.
83
- const useAltScreen = process.stdout.isTTY === true;
84
-
85
- if (useAltScreen) {
86
- process.stdout.write("\x1b[?1049h");
87
- const restoreScreen = () => {
88
- process.stdout.write("\x1b[?1049l");
89
- };
90
- process.on("exit", restoreScreen);
91
- process.on("SIGINT", () => {
92
- restoreScreen();
93
- process.exit(130);
94
- });
95
- process.on("SIGTERM", () => {
96
- restoreScreen();
97
- process.exit(143);
98
- });
99
- process.on("uncaughtException", (err) => {
100
- restoreScreen();
101
- console.error(err);
102
- process.exit(1);
103
- });
72
+ const tui = (process.env.LINER_TUI || "go").toLowerCase();
73
+ if (tui !== "go") {
74
+ console.error(
75
+ [
76
+ `Unsupported LINER_TUI value: ${process.env.LINER_TUI}`,
77
+ "",
78
+ "The Ink TUI has been decommissioned and moved to the repo's ink/ archive.",
79
+ "Run `liner` with no LINER_TUI override, or set LINER_TUI=go.",
80
+ ].join("\n"),
81
+ );
82
+ process.exit(1);
104
83
  }
105
84
 
106
- await import(join(packageRoot, "dist", "index.js"));
85
+ const resolved = resolveGoTuiBinary();
86
+ const headlessRunner = tryResolveHeadlessRunnerScript();
87
+ const child = spawn(resolved.command, resolved.args, {
88
+ stdio: "inherit",
89
+ cwd: resolved.cwd || process.cwd(),
90
+ env: {
91
+ ...process.env,
92
+ LINER_BIN: process.env.LINER_BIN || tryResolveCliCommand() || "",
93
+ LINER_HEADLESS_RUNNER: process.env.LINER_HEADLESS_RUNNER || headlessRunner || "",
94
+ },
95
+ });
96
+ child.on("exit", (code, signal) => {
97
+ if (signal) {
98
+ process.kill(process.pid, signal);
99
+ return;
100
+ }
101
+ process.exit(code ?? 1);
102
+ });
103
+ }
104
+
105
+ function resolveGoTuiBinary() {
106
+ const envBin = process.env.LINER_GO_TUI_BIN;
107
+ if (envBin && existsSync(envBin)) return { command: envBin, args: [] };
108
+
109
+ const packaged = join(packageRoot, "bin", process.platform === "win32" ? "liner-tui.exe" : "liner-tui");
110
+ if (existsSync(packaged)) return { command: packaged, args: [] };
111
+
112
+ const bundled = findBundledGoTuiBinary();
113
+ if (bundled) return { command: bundled, args: [] };
114
+
115
+ const sourceDir = join(packageRoot, "..", "go-tui");
116
+ if (existsSync(join(sourceDir, "go.mod"))) {
117
+ const go = spawnSync("go", ["version"], { encoding: "utf8" });
118
+ if (go.status === 0) {
119
+ return { command: "go", args: ["run", "./cmd/liner-tui"], cwd: sourceDir };
120
+ }
121
+ }
122
+
123
+ console.error(
124
+ [
125
+ "Could not find the Go Liner TUI.",
126
+ "",
127
+ "Expected one of:",
128
+ " - LINER_GO_TUI_BIN=/path/to/liner-tui",
129
+ " - packages/tui/bin/liner-tui built by npm run build:go",
130
+ " - bundled platform package (linersh-<platform>-<arch>)",
131
+ " - repo source at packages/go-tui with go installed",
132
+ ].join("\n"),
133
+ );
134
+ process.exit(1);
107
135
  }
108
136
 
109
137
  function resolveCliBinary() {
@@ -112,12 +140,12 @@ function resolveCliBinary() {
112
140
  return { command: envBin, args: [] };
113
141
  }
114
142
 
115
- const bundled = findBundledBinary();
116
- if (bundled) return { command: bundled, args: [] };
117
-
118
143
  const repoVenv = findRepoVenvBinary();
119
144
  if (repoVenv) return { command: repoVenv, args: [] };
120
145
 
146
+ const bundled = findBundledBinary();
147
+ if (bundled) return { command: bundled, args: [] };
148
+
121
149
  const pathHit = findPathBinary();
122
150
  if (pathHit) return { command: pathHit, args: [] };
123
151
 
@@ -254,13 +282,25 @@ function playwrightCachePath(home) {
254
282
  }
255
283
 
256
284
  function findBundledBinary() {
285
+ const baseDir = findBundledPackageDir();
286
+ if (!baseDir) return null;
287
+ const candidate = join(baseDir, exeName());
288
+ return existsSync(candidate) ? candidate : null;
289
+ }
290
+
291
+ function findBundledGoTuiBinary() {
292
+ const baseDir = findBundledPackageDir();
293
+ if (!baseDir) return null;
294
+ const candidate = join(baseDir, process.platform === "win32" ? "liner-tui.exe" : "liner-tui");
295
+ return existsSync(candidate) ? candidate : null;
296
+ }
297
+
298
+ function findBundledPackageDir() {
257
299
  const require = createRequire(import.meta.url);
258
300
  const target = `linersh-${process.platform}-${process.arch}`;
259
301
  try {
260
302
  const pkgJson = require.resolve(`${target}/package.json`);
261
- const baseDir = pkgJson.replace(/[\\/]package\.json$/, "");
262
- const candidate = join(baseDir, exeName());
263
- return existsSync(candidate) ? candidate : null;
303
+ return pkgJson.replace(/[\\/]package\.json$/, "");
264
304
  } catch {
265
305
  return null;
266
306
  }
@@ -311,7 +351,12 @@ function readTuiVersion() {
311
351
  function tryResolveCliCommand() {
312
352
  const envBin = process.env.LINER_BIN;
313
353
  if (envBin && existsSync(envBin)) return envBin;
314
- return findBundledBinary() || findRepoVenvBinary() || findPathBinary() || null;
354
+ return findRepoVenvBinary() || findBundledBinary() || findPathBinary() || null;
355
+ }
356
+
357
+ function tryResolveHeadlessRunnerScript() {
358
+ const candidate = join(packageRoot, "dist", "agents", "headless-runner.js");
359
+ return existsSync(candidate) ? candidate : null;
315
360
  }
316
361
 
317
362
  function printVersion() {
@@ -1,6 +1,6 @@
1
1
  # Curating Mixtapes — Skill Bundle
2
2
 
3
- This is the Liner methodology made executable by Claude. The bundle implements CURATION.md v2.0 as instructions to a running AI, drives the mixtape lifecycle from a topic to a project folder ready for `liner compile`, and supports both quick mode (the AI does most of the work, the user confirms at two gates) and methodology mode (the curator engages substantively at every phase).
3
+ This is the Liner methodology made executable by Claude or Codex. The bundle implements CURATION.md v2.0 as instructions to a running AI, drives the mixtape lifecycle from a task description to a project folder ready for `liner compile`, and supports both quick mode (the AI does most of the work, with lightweight gate review) and methodology mode (the curator engages substantively at every phase).
4
4
 
5
5
  It is one of Liner's surfaces, alongside the CLI, the TUI, the planned MCP server, and the planned web builder. The skill is the surface for Claude-Code-native and TUI-subprocess authoring. Methodology-mode curators can also use it directly when working in a Claude Code session.
6
6
 
@@ -18,7 +18,7 @@ curating-mixtapes/
18
18
  └── synthesis-guidance.md # Phase 6
19
19
  ```
20
20
 
21
- `SKILL.md` is the orchestrator. It defines the trigger description, the two modes, the two gates, the eight-phase lifecycle skeleton, the AI biases to compensate for, the boundaries (what the skill does NOT do), and the failure modes to watch. It is always loaded when the skill fires.
21
+ `SKILL.md` is the orchestrator. It defines the trigger description, the two modes, the review gates, the lifecycle skeleton, the AI biases to compensate for, the boundaries (what the skill does NOT do), and the failure modes to watch. It is always loaded when the skill fires.
22
22
 
23
23
  The five companion files are loaded only at the phases that use them. Phases 1, 3, 7, and 8 have no companion file — their guidance fits inside SKILL.md.
24
24
 
@@ -28,7 +28,7 @@ The split is deliberate. Every invocation pulls SKILL.md's ~2,300 words into con
28
28
 
29
29
  **Local testing.** Drop this directory into `~/.claude/skills/curating-mixtapes/`. Claude Code and Claude Desktop both look there for user-installed skills. The skill fires when the user says something the description matches — "help me make a mixtape on [topic]" is the canonical trigger.
30
30
 
31
- **Shipping.** The canonical bundle lives at repo-root `cli-update-docs/`. The TUI copies this directory into `packages/tui/cli-update-docs/` during `prepack` and ships it inside the `linersh` npm package, so end users do not need a separate skill install for TUI-driven agent phases.
31
+ **Shipping.** The canonical bundle lives at `docs/curation-skill/`. The TUI copies this directory into `packages/tui/cli-update-docs/` during `prepack` and ships it inside the `linersh` npm package, so end users do not need a separate skill install for TUI-driven agent phases.
32
32
 
33
33
  **Direct skill use.** A documented copy/install flow for using the skill outside the TUI is still planned. Until then, direct local use is a developer workflow.
34
34
 
@@ -48,7 +48,7 @@ The user says something the description matches. Claude loads SKILL.md. Claude r
48
48
 
49
49
  At Phase 2, Claude reads `source-finding-tactics.md`. At Phase 4, Claude reads `source-quality-hierarchy.md` and `curator-notes.md`. At Phase 5, Claude reads `quality-check-tests.md`. At Phase 6, Claude reads `synthesis-guidance.md`. Each companion file is read at the start of its phase, before any work in that phase happens.
50
50
 
51
- The two gates pause for user input. In quick mode, the default is "looks good, continue" — Claude proceeds unless the user actively objects. In methodology mode, Claude pauses for substantive review.
51
+ The gates pause for user input. In quick mode, defaults can auto-continue while preserving project state. In methodology mode, the AI pauses for substantive review.
52
52
 
53
53
  The skill writes artifacts to a project folder named for the topic (e.g., `mobile-design-foundations/`) as it goes. The working notes are produced phase by phase, so the user can stop at any phase boundary and resume later — the working files are picked up where they were left.
54
54
 
@@ -80,7 +80,7 @@ The bundle is functional and ships inside the npm TUI package so agent-backed ph
80
80
 
81
81
  The bundle still benefits from more worked examples in the companion files, but it is no longer blocked by the old "second pass before any shipping" constraint. Current product risk lives more in curation quality and fetcher edge cases than in basic skill availability.
82
82
 
83
- As of `linersh@0.5.5`, compilation is the product completion milestone. A project can be "ready to use — compiled with warnings" when `MIXTAPE.md` is written but some sources are missing or soft-failed. The TUI opens the existing compile result for a completed mixtape and requires an explicit retry/re-run from that screen.
83
+ As of `linersh@1.0.0`, compilation is the corpus-ready milestone and Create Operating Layer is the project-complete milestone. A project can be "ready to use — compiled with warnings" when `MIXTAPE.md` is written but some sources are missing or soft-failed. The TUI opens the existing compile result for a completed mixtape and requires an explicit retry/re-run from that screen. Framing also has a validation contract: Phase 1 must produce a capability brief and required source roles before source discovery can proceed.
84
84
 
85
85
  ## Versioning
86
86
 
@@ -100,7 +100,7 @@ The skill is the methodology made executable. It sits alongside Liner's other su
100
100
 
101
101
  **The Liner CLI** runs `liner compile` against the project folder this skill produces. The skill never compiles; the CLI never authors. Clean split.
102
102
 
103
- **The Liner TUI** invokes this skill internally for quick-mode authoring via the Claude Agent SDK. Same methodology, different UX.
103
+ **The Liner TUI** invokes this skill internally for agent-backed authoring via the local Claude or Codex CLI. Same methodology, different UX.
104
104
 
105
105
  **The Liner MCP server** (planned) will expose mechanical operations — fetch this URL, validate this tape file, query the cache — as tools. A future skill version will use those tools where v1 uses Claude's own web search.
106
106