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.
- package/README.md +84 -159
- package/bin/liner.js +89 -44
- package/cli-update-docs/README.md +6 -6
- package/cli-update-docs/SKILL.md +72 -37
- package/cli-update-docs/quality-check-tests.md +256 -8
- package/cli-update-docs/source-finding-tactics.md +140 -3
- package/cli-update-docs/source-quality-hierarchy.md +83 -0
- package/cli-update-docs/synthesis-guidance.md +19 -5
- package/dist/agents/artifact-validation.js +440 -0
- package/dist/agents/artifact-validation.js.map +1 -0
- package/dist/agents/candidate-longlist.js +100 -0
- package/dist/agents/candidate-longlist.js.map +1 -0
- package/dist/agents/detect.js +3 -2
- package/dist/agents/detect.js.map +1 -1
- package/dist/agents/evaluation-assembly.js +270 -0
- package/dist/agents/evaluation-assembly.js.map +1 -0
- package/dist/agents/headless-runner.js +227 -0
- package/dist/agents/headless-runner.js.map +1 -0
- package/dist/agents/jtbd-clarify.js +42 -41
- package/dist/agents/jtbd-clarify.js.map +1 -1
- package/dist/agents/models.js +6 -7
- package/dist/agents/models.js.map +1 -1
- package/dist/agents/prompts.js +220 -20
- package/dist/agents/prompts.js.map +1 -1
- package/dist/agents/runner.js +462 -21
- package/dist/agents/runner.js.map +1 -1
- package/dist/phases.js +13 -13
- package/dist/phases.js.map +1 -1
- package/dist/source-inbox.js +297 -0
- package/dist/source-inbox.js.map +1 -0
- package/dist/version.js +3 -9
- package/dist/version.js.map +1 -1
- package/dist/yaml-io.js +42 -11
- package/dist/yaml-io.js.map +1 -1
- package/package.json +26 -23
- package/cli-update-docs/ABOUT.md +0 -69
- package/cli-update-docs/AI-HANDOFF.md +0 -241
- package/cli-update-docs/CURATION.md +0 -261
- package/cli-update-docs/JOB-STORY-MIGRATION.md +0 -99
- package/cli-update-docs/JTBD-MASTER-PROMPT-ABOUT.md +0 -133
- package/cli-update-docs/JTBD-MASTER-PROMPT.md +0 -147
- package/cli-update-docs/LINER-MASTER.md +0 -546
- package/cli-update-docs/MIXTAPE-FORMAT.md +0 -398
- package/cli-update-docs/PLATFORM.md +0 -210
- package/cli-update-docs/TUI-BACKLOG.md +0 -155
- package/dist/App.js +0 -220
- package/dist/App.js.map +0 -1
- package/dist/colors.js +0 -132
- package/dist/colors.js.map +0 -1
- package/dist/components/Header.js +0 -15
- package/dist/components/Header.js.map +0 -1
- package/dist/components/KeyHints.js +0 -17
- package/dist/components/KeyHints.js.map +0 -1
- package/dist/components/LabeledBox.js +0 -53
- package/dist/components/LabeledBox.js.map +0 -1
- package/dist/components/NextSteps.js +0 -18
- package/dist/components/NextSteps.js.map +0 -1
- package/dist/index.js +0 -17
- package/dist/index.js.map +0 -1
- package/dist/screens/AgentSetup.js +0 -224
- package/dist/screens/AgentSetup.js.map +0 -1
- package/dist/screens/BootSplash.js +0 -163
- package/dist/screens/BootSplash.js.map +0 -1
- package/dist/screens/CompileView.js +0 -567
- package/dist/screens/CompileView.js.map +0 -1
- package/dist/screens/FramingConfirmReview.js +0 -197
- package/dist/screens/FramingConfirmReview.js.map +0 -1
- package/dist/screens/Gate1Review.js +0 -147
- package/dist/screens/Gate1Review.js.map +0 -1
- package/dist/screens/Gate2Review.js +0 -162
- package/dist/screens/Gate2Review.js.map +0 -1
- package/dist/screens/ImportPrompt.js +0 -173
- package/dist/screens/ImportPrompt.js.map +0 -1
- package/dist/screens/JsSetup.js +0 -77
- package/dist/screens/JsSetup.js.map +0 -1
- package/dist/screens/LocalFilePicker.js +0 -139
- package/dist/screens/LocalFilePicker.js.map +0 -1
- package/dist/screens/NewMixtapeWizard.js +0 -662
- package/dist/screens/NewMixtapeWizard.js.map +0 -1
- package/dist/screens/PhaseRunner.js +0 -1203
- package/dist/screens/PhaseRunner.js.map +0 -1
- package/dist/screens/ProcessManifest.js +0 -160
- package/dist/screens/ProcessManifest.js.map +0 -1
- package/dist/screens/ProjectHub.js +0 -557
- package/dist/screens/ProjectHub.js.map +0 -1
- package/dist/screens/SourceModal.js +0 -269
- package/dist/screens/SourceModal.js.map +0 -1
- package/dist/screens/TapeBrowser.js +0 -312
- package/dist/screens/TapeBrowser.js.map +0 -1
- package/dist/screens/TapeDraftReview.js +0 -444
- package/dist/screens/TapeDraftReview.js.map +0 -1
- package/dist/screens/TapeEditor.js +0 -310
- package/dist/screens/TapeEditor.js.map +0 -1
- package/dist/screens/cassette-art.js +0 -72
- package/dist/screens/cassette-art.js.map +0 -1
- package/dist/store.js +0 -10
- package/dist/store.js.map +0 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import * as YAML from "yaml";
|
|
4
|
+
import { countCandidateUrlsFromLonglist, normalizeCandidateUrl, readCandidateLonglist, } from "./candidate-longlist.js";
|
|
5
|
+
import { validateEvaluation } from "./artifact-validation.js";
|
|
6
|
+
const DECISIONS = new Set(["kept", "trim", "trimmed", "dropped"]);
|
|
7
|
+
const JTBD_FITS = new Set(["direct", "bridge", "background"]);
|
|
8
|
+
const FETCH_STATUSES = new Set(["readable", "partial", "metadata_only", "unavailable"]);
|
|
9
|
+
const USABLE_FETCH_STATUSES = new Set(["readable", "partial"]);
|
|
10
|
+
const CONTENT_QUALITIES = new Set(["high", "medium", "low"]);
|
|
11
|
+
const USABLE_CONTENT_QUALITIES = new Set(["high", "medium"]);
|
|
12
|
+
export function ensureEvaluationArtifact(project) {
|
|
13
|
+
const finalPath = join(project, "working/03-evaluation.yaml");
|
|
14
|
+
const expectedCandidateCount = countCandidateUrlsFromLonglist(join(project, "working/02-candidate-longlist.md"));
|
|
15
|
+
const existing = validateEvaluation(finalPath, { expectedCandidateCount });
|
|
16
|
+
if (existing.ok)
|
|
17
|
+
return { ok: true, assembled: false };
|
|
18
|
+
const assembled = assembleEvaluationFromFragments(project);
|
|
19
|
+
if (!assembled.ok) {
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
message: `${existing.message}; fragment assembly failed: ${assembled.message}`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const validation = validateEvaluation(finalPath, { expectedCandidateCount });
|
|
26
|
+
if (!validation.ok) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
message: `assembled working/03-evaluation.yaml is invalid: ${validation.message}`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
ok: true,
|
|
34
|
+
assembled: true,
|
|
35
|
+
message: `Assembled working/03-evaluation.yaml with ${assembled.count} Evaluation decisions from fragments.`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function assembleEvaluationFromFragments(project) {
|
|
39
|
+
const longlistPath = join(project, "working/02-candidate-longlist.md");
|
|
40
|
+
const candidates = readCandidateLonglist(longlistPath);
|
|
41
|
+
if (candidates.length === 0) {
|
|
42
|
+
return { ok: false, message: "working/02-candidate-longlist.md has no URL candidates" };
|
|
43
|
+
}
|
|
44
|
+
const fragments = readEvaluationFragments(join(project, "working/evaluation-decisions"));
|
|
45
|
+
if (fragments.length === 0) {
|
|
46
|
+
return { ok: false, message: "working/evaluation-decisions has no YAML decision fragments" };
|
|
47
|
+
}
|
|
48
|
+
const byUrl = new Map();
|
|
49
|
+
for (const fragment of fragments) {
|
|
50
|
+
const url = stringField(fragment, "url");
|
|
51
|
+
if (!url)
|
|
52
|
+
return { ok: false, message: "a decision fragment is missing url" };
|
|
53
|
+
const decision = normalizeDecision(stringField(fragment, "decision"));
|
|
54
|
+
if (!DECISIONS.has(decision)) {
|
|
55
|
+
return { ok: false, message: `decision fragment for ${url} has invalid decision: ${decision || "(empty)"}` };
|
|
56
|
+
}
|
|
57
|
+
byUrl.set(normalizeCandidateUrl(url), { ...fragment, decision });
|
|
58
|
+
}
|
|
59
|
+
const missing = candidates.filter((candidate) => !byUrl.has(candidate.url));
|
|
60
|
+
if (missing.length > 0) {
|
|
61
|
+
return {
|
|
62
|
+
ok: false,
|
|
63
|
+
message: `missing decision fragments for ${missing.length} candidates, first: ${missing[0]?.url}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const assembled = candidates.map((candidate) => normalizeDecisionRecord(candidate, byUrl.get(candidate.url)));
|
|
67
|
+
const outputPath = join(project, "working/03-evaluation.yaml");
|
|
68
|
+
mkdirSync(join(project, "working"), { recursive: true });
|
|
69
|
+
writeFileSync(outputPath, YAML.stringify({ candidates: assembled }), "utf8");
|
|
70
|
+
return { ok: true, path: outputPath, count: assembled.length };
|
|
71
|
+
}
|
|
72
|
+
export function validateEvaluationFragment(path, candidates) {
|
|
73
|
+
const parsed = readEvaluationFragmentFile(path);
|
|
74
|
+
if (!parsed.ok)
|
|
75
|
+
return parsed;
|
|
76
|
+
const expectedUrls = new Set(candidates.map((candidate) => candidate.url));
|
|
77
|
+
const candidateByUrl = new Map(candidates.map((candidate) => [candidate.url, candidate]));
|
|
78
|
+
const seen = new Set();
|
|
79
|
+
for (const [i, fragment] of parsed.records.entries()) {
|
|
80
|
+
const rawUrl = stringField(fragment, "url");
|
|
81
|
+
if (!rawUrl)
|
|
82
|
+
return { ok: false, message: `fragment candidates[${i}].url is required` };
|
|
83
|
+
const url = normalizeCandidateUrl(rawUrl);
|
|
84
|
+
if (!expectedUrls.has(url)) {
|
|
85
|
+
return { ok: false, message: `fragment includes unexpected URL: ${url}` };
|
|
86
|
+
}
|
|
87
|
+
if (seen.has(url)) {
|
|
88
|
+
return { ok: false, message: `fragment includes duplicate URL: ${url}` };
|
|
89
|
+
}
|
|
90
|
+
seen.add(url);
|
|
91
|
+
const decision = normalizeDecision(stringField(fragment, "decision"));
|
|
92
|
+
if (!DECISIONS.has(decision)) {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
message: `fragment candidate ${url} has invalid decision: ${decision || "(empty)"}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (decision === "kept" || decision === "trim") {
|
|
99
|
+
const rating = numericField(fragment, "rating");
|
|
100
|
+
if (rating == null || rating < 1 || rating > 5) {
|
|
101
|
+
return { ok: false, message: `fragment candidate ${url} rating must be 1-5 for ${decision}` };
|
|
102
|
+
}
|
|
103
|
+
const jtbdFit = stringField(fragment, "jtbd_fit");
|
|
104
|
+
if (!JTBD_FITS.has(jtbdFit)) {
|
|
105
|
+
return { ok: false, message: `fragment candidate ${url} jtbd_fit is invalid: ${jtbdFit || "(empty)"}` };
|
|
106
|
+
}
|
|
107
|
+
if (!stringField(fragment, "section") && !candidateByUrl.get(url)?.section) {
|
|
108
|
+
return { ok: false, message: `fragment candidate ${url} section is required for ${decision}` };
|
|
109
|
+
}
|
|
110
|
+
if (!stringField(fragment, "note")) {
|
|
111
|
+
return { ok: false, message: `fragment candidate ${url} note is required for ${decision}` };
|
|
112
|
+
}
|
|
113
|
+
const evidence = validateFragmentEvidence(fragment, url, decision);
|
|
114
|
+
if (!evidence.ok)
|
|
115
|
+
return evidence;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const missing = candidates.filter((candidate) => !seen.has(candidate.url));
|
|
119
|
+
if (missing.length > 0) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
message: `fragment is missing ${missing.length} candidate(s), first: ${missing[0]?.url}`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return { ok: true, count: seen.size };
|
|
126
|
+
}
|
|
127
|
+
function readEvaluationFragments(dir) {
|
|
128
|
+
if (!existsSync(dir))
|
|
129
|
+
return [];
|
|
130
|
+
const records = [];
|
|
131
|
+
for (const name of readdirSync(dir).filter((file) => /\.ya?ml$/i.test(file)).sort()) {
|
|
132
|
+
const path = join(dir, name);
|
|
133
|
+
const parsed = readEvaluationFragmentFile(path);
|
|
134
|
+
if (parsed.ok)
|
|
135
|
+
records.push(...parsed.records);
|
|
136
|
+
}
|
|
137
|
+
return records;
|
|
138
|
+
}
|
|
139
|
+
function readEvaluationFragmentFile(path) {
|
|
140
|
+
if (!existsSync(path))
|
|
141
|
+
return { ok: false, message: `${path} is missing` };
|
|
142
|
+
let parsed;
|
|
143
|
+
try {
|
|
144
|
+
parsed = YAML.parse(readFileSync(path, "utf8"));
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
return {
|
|
148
|
+
ok: false,
|
|
149
|
+
message: `fragment YAML could not be parsed: ${error instanceof Error ? error.message : String(error)}`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (Array.isArray(parsed)) {
|
|
153
|
+
return { ok: true, records: parsed.filter(isRecord) };
|
|
154
|
+
}
|
|
155
|
+
if (!isRecord(parsed))
|
|
156
|
+
return { ok: false, message: "fragment is not a YAML mapping or list" };
|
|
157
|
+
const candidates = parsed["candidates"];
|
|
158
|
+
if (Array.isArray(candidates)) {
|
|
159
|
+
return { ok: true, records: candidates.filter(isRecord) };
|
|
160
|
+
}
|
|
161
|
+
if (stringField(parsed, "url")) {
|
|
162
|
+
return { ok: true, records: [parsed] };
|
|
163
|
+
}
|
|
164
|
+
return { ok: false, message: "fragment has no candidates list" };
|
|
165
|
+
}
|
|
166
|
+
function normalizeDecisionRecord(candidate, fragment) {
|
|
167
|
+
const decision = normalizeDecision(stringField(fragment, "decision"));
|
|
168
|
+
const out = {
|
|
169
|
+
url: candidate.url,
|
|
170
|
+
title: stringField(fragment, "title") || candidate.title,
|
|
171
|
+
decision,
|
|
172
|
+
section: stringField(fragment, "section") || candidate.section,
|
|
173
|
+
};
|
|
174
|
+
const rationale = stringField(fragment, "rationale");
|
|
175
|
+
if (rationale)
|
|
176
|
+
out["rationale"] = rationale;
|
|
177
|
+
if (decision === "kept" || decision === "trim") {
|
|
178
|
+
const rating = numericField(fragment, "rating");
|
|
179
|
+
if (rating != null)
|
|
180
|
+
out["rating"] = rating;
|
|
181
|
+
const jtbdFit = stringField(fragment, "jtbd_fit");
|
|
182
|
+
if (jtbdFit)
|
|
183
|
+
out["jtbd_fit"] = jtbdFit;
|
|
184
|
+
const note = stringField(fragment, "note");
|
|
185
|
+
if (note)
|
|
186
|
+
out["note"] = note;
|
|
187
|
+
const fetchStatus = stringField(fragment, "fetch_status");
|
|
188
|
+
if (fetchStatus)
|
|
189
|
+
out["fetch_status"] = fetchStatus;
|
|
190
|
+
const contentQuality = stringField(fragment, "content_quality");
|
|
191
|
+
if (contentQuality)
|
|
192
|
+
out["content_quality"] = contentQuality;
|
|
193
|
+
const evidence = stringListField(fragment, "evidence");
|
|
194
|
+
if (evidence.length > 0)
|
|
195
|
+
out["evidence"] = evidence;
|
|
196
|
+
}
|
|
197
|
+
return Object.fromEntries(Object.entries(out).filter(([, value]) => value != null && value !== ""));
|
|
198
|
+
}
|
|
199
|
+
function validateFragmentEvidence(fragment, url, decision) {
|
|
200
|
+
const fetchStatus = stringField(fragment, "fetch_status");
|
|
201
|
+
if (!FETCH_STATUSES.has(fetchStatus)) {
|
|
202
|
+
return { ok: false, message: `fragment candidate ${url} fetch_status is required for ${decision}` };
|
|
203
|
+
}
|
|
204
|
+
if (!USABLE_FETCH_STATUSES.has(fetchStatus)) {
|
|
205
|
+
return {
|
|
206
|
+
ok: false,
|
|
207
|
+
message: `fragment candidate ${url} fetch_status cannot be ${fetchStatus} for ${decision}`,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const contentQuality = stringField(fragment, "content_quality");
|
|
211
|
+
if (!CONTENT_QUALITIES.has(contentQuality)) {
|
|
212
|
+
return { ok: false, message: `fragment candidate ${url} content_quality is required for ${decision}` };
|
|
213
|
+
}
|
|
214
|
+
if (!USABLE_CONTENT_QUALITIES.has(contentQuality)) {
|
|
215
|
+
return {
|
|
216
|
+
ok: false,
|
|
217
|
+
message: `fragment candidate ${url} content_quality cannot be low for ${decision}`,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const evidence = stringListField(fragment, "evidence");
|
|
221
|
+
if (evidence.length < 2) {
|
|
222
|
+
return {
|
|
223
|
+
ok: false,
|
|
224
|
+
message: `fragment candidate ${url} evidence needs at least two content-specific bullets for ${decision}`,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return { ok: true, count: 1 };
|
|
228
|
+
}
|
|
229
|
+
function normalizeDecision(decision) {
|
|
230
|
+
return decision === "trimmed" ? "trim" : decision;
|
|
231
|
+
}
|
|
232
|
+
function isRecord(value) {
|
|
233
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
234
|
+
}
|
|
235
|
+
function stringField(record, key) {
|
|
236
|
+
const value = record[key];
|
|
237
|
+
return typeof value === "string" ? value.trim() : "";
|
|
238
|
+
}
|
|
239
|
+
function numericField(record, key) {
|
|
240
|
+
const value = record[key];
|
|
241
|
+
if (typeof value === "number")
|
|
242
|
+
return value;
|
|
243
|
+
if (typeof value !== "string")
|
|
244
|
+
return null;
|
|
245
|
+
const parsed = Number(value);
|
|
246
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
247
|
+
}
|
|
248
|
+
function stringListField(record, key) {
|
|
249
|
+
const value = record[key];
|
|
250
|
+
if (!Array.isArray(value))
|
|
251
|
+
return [];
|
|
252
|
+
return value
|
|
253
|
+
.map(yamlListItemToString)
|
|
254
|
+
.filter((item) => item !== "");
|
|
255
|
+
}
|
|
256
|
+
function yamlListItemToString(item) {
|
|
257
|
+
if (typeof item === "string")
|
|
258
|
+
return item.trim();
|
|
259
|
+
if (!isRecord(item))
|
|
260
|
+
return "";
|
|
261
|
+
const entries = Object.entries(item);
|
|
262
|
+
if (entries.length !== 1)
|
|
263
|
+
return "";
|
|
264
|
+
const [key, value] = entries[0];
|
|
265
|
+
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
|
|
266
|
+
return "";
|
|
267
|
+
}
|
|
268
|
+
return `${key}: ${String(value)}`.trim();
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=evaluation-assembly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluation-assembly.js","sourceRoot":"","sources":["../../src/agents/evaluation-assembly.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, dirname, resolve } from "node:path";
|
|
4
|
+
import { detectAgents, resolveSkillPathWithDiagnostics } from "./detect.js";
|
|
5
|
+
import { runPhaseWithAgent } from "./runner.js";
|
|
6
|
+
import { readConfig, resolveConfiguredAgent } from "../config.js";
|
|
7
|
+
import { projectFolder, readTape } from "../yaml-io.js";
|
|
8
|
+
const AGENT_PHASES = new Set([
|
|
9
|
+
"framing",
|
|
10
|
+
"candidates",
|
|
11
|
+
"evaluation",
|
|
12
|
+
"quality",
|
|
13
|
+
"synthesis",
|
|
14
|
+
"assembly",
|
|
15
|
+
]);
|
|
16
|
+
let stdoutBroken = false;
|
|
17
|
+
process.stdout.on("error", (error) => {
|
|
18
|
+
if (isBrokenPipeError(error)) {
|
|
19
|
+
stdoutBroken = true;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
});
|
|
24
|
+
export function parseHeadlessArgs(argv) {
|
|
25
|
+
const values = new Map();
|
|
26
|
+
let resume = false;
|
|
27
|
+
for (let i = 0; i < argv.length; i++) {
|
|
28
|
+
const arg = argv[i] ?? "";
|
|
29
|
+
if (arg === "--help" || arg === "-h") {
|
|
30
|
+
return { ok: false, code: 0, message: usage() };
|
|
31
|
+
}
|
|
32
|
+
if (arg === "--resume") {
|
|
33
|
+
resume = true;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const [name, inlineValue] = splitArg(arg);
|
|
37
|
+
if (!name) {
|
|
38
|
+
return { ok: false, code: 2, message: `Unknown argument: ${arg}` };
|
|
39
|
+
}
|
|
40
|
+
const value = inlineValue ?? argv[++i];
|
|
41
|
+
if (value == null || value.startsWith("--")) {
|
|
42
|
+
return { ok: false, code: 2, message: `Missing value for --${name}` };
|
|
43
|
+
}
|
|
44
|
+
values.set(name, value);
|
|
45
|
+
}
|
|
46
|
+
const project = values.get("project")?.trim();
|
|
47
|
+
if (!project) {
|
|
48
|
+
return { ok: false, code: 2, message: "Missing required --project" };
|
|
49
|
+
}
|
|
50
|
+
const rawPhase = values.get("phase")?.trim();
|
|
51
|
+
if (!rawPhase || !AGENT_PHASES.has(rawPhase)) {
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
code: 2,
|
|
55
|
+
message: `--phase must be one of: ${Array.from(AGENT_PHASES).join(", ")}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const rawAgent = values.get("agent")?.trim() ?? "auto";
|
|
59
|
+
if (rawAgent !== "auto" && rawAgent !== "claude" && rawAgent !== "codex") {
|
|
60
|
+
return { ok: false, code: 2, message: "--agent must be auto, claude, or codex" };
|
|
61
|
+
}
|
|
62
|
+
const skillPath = values.get("skill-path")?.trim();
|
|
63
|
+
return {
|
|
64
|
+
ok: true,
|
|
65
|
+
args: {
|
|
66
|
+
project,
|
|
67
|
+
phaseId: rawPhase,
|
|
68
|
+
agent: rawAgent,
|
|
69
|
+
skillPath: skillPath || undefined,
|
|
70
|
+
resume,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function selectHeadlessAgent(choice, installed, config = readConfig()) {
|
|
75
|
+
if (choice !== "auto") {
|
|
76
|
+
const agent = installed.find((candidate) => candidate.id === choice);
|
|
77
|
+
if (agent)
|
|
78
|
+
return { ok: true, agent };
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
code: 2,
|
|
82
|
+
message: `${choice} agent was requested, but it was not found on PATH.`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const configured = resolveConfiguredAgent(installed, config);
|
|
86
|
+
if (configured)
|
|
87
|
+
return { ok: true, agent: configured };
|
|
88
|
+
if (installed.length === 0) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
code: 2,
|
|
92
|
+
message: "No supported agent found on PATH. Install Claude Code or Codex.",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
code: 2,
|
|
98
|
+
message: `Multiple agents found (${installed.map((a) => a.id).join(", ")}). ` +
|
|
99
|
+
`Pass --agent or set LINER_AGENT.`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
103
|
+
const parsed = parseHeadlessArgs(argv);
|
|
104
|
+
if (!parsed.ok) {
|
|
105
|
+
if (parsed.code === 0) {
|
|
106
|
+
process.stdout.write(parsed.message + "\n");
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
emit({ kind: "runner_error", message: parsed.message });
|
|
110
|
+
}
|
|
111
|
+
return parsed.code;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const args = parsed.args;
|
|
115
|
+
const skillPath = resolveHeadlessSkillPath(args.skillPath);
|
|
116
|
+
if (!skillPath) {
|
|
117
|
+
emit({
|
|
118
|
+
kind: "runner_error",
|
|
119
|
+
message: "Could not find the curating-mixtapes skill bundle. Pass --skill-path.",
|
|
120
|
+
});
|
|
121
|
+
return 2;
|
|
122
|
+
}
|
|
123
|
+
const selection = selectHeadlessAgent(args.agent, detectAgents());
|
|
124
|
+
if (!selection.ok) {
|
|
125
|
+
emit({ kind: "runner_error", message: selection.message });
|
|
126
|
+
return selection.code;
|
|
127
|
+
}
|
|
128
|
+
const folder = projectFolder(args.project);
|
|
129
|
+
const { tape } = readTape(folder.tapePath);
|
|
130
|
+
const handle = runPhaseWithAgent({
|
|
131
|
+
agent: selection.agent,
|
|
132
|
+
phaseId: args.phaseId,
|
|
133
|
+
project: folder.path,
|
|
134
|
+
skillPath,
|
|
135
|
+
tape,
|
|
136
|
+
resume: args.resume,
|
|
137
|
+
onEvent: emit,
|
|
138
|
+
});
|
|
139
|
+
emit({
|
|
140
|
+
kind: "runner_start",
|
|
141
|
+
phaseId: args.phaseId,
|
|
142
|
+
project: folder.path,
|
|
143
|
+
agent: selection.agent.id,
|
|
144
|
+
skillPath,
|
|
145
|
+
resume: args.resume,
|
|
146
|
+
});
|
|
147
|
+
const cancel = () => handle.cancel();
|
|
148
|
+
process.once("SIGINT", cancel);
|
|
149
|
+
process.once("SIGTERM", cancel);
|
|
150
|
+
const result = await handle.done;
|
|
151
|
+
process.off("SIGINT", cancel);
|
|
152
|
+
process.off("SIGTERM", cancel);
|
|
153
|
+
emit({
|
|
154
|
+
kind: "runner_done",
|
|
155
|
+
code: result.code,
|
|
156
|
+
stderr: result.stderr || undefined,
|
|
157
|
+
});
|
|
158
|
+
return result.code ?? 1;
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
emit({
|
|
162
|
+
kind: "runner_error",
|
|
163
|
+
message: error instanceof Error ? error.message : String(error),
|
|
164
|
+
});
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export function resolveHeadlessSkillPath(explicit) {
|
|
169
|
+
if (!explicit)
|
|
170
|
+
return resolveSkillPathWithDiagnostics().path;
|
|
171
|
+
const expanded = explicit === "~"
|
|
172
|
+
? homedir()
|
|
173
|
+
: explicit.startsWith("~/")
|
|
174
|
+
? resolve(homedir(), explicit.slice(2))
|
|
175
|
+
: explicit;
|
|
176
|
+
const directory = basename(expanded) === "SKILL.md" ? dirname(expanded) : expanded;
|
|
177
|
+
return resolve(directory);
|
|
178
|
+
}
|
|
179
|
+
function splitArg(arg) {
|
|
180
|
+
if (!arg.startsWith("--"))
|
|
181
|
+
return [null, undefined];
|
|
182
|
+
const body = arg.slice(2);
|
|
183
|
+
const eq = body.indexOf("=");
|
|
184
|
+
if (eq === -1)
|
|
185
|
+
return [body, undefined];
|
|
186
|
+
return [body.slice(0, eq), body.slice(eq + 1)];
|
|
187
|
+
}
|
|
188
|
+
function emit(event) {
|
|
189
|
+
if (stdoutBroken)
|
|
190
|
+
return;
|
|
191
|
+
if (!writeHeadlessEvent(event))
|
|
192
|
+
stdoutBroken = true;
|
|
193
|
+
}
|
|
194
|
+
export function writeHeadlessEvent(event, write = (line) => process.stdout.write(line)) {
|
|
195
|
+
try {
|
|
196
|
+
write(JSON.stringify(event) + "\n");
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
if (isBrokenPipeError(error))
|
|
201
|
+
return false;
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
export function isBrokenPipeError(error) {
|
|
206
|
+
return Boolean(error &&
|
|
207
|
+
typeof error === "object" &&
|
|
208
|
+
"code" in error &&
|
|
209
|
+
error.code === "EPIPE");
|
|
210
|
+
}
|
|
211
|
+
function usage() {
|
|
212
|
+
return [
|
|
213
|
+
"Usage: node dist/agents/headless-runner.js --project <path> --phase <phase> [options]",
|
|
214
|
+
"",
|
|
215
|
+
"Options:",
|
|
216
|
+
" --agent auto|claude|codex Agent to run. Defaults to auto.",
|
|
217
|
+
" --skill-path <path> Directory containing SKILL.md.",
|
|
218
|
+
" --resume Continue the last agent session for this project.",
|
|
219
|
+
" -h, --help Show this help.",
|
|
220
|
+
].join("\n");
|
|
221
|
+
}
|
|
222
|
+
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
223
|
+
void main().then((code) => {
|
|
224
|
+
process.exitCode = code;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=headless-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-runner.js","sourceRoot":"","sources":["../../src/agents/headless-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,38 +1,33 @@
|
|
|
1
|
-
//
|
|
2
|
-
// user
|
|
1
|
+
// Capability elicitation — generate 3-4 clarifying questions targeted at what
|
|
2
|
+
// the user wants this Liner to help a future AI agent do.
|
|
3
3
|
//
|
|
4
4
|
// Runs as a side task at wizard time, not as a methodology phase. The agent
|
|
5
5
|
// answers in JSON; we accumulate streamed text and parse once the run
|
|
6
|
-
// completes. If
|
|
7
|
-
//
|
|
8
|
-
// below — they're the same canonical set the recommendation system uses when
|
|
9
|
-
// the agent path is unavailable. Better to ask predictable questions than
|
|
10
|
-
// to skip the step entirely.
|
|
6
|
+
// completes. If the agent fails, the caller should surface the failure and let
|
|
7
|
+
// the user retry; Liner should not hide the problem behind canned questions.
|
|
11
8
|
import { runAgentTask } from "./runner.js";
|
|
12
9
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* 2. Output kinds expected
|
|
17
|
-
* 3. Quality anchors the curator can name
|
|
18
|
-
* 4. Audience / autonomy mode
|
|
19
|
-
*/
|
|
20
|
-
export const HARDCODED_QUESTIONS = [
|
|
21
|
-
"If your JTBD names multiple domains (e.g. X and Y), are they equally weighted, or is one primary?",
|
|
22
|
-
"What specific kinds of output should this mixtape help produce — flag descriptions, errors, help text, longer docs, all of the above?",
|
|
23
|
-
"Name 1–2 tools, projects, or authors whose work in this domain you admire. These become quality anchors for source discovery.",
|
|
24
|
-
"Is this corpus for an AI assisting you interactively, or for an AI working autonomously?",
|
|
25
|
-
];
|
|
26
|
-
/**
|
|
27
|
-
* Generate clarifying questions for a raw JTBD. Returns the agent's
|
|
28
|
-
* questions on success, or the hardcoded baseline if anything prevents a
|
|
29
|
-
* clean agent answer. Never throws — failure modes degrade to fallback.
|
|
10
|
+
* Generate clarifying questions for a raw capability goal. Returns the agent's
|
|
11
|
+
* questions on success. Throws after retry when no agent is available, the
|
|
12
|
+
* agent crashes or times out, or the answer cannot be parsed.
|
|
30
13
|
*/
|
|
31
14
|
export async function elicitClarifyingQuestions(args) {
|
|
32
15
|
if (!args.agent || !args.skillPath) {
|
|
33
|
-
|
|
16
|
+
throw new Error("Clarifying questions require an available Claude Code or Codex agent and skill bundle");
|
|
17
|
+
}
|
|
18
|
+
const prompt = buildClarifyingQuestionsPrompt(args.jtbd);
|
|
19
|
+
const failures = [];
|
|
20
|
+
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
21
|
+
try {
|
|
22
|
+
return await runClarifyAttempt(args, prompt);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
failures.push(error instanceof Error ? error.message : String(error));
|
|
26
|
+
}
|
|
34
27
|
}
|
|
35
|
-
|
|
28
|
+
throw new Error(`Could not generate clarification questions after retry: ${failures.join("; retry: ")}`);
|
|
29
|
+
}
|
|
30
|
+
async function runClarifyAttempt(args, prompt) {
|
|
36
31
|
// Accumulate every text + tool-result event into one buffer; the response
|
|
37
32
|
// will be in there somewhere. The agent's `summary.finalText` lands at the
|
|
38
33
|
// end and is usually the cleanest source of the JSON.
|
|
@@ -61,40 +56,46 @@ export async function elicitClarifyingQuestions(args) {
|
|
|
61
56
|
}, timeoutMs);
|
|
62
57
|
try {
|
|
63
58
|
const { code } = await handle.done;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
if (timedOut) {
|
|
60
|
+
throw new Error(`${args.agent.name} did not return clarification questions before timeout`);
|
|
61
|
+
}
|
|
62
|
+
if (code !== 0) {
|
|
63
|
+
throw new Error(`${args.agent.name} exited with code ${code}`);
|
|
67
64
|
}
|
|
68
65
|
const body = finalText || textChunks.join("\n");
|
|
69
66
|
const questions = parseQuestions(body);
|
|
70
67
|
if (questions.length === 0) {
|
|
71
|
-
return
|
|
68
|
+
throw new Error(`${args.agent.name} did not return a JSON array of questions`);
|
|
72
69
|
}
|
|
73
70
|
// Clamp to a sane range: at least 2, at most 6. The wizard step renders
|
|
74
71
|
// them one at a time, so very long question lists fatigue the user.
|
|
75
72
|
return questions.slice(0, 6);
|
|
76
73
|
}
|
|
77
|
-
|
|
74
|
+
finally {
|
|
78
75
|
clearTimeout(timeout);
|
|
79
|
-
return [...HARDCODED_QUESTIONS];
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
|
-
function
|
|
83
|
-
return `You are helping a curator sharpen a
|
|
78
|
+
export function buildClarifyingQuestionsPrompt(jtbd) {
|
|
79
|
+
return `You are helping a curator sharpen a plain-language capability goal for a Liner project.
|
|
84
80
|
|
|
85
|
-
# The
|
|
81
|
+
# The capability goal
|
|
86
82
|
${jtbd}
|
|
87
83
|
|
|
88
84
|
# Your task
|
|
89
85
|
|
|
90
|
-
Generate 3-4 targeted questions whose answers will
|
|
86
|
+
Generate 3-4 targeted questions whose answers will help Liner build a hyper-specific, source-grounded resource for a future AI agent. The user should not have to name research lanes, source categories, or formal JTBD syntax. Ask only what is needed to infer those.
|
|
87
|
+
|
|
88
|
+
Ask questions that are specific to this capability. Do not use a generic checklist. Prefer questions that clarify:
|
|
89
|
+
|
|
90
|
+
- what future AI sessions should produce, decide, critique, translate, or prevent
|
|
91
|
+
- the narrow niche or situation where the resource should be excellent
|
|
92
|
+
- domain constraints, risk boundaries, regulated contexts, or things the agent must avoid
|
|
93
|
+
- quality anchors only when the user already hinted at examples, people, products, or styles they care about
|
|
94
|
+
- whether the future agent should ask follow-up questions at runtime or act autonomously from the request and corpus
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
2. **Output kinds** — what specific things will this mixtape help produce (e.g. flag descriptions, errors, designs, prose, etc.)? Force a concrete answer.
|
|
94
|
-
3. **Quality anchors** — name 1-2 tools/projects/authors whose work in this domain the curator admires. These anchor source discovery.
|
|
95
|
-
4. **Audience / autonomy** — is the corpus for an AI assisting interactively, or for an AI working autonomously?
|
|
96
|
+
If the goal involves images, moodboards, references, examples, inspiration, style, art direction, visual language, or translating one medium/domain into another output, include at least one question that clarifies the runtime inputs and output contract. Ask what kinds of references the future agent may receive and what the caller needs back (for example: observations, interpretation, carry-forward rules, implementation vocabulary, avoid-list, or clarification questions). This is not asking the user to name research sources; it is clarifying the job the corpus must support.
|
|
96
97
|
|
|
97
|
-
If the
|
|
98
|
+
If the goal names multiple domains, ask how they relate in the capability. Do not ask the user "what sources should we gather" or "what should Liner extract"; Liner infers that from the capability.
|
|
98
99
|
|
|
99
100
|
# Output format (strict)
|
|
100
101
|
|