@sushanglewis/lincoln 1.5.5 → 1.6.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/dist/main.js +425 -51
- package/dist/main.js.map +1 -1
- package/dist/postinstall.d.ts +9 -2
- package/dist/postinstall.js +812 -6
- package/dist/postinstall.js.map +1 -1
- package/framework/.claude/agents/architect.md +15 -15
- package/framework/.claude/agents/default.md +118 -104
- package/framework/.claude/agents/designer.md +16 -51
- package/framework/.claude/agents/engineer.md +16 -25
- package/framework/.claude/agents/frontend-engineer.md +15 -16
- package/framework/.claude/agents/knowledge-curator.md +18 -15
- package/framework/.claude/agents/pm.md +16 -75
- package/framework/.claude/agents/qa.md +17 -13
- package/framework/.claude/agents/release-coordinator.md +18 -12
- package/framework/.claude/agents/researcher.md +16 -26
- package/framework/.claude/harnesses/command-map.yaml +12 -5
- package/framework/.claude/hooks/on-session-start.sh +0 -1
- package/framework/.claude/schemas/agent-definition.schema.json +6 -1
- package/framework/.claude/schemas/stage-definition.schema.json +49 -4
- package/framework/.claude/skills/build-product-prototype/prompts/main.md +89 -26
- package/framework/.claude/skills/clarify-requirements/prompts/main.md +80 -14
- package/framework/.claude/skills/draft-product-design/prompts/main.md +24 -12
- package/framework/.claude/skills/lc-build-codebase-knowledge/SKILL.md +2 -0
- package/framework/.claude/skills/lc-explore-opensource/SKILL.md +2 -0
- package/framework/.claude/skills/lc-market-research/SKILL.md +1 -1
- package/framework/.claude/skills/lc-one-id/SKILL.md +81 -0
- package/framework/.claude/skills/lc-one-id/prompts/main.md +35 -0
- package/framework/.claude/skills/lc-stakeholder-research/SKILL.md +1 -1
- package/framework/.claude/skills/lc-workflow-router/SKILL.md +2 -0
- package/framework/.claude/stages/build-codebase-knowledge.yaml +10 -10
- package/framework/.claude/stages/clarify.yaml +21 -15
- package/framework/.claude/stages/explore-opensource.yaml +13 -10
- package/framework/.claude/stages/implement.yaml +11 -11
- package/framework/.claude/stages/ingest.yaml +13 -10
- package/framework/.claude/stages/lc-analyze-frameworks.yaml +13 -10
- package/framework/.claude/stages/lc-collect-intelligence.yaml +13 -10
- package/framework/.claude/stages/lc-competitive-analysis.yaml +13 -10
- package/framework/.claude/stages/lc-first-principles.yaml +13 -10
- package/framework/.claude/stages/lc-market-research.yaml +13 -10
- package/framework/.claude/stages/lc-product-research.yaml +13 -10
- package/framework/.claude/stages/lc-research-report.yaml +13 -10
- package/framework/.claude/stages/lc-research-scope.yaml +13 -10
- package/framework/.claude/stages/lc-stakeholder-research.yaml +13 -10
- package/framework/.claude/stages/lc-storytelling.yaml +13 -10
- package/framework/.claude/stages/product-design-docs.yaml +30 -18
- package/framework/.claude/stages/product-prototype.yaml +20 -17
- package/framework/.claude/stages/propose.yaml +16 -9
- package/framework/.claude/stages/split.yaml +13 -9
- package/framework/.claude/stages/sync-knowledge.yaml +20 -9
- package/framework/.claude/stages/tdd-development-plan.yaml +17 -9
- package/framework/.claude/stages/workflow-router.yaml +17 -13
- package/framework/.claude/workflows/bug-fix.yaml +1 -0
- package/framework/.claude/workflows/existing-project-iteration.yaml +1 -0
- package/framework/.claude/workflows/interview-to-knowledge.yaml +1 -0
- package/framework/.claude/workflows/oss-first-design.yaml +1 -0
- package/framework/.claude-plugin/marketplace.json +2 -2
- package/framework/.claude-plugin/plugin.json +2 -1
- package/framework/.version-bump.json +1 -1
- package/framework/README.en.md +15 -2
- package/framework/README.md +16 -3
- package/framework/RELEASE.md +32 -0
- package/framework/manifest.json +93 -73
- package/framework/scripts/check-prompt-drift.py +132 -1
- package/framework/scripts/extract_release_notes.py +79 -0
- package/framework/scripts/init-lincoln-branch.sh +6 -0
- package/framework/scripts/lincoln_command_map.py +1 -1
- package/framework/scripts/lincoln_id.py +333 -0
- package/framework/scripts/lincoln_index.py +10 -0
- package/framework/scripts/lincoln_prd.py +16 -17
- package/framework/scripts/lincoln_render.py +657 -0
- package/framework/scripts/run-infrastructure-tests.py +2 -0
- package/framework/scripts/stage_loader.py +149 -2
- package/framework/scripts/static-check.sh +1 -1
- package/framework/scripts/update_readme_version.py +149 -0
- package/framework/scripts/validate_stage.py +80 -1
- package/framework/tools/lincoln/package-lock.json +2 -2
- package/framework/tools/lincoln/package.json +1 -1
- package/framework/tools/lincoln-installer/package-lock.json +2 -2
- package/framework/tools/lincoln-installer/package.json +1 -1
- package/package.json +2 -2
- package/framework/.claude/agents/_contract.md +0 -79
package/dist/postinstall.js
CHANGED
|
@@ -1,18 +1,824 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/commands/install.ts
|
|
4
|
+
import fs5 from "fs";
|
|
5
|
+
import path6 from "path";
|
|
6
|
+
import { spawn as spawn2 } from "child_process";
|
|
7
|
+
|
|
8
|
+
// src/lib/paths.ts
|
|
9
|
+
import path from "path";
|
|
10
|
+
import os from "os";
|
|
11
|
+
function resolveLincolnPaths(overrideHomeDir) {
|
|
12
|
+
const homeDir = overrideHomeDir ?? os.homedir();
|
|
13
|
+
const lincolnHome = process.env.LINCOLN_HOME ? path.resolve(process.env.LINCOLN_HOME) : path.join(homeDir, ".lincoln");
|
|
14
|
+
return {
|
|
15
|
+
homeDir,
|
|
16
|
+
lincolnHome,
|
|
17
|
+
versionsDir: path.join(lincolnHome, "versions"),
|
|
18
|
+
currentDir: path.join(lincolnHome, "current"),
|
|
19
|
+
versionMarker: path.join(lincolnHome, "marker.json"),
|
|
20
|
+
venvDir: path.join(lincolnHome, "venv"),
|
|
21
|
+
claudeDir: path.join(homeDir, ".claude"),
|
|
22
|
+
codexDir: path.join(homeDir, ".codex"),
|
|
23
|
+
opencodeDir: path.join(homeDir, ".opencode")
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/lib/versionMarker.ts
|
|
28
|
+
import fs from "fs";
|
|
29
|
+
import path2 from "path";
|
|
30
|
+
function writeVersionMarker(paths, marker) {
|
|
31
|
+
fs.mkdirSync(path2.dirname(paths.versionMarker), { recursive: true });
|
|
32
|
+
fs.writeFileSync(paths.versionMarker, JSON.stringify(marker, null, 2) + "\n");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/lib/packageInfo.ts
|
|
36
|
+
import fs2 from "fs";
|
|
37
|
+
import path3 from "path";
|
|
38
|
+
import { fileURLToPath } from "url";
|
|
39
|
+
function readLocalPackageRoot() {
|
|
40
|
+
try {
|
|
41
|
+
let dir = path3.dirname(fileURLToPath(import.meta.url));
|
|
42
|
+
const root = path3.parse(dir).root;
|
|
43
|
+
while (dir !== root) {
|
|
44
|
+
const pkgPath = path3.join(dir, "package.json");
|
|
45
|
+
if (fs2.existsSync(pkgPath)) {
|
|
46
|
+
const parsed = JSON.parse(fs2.readFileSync(pkgPath, "utf8"));
|
|
47
|
+
if (parsed.name === "@sushanglewis/lincoln") {
|
|
48
|
+
return dir;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
dir = path3.dirname(dir);
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
function readLocalPackageVersion() {
|
|
58
|
+
try {
|
|
59
|
+
const root = readLocalPackageRoot();
|
|
60
|
+
if (!root) return void 0;
|
|
61
|
+
const parsed = JSON.parse(fs2.readFileSync(path3.join(root, "package.json"), "utf8"));
|
|
62
|
+
return typeof parsed.version === "string" ? parsed.version : void 0;
|
|
63
|
+
} catch {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function resolvePayloadRoot() {
|
|
68
|
+
const root = readLocalPackageRoot();
|
|
69
|
+
if (!root) return void 0;
|
|
70
|
+
const payload = path3.join(root, "framework");
|
|
71
|
+
return fs2.existsSync(payload) ? payload : void 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/lib/syncClaude.ts
|
|
75
|
+
import fs3 from "fs";
|
|
76
|
+
import path4 from "path";
|
|
77
|
+
import crypto from "crypto";
|
|
78
|
+
|
|
79
|
+
// src/lib/claudeMdMerge.ts
|
|
80
|
+
var BEGIN = "<!-- lincoln:begin -->";
|
|
81
|
+
var END = "<!-- lincoln:end -->";
|
|
82
|
+
function mergeManagedBlock(existing, block) {
|
|
83
|
+
const wrapped = `${BEGIN}
|
|
84
|
+
${block}
|
|
85
|
+
${END}`;
|
|
86
|
+
const text = existing ?? "";
|
|
87
|
+
const beginIndex = text.indexOf(BEGIN);
|
|
88
|
+
const endIndex = text.indexOf(END);
|
|
89
|
+
if (beginIndex !== -1 && endIndex !== -1 && endIndex > beginIndex) {
|
|
90
|
+
return text.slice(0, beginIndex) + wrapped + text.slice(endIndex + END.length);
|
|
91
|
+
}
|
|
92
|
+
if (text.trim().length === 0) {
|
|
93
|
+
return wrapped;
|
|
94
|
+
}
|
|
95
|
+
return `${text.trimEnd()}
|
|
96
|
+
|
|
97
|
+
${wrapped}
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/lib/syncClaude.ts
|
|
102
|
+
var COPY_SUBDIRS = [
|
|
103
|
+
"agents",
|
|
104
|
+
"skills",
|
|
105
|
+
"workflows",
|
|
106
|
+
"stages",
|
|
107
|
+
"schemas",
|
|
108
|
+
"templates",
|
|
109
|
+
"harnesses"
|
|
110
|
+
];
|
|
111
|
+
function sha256(filePath) {
|
|
112
|
+
const data = fs3.readFileSync(filePath);
|
|
113
|
+
return crypto.createHash("sha256").update(data).digest("hex");
|
|
114
|
+
}
|
|
115
|
+
function sameContent(a, b) {
|
|
116
|
+
return sha256(a) === sha256(b);
|
|
117
|
+
}
|
|
118
|
+
function deepMergeSettings(existing, incoming) {
|
|
119
|
+
if (Array.isArray(existing) && Array.isArray(incoming)) {
|
|
120
|
+
return incoming;
|
|
121
|
+
}
|
|
122
|
+
if (typeof existing === "object" && existing !== null && typeof incoming === "object" && incoming !== null) {
|
|
123
|
+
const result = { ...existing };
|
|
124
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
125
|
+
if (key in result) {
|
|
126
|
+
result[key] = deepMergeSettings(result[key], value);
|
|
127
|
+
} else {
|
|
128
|
+
result[key] = value;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
return incoming;
|
|
134
|
+
}
|
|
135
|
+
function syncClaudeCode(opts) {
|
|
136
|
+
const report = {
|
|
137
|
+
written: [],
|
|
138
|
+
skipped: [],
|
|
139
|
+
preserved: [],
|
|
140
|
+
warnings: [],
|
|
141
|
+
settingsTouched: []
|
|
142
|
+
};
|
|
143
|
+
const payloadClaude = path4.join(opts.payloadRoot, ".claude");
|
|
144
|
+
if (!fs3.existsSync(payloadClaude)) {
|
|
145
|
+
report.warnings.push(`payload .claude directory not found: ${payloadClaude}`);
|
|
146
|
+
return report;
|
|
147
|
+
}
|
|
148
|
+
if (!opts.dryRun) {
|
|
149
|
+
fs3.mkdirSync(opts.targetDir, { recursive: true });
|
|
150
|
+
}
|
|
151
|
+
for (const subdir of COPY_SUBDIRS) {
|
|
152
|
+
const srcDir = path4.join(payloadClaude, subdir);
|
|
153
|
+
if (!fs3.existsSync(srcDir)) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const destDir = path4.join(opts.targetDir, subdir);
|
|
157
|
+
if (!opts.dryRun) {
|
|
158
|
+
fs3.mkdirSync(destDir, { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
for (const entry of walkSync(srcDir)) {
|
|
161
|
+
const relativePath = path4.relative(srcDir, entry);
|
|
162
|
+
const srcFile = entry;
|
|
163
|
+
const destFile = path4.join(destDir, relativePath);
|
|
164
|
+
if (fs3.existsSync(destFile) && sameContent(srcFile, destFile)) {
|
|
165
|
+
report.skipped.push(path4.join(".claude", subdir, relativePath));
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (!opts.dryRun) {
|
|
169
|
+
fs3.mkdirSync(path4.dirname(destFile), { recursive: true });
|
|
170
|
+
fs3.copyFileSync(srcFile, destFile);
|
|
171
|
+
}
|
|
172
|
+
report.written.push(path4.join(".claude", subdir, relativePath));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const payloadSettings = path4.join(payloadClaude, "settings.json");
|
|
176
|
+
const targetSettings = path4.join(opts.targetDir, "settings.json");
|
|
177
|
+
if (fs3.existsSync(payloadSettings)) {
|
|
178
|
+
const incoming = JSON.parse(fs3.readFileSync(payloadSettings, "utf8"));
|
|
179
|
+
let merged = incoming;
|
|
180
|
+
if (fs3.existsSync(targetSettings)) {
|
|
181
|
+
const existing = JSON.parse(fs3.readFileSync(targetSettings, "utf8"));
|
|
182
|
+
merged = deepMergeSettings(existing, incoming);
|
|
183
|
+
}
|
|
184
|
+
const wouldChange = !fs3.existsSync(targetSettings) || JSON.stringify(merged) !== JSON.stringify(JSON.parse(fs3.readFileSync(targetSettings, "utf8")));
|
|
185
|
+
if (wouldChange) {
|
|
186
|
+
if (!opts.dryRun) {
|
|
187
|
+
fs3.writeFileSync(targetSettings, JSON.stringify(merged, null, 2) + "\n");
|
|
188
|
+
}
|
|
189
|
+
report.written.push(".claude/settings.json");
|
|
190
|
+
report.settingsTouched = [".claude/settings.json"];
|
|
191
|
+
} else {
|
|
192
|
+
report.skipped.push(".claude/settings.json");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const payloadClaudeMd = path4.join(opts.payloadRoot, "CLAUDE.md");
|
|
196
|
+
const targetClaudeMd = path4.join(path4.dirname(opts.targetDir), "CLAUDE.md");
|
|
197
|
+
if (fs3.existsSync(payloadClaudeMd)) {
|
|
198
|
+
const incomingBlock = fs3.readFileSync(payloadClaudeMd, "utf8");
|
|
199
|
+
const existing = fs3.existsSync(targetClaudeMd) ? fs3.readFileSync(targetClaudeMd, "utf8") : void 0;
|
|
200
|
+
const merged = mergeManagedBlock(existing, incomingBlock);
|
|
201
|
+
if (merged !== existing) {
|
|
202
|
+
if (!opts.dryRun) {
|
|
203
|
+
fs3.writeFileSync(targetClaudeMd, merged);
|
|
204
|
+
}
|
|
205
|
+
report.written.push("CLAUDE.md");
|
|
206
|
+
} else {
|
|
207
|
+
report.skipped.push("CLAUDE.md");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return report;
|
|
211
|
+
}
|
|
212
|
+
function* walkSync(dir) {
|
|
213
|
+
const entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
214
|
+
for (const entry of entries) {
|
|
215
|
+
const fullPath = path4.join(dir, entry.name);
|
|
216
|
+
if (entry.isDirectory()) {
|
|
217
|
+
yield* walkSync(fullPath);
|
|
218
|
+
} else {
|
|
219
|
+
yield fullPath;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/lib/runHarnessAdapter.ts
|
|
225
|
+
import { spawn } from "child_process";
|
|
226
|
+
function runCommand(command, args, spawnCommand) {
|
|
227
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
228
|
+
const child = spawnCommand(command, args, { stdio: "inherit" });
|
|
229
|
+
child.on("close", (code) => {
|
|
230
|
+
resolvePromise(code);
|
|
231
|
+
});
|
|
232
|
+
child.on("error", (err) => {
|
|
233
|
+
rejectPromise(err);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
async function runHarnessAdapter(opts) {
|
|
238
|
+
const report = {
|
|
239
|
+
written: [],
|
|
240
|
+
skipped: [],
|
|
241
|
+
preserved: [],
|
|
242
|
+
warnings: []
|
|
243
|
+
};
|
|
244
|
+
if (opts.dryRun) {
|
|
245
|
+
report.written.push(`${opts.harnessId} (dry run)`);
|
|
246
|
+
return report;
|
|
247
|
+
}
|
|
248
|
+
const args = [
|
|
249
|
+
`${opts.payloadRoot}/scripts/lincoln_harness_adapter.py`,
|
|
250
|
+
"--harness",
|
|
251
|
+
opts.harnessId,
|
|
252
|
+
"--root",
|
|
253
|
+
opts.payloadRoot,
|
|
254
|
+
"--project-dir",
|
|
255
|
+
opts.projectDir,
|
|
256
|
+
"--home-dir",
|
|
257
|
+
opts.homeDir
|
|
258
|
+
];
|
|
259
|
+
try {
|
|
260
|
+
const spawnCommand = opts.spawnCommand ?? spawn;
|
|
261
|
+
const code = await runCommand(opts.pythonPath, args, spawnCommand);
|
|
262
|
+
if (code === 0) {
|
|
263
|
+
report.written.push(opts.harnessId);
|
|
264
|
+
} else {
|
|
265
|
+
report.warnings.push(
|
|
266
|
+
`Adapter for ${opts.harnessId} exited with code ${code}. Run manually to diagnose.`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
} catch (err) {
|
|
270
|
+
report.warnings.push(
|
|
271
|
+
`Failed to run adapter for ${opts.harnessId}: ${err instanceof Error ? err.message : String(err)}`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
return report;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/lib/syncHarness.ts
|
|
278
|
+
function emptyReport() {
|
|
279
|
+
return {
|
|
280
|
+
written: [],
|
|
281
|
+
skipped: [],
|
|
282
|
+
preserved: [],
|
|
283
|
+
warnings: []
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
async function syncHarnesses(opts) {
|
|
287
|
+
const reports = {};
|
|
288
|
+
const syncClaude = opts.syncClaude ?? syncClaudeCode;
|
|
289
|
+
for (const harnessId of opts.harnesses) {
|
|
290
|
+
reports[harnessId] = await syncHarness(harnessId, opts, syncClaude);
|
|
291
|
+
}
|
|
292
|
+
return reports;
|
|
293
|
+
}
|
|
294
|
+
async function syncHarness(harnessId, opts, syncClaude) {
|
|
295
|
+
if (harnessId === "claude-code") {
|
|
296
|
+
return syncClaude({
|
|
297
|
+
payloadRoot: opts.payloadRoot,
|
|
298
|
+
targetDir: opts.paths.claudeDir,
|
|
299
|
+
version: opts.version,
|
|
300
|
+
dryRun: opts.dryRun
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (harnessId === "codex" || harnessId === "opencode") {
|
|
304
|
+
if (opts.dryRun) {
|
|
305
|
+
const report2 = emptyReport();
|
|
306
|
+
report2.written.push(`${harnessId} (dry run)`);
|
|
307
|
+
return report2;
|
|
308
|
+
}
|
|
309
|
+
if (!opts.pythonPath) {
|
|
310
|
+
const report2 = emptyReport();
|
|
311
|
+
report2.warnings.push(
|
|
312
|
+
`Skipped ${harnessId} sync because Python is not available. Install Python 3.10+ or run without --no-venv.`
|
|
313
|
+
);
|
|
314
|
+
return report2;
|
|
315
|
+
}
|
|
316
|
+
return runHarnessAdapter({
|
|
317
|
+
harnessId,
|
|
318
|
+
payloadRoot: opts.payloadRoot,
|
|
319
|
+
projectDir: opts.projectDir,
|
|
320
|
+
homeDir: opts.paths.homeDir,
|
|
321
|
+
pythonPath: opts.pythonPath,
|
|
322
|
+
dryRun: opts.dryRun
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
const report = emptyReport();
|
|
326
|
+
report.warnings.push(`Unsupported harness: ${harnessId}`);
|
|
327
|
+
return report;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/lib/harnessDetect.ts
|
|
331
|
+
import fs4 from "fs";
|
|
332
|
+
import path5 from "path";
|
|
333
|
+
import os2 from "os";
|
|
334
|
+
var HARNESS_SPECS = [
|
|
335
|
+
{
|
|
336
|
+
id: "claude-code",
|
|
337
|
+
configDirName: ".claude",
|
|
338
|
+
pluginMarker: "plugins/lincoln"
|
|
339
|
+
},
|
|
340
|
+
{ id: "codex", configDirName: ".codex" },
|
|
341
|
+
{ id: "opencode", configDirName: ".opencode" }
|
|
342
|
+
];
|
|
343
|
+
function detectGlobalHarnesses(overrideHomeDir) {
|
|
344
|
+
const homeDir = overrideHomeDir ?? os2.homedir();
|
|
345
|
+
return HARNESS_SPECS.map((spec) => {
|
|
346
|
+
const configDir = path5.join(homeDir, spec.configDirName);
|
|
347
|
+
const installed = fs4.existsSync(configDir);
|
|
348
|
+
const pluginManaged = spec.pluginMarker ? fs4.existsSync(path5.join(configDir, spec.pluginMarker)) : false;
|
|
349
|
+
return {
|
|
350
|
+
id: spec.id,
|
|
351
|
+
installed,
|
|
352
|
+
configDir,
|
|
353
|
+
pluginManaged
|
|
354
|
+
};
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
function installedHarnessIds(homeDir) {
|
|
358
|
+
return detectGlobalHarnesses(homeDir).filter((h) => h.installed).map((h) => h.id);
|
|
359
|
+
}
|
|
360
|
+
var HARNESS_IDS = HARNESS_SPECS.map((spec) => spec.id);
|
|
361
|
+
function isValidHarnessId(value) {
|
|
362
|
+
return HARNESS_SPECS.some((spec) => spec.id === value);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// src/lib/harnessSelect.ts
|
|
366
|
+
var HARNESS_LABELS = {
|
|
367
|
+
"claude-code": "Claude Code",
|
|
368
|
+
codex: "Codex",
|
|
369
|
+
opencode: "OpenCode"
|
|
370
|
+
};
|
|
371
|
+
function buildHarnessOptions(detected) {
|
|
372
|
+
return detected.map((harness) => ({
|
|
373
|
+
id: harness.id,
|
|
374
|
+
label: HARNESS_LABELS[harness.id],
|
|
375
|
+
checked: harness.installed
|
|
376
|
+
}));
|
|
377
|
+
}
|
|
378
|
+
function resolveHarnessSelection(detected, selection) {
|
|
379
|
+
if (selection === void 0) {
|
|
380
|
+
return detected.filter((harness) => harness.installed).map((harness) => harness.id);
|
|
381
|
+
}
|
|
382
|
+
const validIds = /* @__PURE__ */ new Set();
|
|
383
|
+
for (const id of selection) {
|
|
384
|
+
const match = detected.find((harness) => harness.id === id);
|
|
385
|
+
if (match) {
|
|
386
|
+
validIds.add(match.id);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return Array.from(validIds);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/lib/prompt.ts
|
|
393
|
+
function createLineReader(input, output) {
|
|
394
|
+
const buffer = [];
|
|
395
|
+
const queue = [];
|
|
396
|
+
let remainder = "";
|
|
397
|
+
let ended = false;
|
|
398
|
+
function flushQueue() {
|
|
399
|
+
while (queue.length > 0 && buffer.length > 0) {
|
|
400
|
+
const next = queue.shift();
|
|
401
|
+
const line = buffer.shift();
|
|
402
|
+
if (next && line !== void 0) {
|
|
403
|
+
next.resolve(line);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
input.on("data", (chunk) => {
|
|
408
|
+
const text = remainder + chunk.toString("utf-8");
|
|
409
|
+
const lines = text.split("\n");
|
|
410
|
+
remainder = lines.pop() ?? "";
|
|
411
|
+
for (const line of lines) {
|
|
412
|
+
buffer.push(line.replace(/\r$/, ""));
|
|
413
|
+
}
|
|
414
|
+
flushQueue();
|
|
415
|
+
});
|
|
416
|
+
input.on("end", () => {
|
|
417
|
+
ended = true;
|
|
418
|
+
if (remainder.length > 0) {
|
|
419
|
+
buffer.push(remainder.replace(/\r$/, ""));
|
|
420
|
+
remainder = "";
|
|
421
|
+
}
|
|
422
|
+
flushQueue();
|
|
423
|
+
while (queue.length > 0) {
|
|
424
|
+
const next = queue.shift();
|
|
425
|
+
next?.resolve("");
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
input.on("error", (err) => {
|
|
429
|
+
while (queue.length > 0) {
|
|
430
|
+
queue.shift()?.reject(err);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
return {
|
|
434
|
+
readLine(prompt) {
|
|
435
|
+
output.write(prompt);
|
|
436
|
+
if (buffer.length > 0) {
|
|
437
|
+
return Promise.resolve(buffer.shift() ?? "");
|
|
438
|
+
}
|
|
439
|
+
if (ended) {
|
|
440
|
+
return Promise.resolve("");
|
|
441
|
+
}
|
|
442
|
+
return new Promise((resolve, reject) => {
|
|
443
|
+
queue.push({ resolve, reject });
|
|
444
|
+
});
|
|
445
|
+
},
|
|
446
|
+
close() {
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function normalizeAnswer(text) {
|
|
451
|
+
return text.trim().toLowerCase();
|
|
452
|
+
}
|
|
453
|
+
function createPrompt(streams = {}) {
|
|
454
|
+
const input = streams.input ?? process.stdin;
|
|
455
|
+
const output = streams.output ?? process.stdout;
|
|
456
|
+
const reader = createLineReader(input, output);
|
|
457
|
+
async function ask(question) {
|
|
458
|
+
return reader.readLine(question);
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
async confirm(question, defaultValue = true) {
|
|
462
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
463
|
+
const first = await ask(`${question} ${hint} `);
|
|
464
|
+
const normalized = normalizeAnswer(first);
|
|
465
|
+
if (normalized === "y" || normalized === "yes") {
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
if (normalized === "n" || normalized === "no") {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
if (normalized === "") {
|
|
472
|
+
return defaultValue;
|
|
473
|
+
}
|
|
474
|
+
const second = await ask("Please answer y or n: ");
|
|
475
|
+
const secondNormalized = normalizeAnswer(second);
|
|
476
|
+
if (secondNormalized === "y" || secondNormalized === "yes") {
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
if (secondNormalized === "n" || secondNormalized === "no") {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
return defaultValue;
|
|
483
|
+
},
|
|
484
|
+
async multiSelect(question, options) {
|
|
485
|
+
const lines = options.map((opt, index) => {
|
|
486
|
+
const mark = opt.checked ? "x" : " ";
|
|
487
|
+
return ` [${mark}] ${index + 1}. ${opt.label}`;
|
|
488
|
+
});
|
|
489
|
+
const promptText = `${question}
|
|
490
|
+
${lines.join("\n")}
|
|
491
|
+
Enter numbers (e.g. 1,3), 'all', 'none', or harness names: `;
|
|
492
|
+
async function parse(answer) {
|
|
493
|
+
const normalized = normalizeAnswer(answer);
|
|
494
|
+
if (normalized === "all") {
|
|
495
|
+
return options.map((opt) => opt.id);
|
|
496
|
+
}
|
|
497
|
+
if (normalized === "none") {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
if (normalized === "") {
|
|
501
|
+
return options.filter((opt) => opt.checked).map((opt) => opt.id);
|
|
502
|
+
}
|
|
503
|
+
const parts = normalized.split(/[,\s]+/).filter((part) => part.length > 0);
|
|
504
|
+
const selected = /* @__PURE__ */ new Set();
|
|
505
|
+
for (const part of parts) {
|
|
506
|
+
const index = Number(part);
|
|
507
|
+
if (!Number.isNaN(index) && index >= 1 && index <= options.length) {
|
|
508
|
+
selected.add(options[index - 1].id);
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
const match = options.find((opt) => opt.id === part);
|
|
512
|
+
if (match) {
|
|
513
|
+
selected.add(match.id);
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
return void 0;
|
|
517
|
+
}
|
|
518
|
+
return Array.from(selected);
|
|
519
|
+
}
|
|
520
|
+
let result = await parse(await ask(promptText));
|
|
521
|
+
if (result !== void 0) {
|
|
522
|
+
return result;
|
|
523
|
+
}
|
|
524
|
+
const retry = await ask("Invalid selection. Please try again: ");
|
|
525
|
+
result = await parse(retry);
|
|
526
|
+
return result ?? [];
|
|
527
|
+
},
|
|
528
|
+
close() {
|
|
529
|
+
reader.close();
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/commands/install.ts
|
|
535
|
+
function createDefaultDeps() {
|
|
536
|
+
return {
|
|
537
|
+
paths: resolveLincolnPaths(),
|
|
538
|
+
payloadRoot: resolvePayloadRoot() || "",
|
|
539
|
+
syncHarnesses,
|
|
540
|
+
createPrompt,
|
|
541
|
+
resolvePythonForVenv,
|
|
542
|
+
isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY)
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
async function install(options, deps = createDefaultDeps()) {
|
|
546
|
+
const version = readLocalPackageVersion();
|
|
547
|
+
if (!version) {
|
|
548
|
+
console.error("Could not determine Lincoln version");
|
|
549
|
+
return 1;
|
|
550
|
+
}
|
|
551
|
+
const payloadRoot = deps.payloadRoot;
|
|
552
|
+
if (!payloadRoot || !fs5.existsSync(payloadRoot)) {
|
|
553
|
+
console.error('Lincoln payload not found. Run "npm install -g @sushanglewis/lincoln" first.');
|
|
554
|
+
return 1;
|
|
555
|
+
}
|
|
556
|
+
if (!options.dryRun && !options.yes && (options.noInteractive || !deps.isTTY)) {
|
|
557
|
+
console.error(
|
|
558
|
+
"This will install Lincoln globally. Run with --yes to proceed, or run interactively in a TTY."
|
|
559
|
+
);
|
|
560
|
+
return 1;
|
|
561
|
+
}
|
|
562
|
+
const harnesses = await resolveHarnesses(options, deps);
|
|
563
|
+
if (harnesses.length === 0) {
|
|
564
|
+
return 1;
|
|
565
|
+
}
|
|
566
|
+
const pythonPath = await resolvePythonIfNeeded(options, deps, harnesses);
|
|
567
|
+
if (pythonPath === null) {
|
|
568
|
+
return 1;
|
|
569
|
+
}
|
|
570
|
+
if (!options.dryRun) {
|
|
571
|
+
const versionDir = path6.join(deps.paths.versionsDir, version);
|
|
572
|
+
fs5.mkdirSync(versionDir, { recursive: true });
|
|
573
|
+
fs5.cpSync(payloadRoot, versionDir, { recursive: true, force: true });
|
|
574
|
+
try {
|
|
575
|
+
fs5.rmSync(deps.paths.currentDir, { recursive: true, force: true });
|
|
576
|
+
fs5.symlinkSync(versionDir, deps.paths.currentDir);
|
|
577
|
+
} catch {
|
|
578
|
+
fs5.rmSync(deps.paths.currentDir, { recursive: true, force: true });
|
|
579
|
+
fs5.cpSync(versionDir, deps.paths.currentDir, { recursive: true, force: true });
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
const reports = await deps.syncHarnesses({
|
|
583
|
+
harnesses,
|
|
584
|
+
payloadRoot: deps.paths.currentDir,
|
|
585
|
+
paths: deps.paths,
|
|
586
|
+
projectDir: deps.paths.lincolnHome,
|
|
587
|
+
version,
|
|
588
|
+
dryRun: options.dryRun,
|
|
589
|
+
pythonPath
|
|
590
|
+
});
|
|
591
|
+
if (!options.dryRun) {
|
|
592
|
+
writeVersionMarker(deps.paths, {
|
|
593
|
+
version,
|
|
594
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
595
|
+
harnesses,
|
|
596
|
+
managedFiles: collectManagedFiles(reports)
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
printSummary(options, version, harnesses, reports);
|
|
600
|
+
return 0;
|
|
601
|
+
}
|
|
602
|
+
async function resolvePythonIfNeeded(options, deps, harnesses) {
|
|
603
|
+
const needsPython = !options.dryRun && !options.noVenv && harnesses.some((id) => id === "codex" || id === "opencode");
|
|
604
|
+
if (!needsPython) {
|
|
605
|
+
return void 0;
|
|
606
|
+
}
|
|
607
|
+
const pythonCommand = await deps.resolvePythonForVenv();
|
|
608
|
+
if (!pythonCommand) {
|
|
609
|
+
console.error(
|
|
610
|
+
"Python 3.10+ is required for Codex/OpenCode sync but was not found. Set LINCOLN_PYTHON to a compatible Python executable, or run with --no-venv."
|
|
611
|
+
);
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
await setupVenv(deps.paths, deps.payloadRoot, pythonCommand);
|
|
615
|
+
return venvPythonPath(deps.paths);
|
|
616
|
+
}
|
|
617
|
+
async function resolveHarnesses(options, deps) {
|
|
618
|
+
const detected = detectGlobalHarnesses(deps.paths.homeDir);
|
|
619
|
+
if (options.harnesses.length > 0) {
|
|
620
|
+
const invalid = options.harnesses.filter((id) => !isValidHarnessId(id));
|
|
621
|
+
if (invalid.length > 0) {
|
|
622
|
+
console.error(`Unknown harness id(s): ${invalid.join(", ")}`);
|
|
623
|
+
console.error(`Valid ids: ${HARNESS_IDS.join(", ")}`);
|
|
624
|
+
return [];
|
|
625
|
+
}
|
|
626
|
+
return options.harnesses;
|
|
627
|
+
}
|
|
628
|
+
const selected = installedHarnessIds(deps.paths.homeDir);
|
|
629
|
+
if (selected.length > 0 && !options.dryRun && !options.yes && !options.noInteractive && deps.isTTY) {
|
|
630
|
+
const prompt = deps.createPrompt();
|
|
631
|
+
try {
|
|
632
|
+
const answer = await prompt.multiSelect(
|
|
633
|
+
"Select agent harnesses to install Lincoln into:",
|
|
634
|
+
buildHarnessOptions(detected)
|
|
635
|
+
);
|
|
636
|
+
const resolved = resolveHarnessSelection(detected, answer);
|
|
637
|
+
if (resolved.length === 0) {
|
|
638
|
+
console.error("No harnesses selected. Aborting.");
|
|
639
|
+
return [];
|
|
640
|
+
}
|
|
641
|
+
return resolved;
|
|
642
|
+
} catch (err) {
|
|
643
|
+
console.error(`Interactive selection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
644
|
+
return [];
|
|
645
|
+
} finally {
|
|
646
|
+
prompt.close();
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (selected.length === 0 && !options.dryRun) {
|
|
650
|
+
console.error("No agent harness detected. Install Claude Code, Codex, or OpenCode first.");
|
|
651
|
+
return [];
|
|
652
|
+
}
|
|
653
|
+
return selected;
|
|
654
|
+
}
|
|
655
|
+
function collectManagedFiles(reports) {
|
|
656
|
+
const files = [];
|
|
657
|
+
for (const report of Object.values(reports)) {
|
|
658
|
+
files.push(...report.written, ...report.skipped, ...report.preserved);
|
|
659
|
+
}
|
|
660
|
+
return files;
|
|
661
|
+
}
|
|
662
|
+
function printSummary(options, version, harnesses, reports) {
|
|
663
|
+
const warnings = collectWarnings(reports);
|
|
664
|
+
if (options.dryRun) {
|
|
665
|
+
console.log(`Dry run: would install Lincoln ${version} for harnesses: ${harnesses.join(", ")}`);
|
|
666
|
+
} else {
|
|
667
|
+
console.log(`Installed Lincoln ${version} for harnesses: ${harnesses.join(", ")}`);
|
|
668
|
+
}
|
|
669
|
+
for (const [harnessId, report] of Object.entries(reports)) {
|
|
670
|
+
const count = report.written.length + report.skipped.length + report.preserved.length;
|
|
671
|
+
console.log(` ${harnessId}: ${count} file(s)`);
|
|
672
|
+
}
|
|
673
|
+
for (const warning of warnings) {
|
|
674
|
+
console.warn(` warning: ${warning}`);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function collectWarnings(reports) {
|
|
678
|
+
const warnings = [];
|
|
679
|
+
for (const report of Object.values(reports)) {
|
|
680
|
+
warnings.push(...report.warnings);
|
|
681
|
+
}
|
|
682
|
+
return warnings;
|
|
683
|
+
}
|
|
684
|
+
function runCommand2(command, args) {
|
|
685
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
686
|
+
const child = spawn2(command, args, { stdio: "inherit" });
|
|
687
|
+
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
688
|
+
child.on("error", (err) => rejectPromise(err));
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
var MIN_PYTHON_MAJOR = 3;
|
|
692
|
+
var MIN_PYTHON_MINOR = 10;
|
|
693
|
+
var DEFAULT_PYTHON_CANDIDATES = ["python3.12", "python3.11", "python3.10", "python3"];
|
|
694
|
+
function parsePythonVersion(version) {
|
|
695
|
+
const match = /(\d+)\.(\d+)/.exec(version);
|
|
696
|
+
if (!match) {
|
|
697
|
+
return void 0;
|
|
698
|
+
}
|
|
699
|
+
return { major: Number(match[1]), minor: Number(match[2]) };
|
|
700
|
+
}
|
|
701
|
+
async function queryPythonVersion(command) {
|
|
702
|
+
return new Promise((resolvePromise) => {
|
|
703
|
+
const child = spawn2(command, ["--version"], {
|
|
704
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
705
|
+
shell: process.platform === "win32"
|
|
706
|
+
});
|
|
707
|
+
let stdout = "";
|
|
708
|
+
child.stdout?.on("data", (chunk) => {
|
|
709
|
+
stdout += chunk.toString();
|
|
710
|
+
});
|
|
711
|
+
child.on("close", (code) => {
|
|
712
|
+
const text = stdout.trim();
|
|
713
|
+
resolvePromise(code === 0 && text.length > 0 ? text : void 0);
|
|
714
|
+
});
|
|
715
|
+
child.on("error", () => resolvePromise(void 0));
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
async function resolvePythonForVenv(envOverride = process.env.LINCOLN_PYTHON, candidates = DEFAULT_PYTHON_CANDIDATES, queryVersion = queryPythonVersion) {
|
|
719
|
+
const list = envOverride ? [envOverride] : candidates;
|
|
720
|
+
for (const cmd of list) {
|
|
721
|
+
const version = await queryVersion(cmd);
|
|
722
|
+
if (!version) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
const parsed = parsePythonVersion(version);
|
|
726
|
+
if (parsed && parsed.major >= MIN_PYTHON_MAJOR && (parsed.major > MIN_PYTHON_MAJOR || parsed.minor >= MIN_PYTHON_MINOR)) {
|
|
727
|
+
return cmd;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return void 0;
|
|
731
|
+
}
|
|
732
|
+
function venvPythonPath(paths) {
|
|
733
|
+
return path6.join(
|
|
734
|
+
paths.venvDir,
|
|
735
|
+
process.platform === "win32" ? "Scripts" : "bin",
|
|
736
|
+
process.platform === "win32" ? "python.exe" : "python"
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
async function setupVenv(paths, payloadRoot, pythonCommand) {
|
|
740
|
+
const pythonExe = venvPythonPath(paths);
|
|
741
|
+
if (!fs5.existsSync(pythonExe)) {
|
|
742
|
+
console.log("Creating Lincoln virtual environment...");
|
|
743
|
+
const venvCode = await runCommand2(pythonCommand, ["-m", "venv", paths.venvDir]);
|
|
744
|
+
if (venvCode !== 0) {
|
|
745
|
+
throw new Error(`Failed to create virtual environment (exit code ${venvCode})`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const requirementsPath = path6.join(payloadRoot, "requirements.txt");
|
|
749
|
+
if (fs5.existsSync(requirementsPath)) {
|
|
750
|
+
console.log("Installing Python dependencies...");
|
|
751
|
+
const pipExe = path6.join(
|
|
752
|
+
paths.venvDir,
|
|
753
|
+
process.platform === "win32" ? "Scripts" : "bin",
|
|
754
|
+
process.platform === "win32" ? "pip.exe" : "pip"
|
|
755
|
+
);
|
|
756
|
+
const pipCode = await runCommand2(pipExe, ["install", "-r", requirementsPath]);
|
|
757
|
+
if (pipCode !== 0) {
|
|
758
|
+
throw new Error(`Failed to install Python dependencies (exit code ${pipCode})`);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
3
763
|
// src/postinstall.ts
|
|
4
|
-
function
|
|
5
|
-
if (
|
|
764
|
+
function isSkipped(env) {
|
|
765
|
+
if (env.CI) {
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
if (env.NODE_ENV === "test") {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
if (env.LINCOLN_SKIP_POSTINSTALL) {
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
function createDefaultDeps2() {
|
|
777
|
+
return {
|
|
778
|
+
isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
779
|
+
confirm: async (question) => {
|
|
780
|
+
const prompt = createPrompt();
|
|
781
|
+
try {
|
|
782
|
+
return await prompt.confirm(question, true);
|
|
783
|
+
} finally {
|
|
784
|
+
prompt.close();
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
install: async () => install({ yes: false, dryRun: false, force: false, harnesses: [], noVenv: false, noInteractive: false }),
|
|
788
|
+
env: process.env
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
async function runPostinstall(deps = createDefaultDeps2()) {
|
|
792
|
+
if (isSkipped(deps.env)) {
|
|
793
|
+
return 0;
|
|
794
|
+
}
|
|
795
|
+
if (!deps.isTTY) {
|
|
796
|
+
console.log("Lincoln installed globally.");
|
|
797
|
+
console.log('Run "lincoln install" to finish setup.');
|
|
798
|
+
return 0;
|
|
799
|
+
}
|
|
800
|
+
try {
|
|
801
|
+
const ok = await deps.confirm("Configure Lincoln harnesses now?");
|
|
802
|
+
if (!ok) {
|
|
803
|
+
console.log('Run "lincoln install" anytime to finish setup.');
|
|
804
|
+
return 0;
|
|
805
|
+
}
|
|
806
|
+
await deps.install();
|
|
807
|
+
return 0;
|
|
808
|
+
} catch (err) {
|
|
809
|
+
console.log("Lincoln installed globally.");
|
|
810
|
+
console.log('Run "lincoln install" anytime to finish setup.');
|
|
811
|
+
if (err instanceof Error) {
|
|
812
|
+
console.error(`Postinstall setup skipped: ${err.message}`);
|
|
813
|
+
}
|
|
6
814
|
return 0;
|
|
7
815
|
}
|
|
8
|
-
console.log("Lincoln installed globally.");
|
|
9
|
-
console.log('Run "lincoln install" to finish setup.');
|
|
10
|
-
return 0;
|
|
11
816
|
}
|
|
12
817
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
13
|
-
process.exit(
|
|
818
|
+
runPostinstall().then((code) => process.exit(code)).catch(() => process.exit(0));
|
|
14
819
|
}
|
|
15
820
|
export {
|
|
821
|
+
createDefaultDeps2 as createDefaultDeps,
|
|
16
822
|
runPostinstall
|
|
17
823
|
};
|
|
18
824
|
//# sourceMappingURL=postinstall.js.map
|