@sushanglewis/lincoln 1.5.0 → 1.5.2
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.d.ts +3 -0
- package/dist/main.js +1286 -916
- package/dist/main.js.map +1 -1
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.js +18 -0
- package/dist/postinstall.js.map +1 -0
- package/framework/.claude/agents/_contract.md +79 -0
- package/framework/.claude/agents/architect.md +31 -0
- package/framework/.claude/agents/default.md +151 -0
- package/framework/.claude/agents/designer.md +33 -0
- package/framework/.claude/agents/engineer.md +42 -0
- package/framework/.claude/agents/external/NOTICES.md +12 -0
- package/framework/.claude/agents/external/everything-claude-code.manifest.yaml +23 -0
- package/framework/.claude/agents/external/oh-my-claudecode.manifest.yaml +26 -0
- package/framework/.claude/agents/external/wshobson-agents.manifest.yaml +23 -0
- package/framework/.claude/agents/frontend-engineer.md +32 -0
- package/framework/.claude/agents/knowledge-curator.md +28 -0
- package/framework/.claude/agents/pm.md +38 -0
- package/framework/.claude/agents/qa.md +28 -0
- package/framework/.claude/agents/release-coordinator.md +25 -0
- package/framework/.claude/agents/researcher.md +41 -0
- package/framework/.claude/harnesses/claude-code.yaml +15 -0
- package/framework/.claude/harnesses/codex.yaml +40 -0
- package/framework/.claude/harnesses/command-map.yaml +255 -0
- package/framework/.claude/harnesses/opencode.yaml +32 -0
- package/framework/.claude/harnesses/scenarios.yaml +45 -0
- package/framework/.claude/hooks/on-pr-event.sh +69 -0
- package/framework/.claude/hooks/on-session-start.sh +427 -0
- package/framework/.claude/hooks/on-stop.sh +104 -0
- package/framework/.claude/hooks/post-tool-use.sh +161 -0
- package/framework/.claude/hooks/pre-tool-use.sh +246 -0
- package/framework/.claude/schemas/agent-definition.schema.json +35 -0
- package/framework/.claude/schemas/benchmark-report.schema.json +148 -0
- package/framework/.claude/schemas/pm-to-ux-handoff.schema.yaml +128 -0
- package/framework/.claude/schemas/stage-definition.schema.json +233 -0
- package/framework/.claude/schemas/workflow-stage.schema.json +86 -0
- package/framework/.claude/schemas/workflow-template.schema.json +88 -0
- package/framework/.claude/settings.json +14 -0
- package/framework/.claude/skills/build-product-prototype/SKILL.md +35 -0
- package/framework/.claude/skills/build-product-prototype/prompts/main.md +78 -0
- package/framework/.claude/skills/clarify-requirements/SKILL.md +32 -0
- package/framework/.claude/skills/clarify-requirements/prompts/main.md +81 -0
- package/framework/.claude/skills/dependencies.yaml +139 -0
- package/framework/.claude/skills/draft-product-design/SKILL.md +40 -0
- package/framework/.claude/skills/draft-product-design/prompts/main.md +47 -0
- package/framework/.claude/skills/lc-analyze-frameworks/SKILL.md +43 -0
- package/framework/.claude/skills/lc-analyze-frameworks/prompts/main.md +95 -0
- package/framework/.claude/skills/lc-benchmark/SKILL.md +61 -0
- package/framework/.claude/skills/lc-build-codebase-knowledge/SKILL.md +38 -0
- package/framework/.claude/skills/lc-build-codebase-knowledge/prompts/build-codebase-knowledge.md +61 -0
- package/framework/.claude/skills/lc-collect-intelligence/SKILL.md +43 -0
- package/framework/.claude/skills/lc-collect-intelligence/prompts/main.md +72 -0
- package/framework/.claude/skills/lc-competitive-analysis/SKILL.md +43 -0
- package/framework/.claude/skills/lc-competitive-analysis/prompts/main.md +70 -0
- package/framework/.claude/skills/lc-explore-opensource/SKILL.md +36 -0
- package/framework/.claude/skills/lc-explore-opensource/prompts/explore-opensource.md +77 -0
- package/framework/.claude/skills/lc-first-principles/SKILL.md +43 -0
- package/framework/.claude/skills/lc-first-principles/prompts/main.md +73 -0
- package/framework/.claude/skills/lc-handoff/SKILL.md +34 -0
- package/framework/.claude/skills/lc-init-branch/SKILL.md +52 -0
- package/framework/.claude/skills/lc-market-research/SKILL.md +43 -0
- package/framework/.claude/skills/lc-market-research/prompts/main.md +79 -0
- package/framework/.claude/skills/lc-product-research/SKILL.md +43 -0
- package/framework/.claude/skills/lc-product-research/prompts/main.md +80 -0
- package/framework/.claude/skills/lc-research-report/SKILL.md +43 -0
- package/framework/.claude/skills/lc-research-report/prompts/main.md +90 -0
- package/framework/.claude/skills/lc-research-scope/SKILL.md +43 -0
- package/framework/.claude/skills/lc-research-scope/prompts/main.md +82 -0
- package/framework/.claude/skills/lc-setup/SKILL.md +68 -0
- package/framework/.claude/skills/lc-setup/prompts/main.md +88 -0
- package/framework/.claude/skills/lc-stage/SKILL.md +45 -0
- package/framework/.claude/skills/lc-stakeholder-research/SKILL.md +43 -0
- package/framework/.claude/skills/lc-stakeholder-research/prompts/main.md +65 -0
- package/framework/.claude/skills/lc-status/SKILL.md +25 -0
- package/framework/.claude/skills/lc-storytelling/SKILL.md +43 -0
- package/framework/.claude/skills/lc-storytelling/prompts/main.md +77 -0
- package/framework/.claude/skills/lc-wf/SKILL.md +54 -0
- package/framework/.claude/skills/lc-workflow/SKILL.md +48 -0
- package/framework/.claude/skills/lc-workflow/validators/validate.py +755 -0
- package/framework/.claude/skills/lc-workflow-router/SKILL.md +41 -0
- package/framework/.claude/skills/lc-workflow-router/prompts/intake-prompt.md +91 -0
- package/framework/.claude/skills/lc-workflow-router/prompts/router-prompt.md +44 -0
- package/framework/.claude/skills/plan-tdd-development/SKILL.md +31 -0
- package/framework/.claude/skills/plan-tdd-development/prompts/main.md +44 -0
- package/framework/.claude/skills/process-interview/SKILL.md +32 -0
- package/framework/.claude/skills/process-interview/prompts/main.md +47 -0
- package/framework/.claude/skills/propose-with-openspec/SKILL.md +37 -0
- package/framework/.claude/skills/propose-with-openspec/prompts/main.md +53 -0
- package/framework/.claude/skills/split-to-github/SKILL.md +32 -0
- package/framework/.claude/skills/split-to-github/prompts/main.md +42 -0
- package/framework/.claude/skills/sync-to-knowledge/SKILL.md +35 -0
- package/framework/.claude/skills/sync-to-knowledge/prompts/main.md +54 -0
- package/framework/.claude/skills/workflow-continue/SKILL.md +24 -0
- package/framework/.claude/skills/workflow-continue/prompts/main.md +25 -0
- package/framework/.claude/stages/build-codebase-knowledge.yaml +42 -0
- package/framework/.claude/stages/clarify.yaml +59 -0
- package/framework/.claude/stages/explore-opensource.yaml +40 -0
- package/framework/.claude/stages/implement.yaml +60 -0
- package/framework/.claude/stages/ingest.yaml +40 -0
- package/framework/.claude/stages/lc-analyze-frameworks.yaml +37 -0
- package/framework/.claude/stages/lc-collect-intelligence.yaml +37 -0
- package/framework/.claude/stages/lc-competitive-analysis.yaml +37 -0
- package/framework/.claude/stages/lc-first-principles.yaml +37 -0
- package/framework/.claude/stages/lc-market-research.yaml +37 -0
- package/framework/.claude/stages/lc-product-research.yaml +37 -0
- package/framework/.claude/stages/lc-research-report.yaml +38 -0
- package/framework/.claude/stages/lc-research-scope.yaml +38 -0
- package/framework/.claude/stages/lc-stakeholder-research.yaml +37 -0
- package/framework/.claude/stages/lc-storytelling.yaml +37 -0
- package/framework/.claude/stages/product-design-docs.yaml +66 -0
- package/framework/.claude/stages/product-prototype.yaml +53 -0
- package/framework/.claude/stages/propose.yaml +45 -0
- package/framework/.claude/stages/split.yaml +41 -0
- package/framework/.claude/stages/sync-knowledge.yaml +49 -0
- package/framework/.claude/stages/tdd-development-plan.yaml +43 -0
- package/framework/.claude/stages/workflow-router.yaml +45 -0
- package/framework/.claude/templates/solo-workflow-context.yaml +23 -0
- package/framework/.claude/workflows/README.md +93 -0
- package/framework/.claude/workflows/bug-fix.yaml +81 -0
- package/framework/.claude/workflows/design-spike.yaml +55 -0
- package/framework/.claude/workflows/existing-project-iteration.yaml +106 -0
- package/framework/.claude/workflows/interview-to-knowledge.yaml +189 -0
- package/framework/.claude/workflows/oss-first-design.yaml +100 -0
- package/framework/.claude/workflows/pm-research.yaml +115 -0
- package/framework/.claude-plugin/hooks.json +6 -0
- package/framework/.claude-plugin/marketplace.json +32 -0
- package/framework/.claude-plugin/plugin.json +57 -0
- package/framework/.version-bump.json +43 -0
- package/framework/CLAUDE.md +140 -0
- package/framework/CONTRIBUTING.md +219 -0
- package/framework/LICENSE +21 -0
- package/framework/README.en.md +139 -0
- package/framework/README.md +139 -0
- package/framework/RELEASE.md +334 -0
- package/framework/SKILL.md +24 -0
- package/framework/USAGE.md +356 -0
- package/framework/manifest.json +1214 -0
- package/framework/requirements.txt +4 -0
- package/framework/scripts/__init__.py +0 -0
- package/framework/scripts/build_codebase_knowledge.py +76 -0
- package/framework/scripts/bump_version.py +181 -0
- package/framework/scripts/check-dependency-drift.py +69 -0
- package/framework/scripts/check-harness-drift.sh +57 -0
- package/framework/scripts/check-main-merge-hygiene.py +128 -0
- package/framework/scripts/check-skill-dependencies.sh +124 -0
- package/framework/scripts/init-lincoln-branch.sh +300 -0
- package/framework/scripts/init-project.sh +184 -0
- package/framework/scripts/lc-benchmark-cli.py +66 -0
- package/framework/scripts/lincoln-audit.py +288 -0
- package/framework/scripts/lincoln-setup.py +651 -0
- package/framework/scripts/lincoln-status.py +448 -0
- package/framework/scripts/lincoln_benchmark.py +224 -0
- package/framework/scripts/lincoln_benchmark_eval.py +104 -0
- package/framework/scripts/lincoln_benchmark_metrics.py +818 -0
- package/framework/scripts/lincoln_benchmark_report.py +141 -0
- package/framework/scripts/lincoln_command_map.py +289 -0
- package/framework/scripts/lincoln_dependency_manager.py +335 -0
- package/framework/scripts/lincoln_documents.py +175 -0
- package/framework/scripts/lincoln_harness_adapter.py +319 -0
- package/framework/scripts/lincoln_index.py +255 -0
- package/framework/scripts/lincoln_paths.py +198 -0
- package/framework/scripts/lincoln_prd.py +227 -0
- package/framework/scripts/lincoln_role.py +46 -0
- package/framework/scripts/lincoln_scenario.py +59 -0
- package/framework/scripts/lincoln_session_start_metrics.py +71 -0
- package/framework/scripts/lincoln_skill_prompt.py +48 -0
- package/framework/scripts/lincoln_trace.py +335 -0
- package/framework/scripts/lincoln_workflow.py +199 -0
- package/framework/scripts/list-active-lincoln-branches.sh +87 -0
- package/framework/scripts/package-lincoln-plugin.py +340 -0
- package/framework/scripts/run-infrastructure-tests.py +84 -0
- package/framework/scripts/stage_loader.py +1071 -0
- package/framework/scripts/static-check.sh +356 -0
- package/framework/scripts/sync-external-agents.sh +210 -0
- package/framework/scripts/sync-framework-package.mjs +218 -0
- package/framework/scripts/task_tool_guard.py +213 -0
- package/framework/scripts/track-artifacts.py +140 -0
- package/framework/scripts/validate_stage.py +350 -0
- package/{README.md → framework/tools/lincoln/README.md} +4 -4
- package/framework/tools/lincoln/package-lock.json +3349 -0
- package/framework/tools/lincoln/package.json +48 -0
- package/framework/tools/lincoln/src/cli.tsx +60 -0
- package/framework/tools/lincoln/src/components/AudioMeter.tsx +34 -0
- package/framework/tools/lincoln/src/components/CancelledScreen.tsx +11 -0
- package/framework/tools/lincoln/src/components/DevicesMenu.tsx +79 -0
- package/framework/tools/lincoln/src/components/HintBar.tsx +25 -0
- package/framework/tools/lincoln/src/components/LogView.tsx +36 -0
- package/framework/tools/lincoln/src/components/ModelMenu.tsx +122 -0
- package/framework/tools/lincoln/src/components/ReadyScreen.tsx +54 -0
- package/framework/tools/lincoln/src/components/RecordingApp.tsx +211 -0
- package/framework/tools/lincoln/src/components/RecordingScreen.tsx +41 -0
- package/framework/tools/lincoln/src/components/SelectMenu.tsx +53 -0
- package/framework/tools/lincoln/src/components/StatusPanel.tsx +52 -0
- package/framework/tools/lincoln/src/components/StopConfirmation.tsx +32 -0
- package/framework/tools/lincoln/src/config/args.ts +35 -0
- package/framework/tools/lincoln/src/config/loadConfig.ts +81 -0
- package/framework/tools/lincoln/src/config/resolveConfig.ts +85 -0
- package/framework/tools/lincoln/src/devices/listDevices.ts +11 -0
- package/framework/tools/lincoln/src/devices/parseDevices.ts +25 -0
- package/framework/tools/lincoln/src/hooks/useKeyHandler.ts +63 -0
- package/framework/tools/lincoln/src/main.tsx +4 -0
- package/framework/tools/lincoln/src/models/models.ts +34 -0
- package/framework/tools/lincoln/src/models/runWarmup.ts +46 -0
- package/framework/tools/lincoln/src/models/warmupProgress.ts +30 -0
- package/framework/tools/lincoln/src/recording/spawnRecorder.ts +127 -0
- package/framework/tools/lincoln/src/recording/useRecorder.ts +146 -0
- package/framework/tools/lincoln/src/utils/amplitudeToMeter.ts +4 -0
- package/framework/tools/lincoln/src/utils/formatDuration.ts +6 -0
- package/framework/tools/lincoln/src/utils/sessionId.ts +25 -0
- package/framework/tools/lincoln/tests/cli.test.tsx +52 -0
- package/framework/tools/lincoln/tests/components/AudioMeter.test.tsx +31 -0
- package/framework/tools/lincoln/tests/components/CancelledScreen.test.tsx +12 -0
- package/framework/tools/lincoln/tests/components/ReadyScreen.test.tsx +68 -0
- package/framework/tools/lincoln/tests/components/RecordingApp.menus.test.tsx +158 -0
- package/framework/tools/lincoln/tests/components/RecordingApp.test.tsx +248 -0
- package/framework/tools/lincoln/tests/components/RecordingScreen.test.tsx +37 -0
- package/framework/tools/lincoln/tests/components/SelectMenu.test.tsx +59 -0
- package/framework/tools/lincoln/tests/components/StopConfirmation.test.tsx +38 -0
- package/framework/tools/lincoln/tests/config/args.test.ts +49 -0
- package/framework/tools/lincoln/tests/config/loadConfig.test.ts +59 -0
- package/framework/tools/lincoln/tests/config/resolveConfig.test.ts +72 -0
- package/framework/tools/lincoln/tests/devices/parseDevices.test.ts +21 -0
- package/framework/tools/lincoln/tests/hooks/useKeyHandler.enabled.test.tsx +44 -0
- package/framework/tools/lincoln/tests/hooks/useKeyHandler.test.tsx +130 -0
- package/framework/tools/lincoln/tests/models/models.test.ts +27 -0
- package/framework/tools/lincoln/tests/models/warmupProgress.test.ts +25 -0
- package/framework/tools/lincoln/tests/recording/spawnRecorder.test.ts +85 -0
- package/framework/tools/lincoln/tests/recording/useRecorder.test.tsx +172 -0
- package/framework/tools/lincoln/tests/utils/amplitudeToMeter.test.ts +22 -0
- package/framework/tools/lincoln/tests/utils/formatDuration.test.ts +11 -0
- package/framework/tools/lincoln/tests/utils/sessionId.test.ts +30 -0
- package/framework/tools/lincoln/tsconfig.json +22 -0
- package/framework/tools/lincoln/tsconfig.tests.json +10 -0
- package/framework/tools/lincoln/tsup.config.ts +17 -0
- package/framework/tools/lincoln/vitest.config.ts +20 -0
- package/framework/tools/lincoln-installer/package-lock.json +3611 -0
- package/framework/tools/lincoln-installer/package.json +53 -0
- package/framework/tools/lincoln-installer/src/cli.tsx +63 -0
- package/framework/tools/lincoln-installer/src/components/HarnessSelectScreen.tsx +43 -0
- package/framework/tools/lincoln-installer/src/components/InstallerApp.tsx +98 -0
- package/framework/tools/lincoln-installer/src/components/OptionsScreen.tsx +56 -0
- package/framework/tools/lincoln-installer/src/components/ProgressScreen.tsx +25 -0
- package/framework/tools/lincoln-installer/src/components/ResultScreen.tsx +40 -0
- package/framework/tools/lincoln-installer/src/components/SelectMenu.tsx +73 -0
- package/framework/tools/lincoln-installer/src/components/SummaryScreen.tsx +49 -0
- package/framework/tools/lincoln-installer/src/components/UpdateApp.tsx +135 -0
- package/framework/tools/lincoln-installer/src/components/WelcomeScreen.tsx +22 -0
- package/framework/tools/lincoln-installer/src/config/args.ts +76 -0
- package/framework/tools/lincoln-installer/src/config/resolveConfig.ts +33 -0
- package/framework/tools/lincoln-installer/src/config/updateArgs.ts +67 -0
- package/framework/tools/lincoln-installer/src/hooks/useSetup.ts +149 -0
- package/framework/tools/lincoln-installer/src/main.tsx +11 -0
- package/framework/tools/lincoln-installer/src/types.ts +19 -0
- package/framework/tools/lincoln-installer/src/update-main.tsx +11 -0
- package/framework/tools/lincoln-installer/src/update.tsx +90 -0
- package/framework/tools/lincoln-installer/src/utils/detectHarness.ts +51 -0
- package/framework/tools/lincoln-installer/src/utils/runSetup.ts +62 -0
- package/framework/tools/lincoln-installer/src/utils/updateRelease.ts +454 -0
- package/framework/tools/lincoln-installer/tests/components/InstallerApp.test.tsx +88 -0
- package/framework/tools/lincoln-installer/tests/components/SelectMenu.test.tsx +26 -0
- package/framework/tools/lincoln-installer/tests/components/UpdateApp.test.tsx +170 -0
- package/framework/tools/lincoln-installer/tests/components/screens.test.tsx +310 -0
- package/framework/tools/lincoln-installer/tests/config/args.test.ts +66 -0
- package/framework/tools/lincoln-installer/tests/config/resolveConfig.test.ts +75 -0
- package/framework/tools/lincoln-installer/tests/config/updateArgs.test.ts +52 -0
- package/framework/tools/lincoln-installer/tests/hooks/useSetup.test.tsx +213 -0
- package/framework/tools/lincoln-installer/tests/update.test.tsx +108 -0
- package/framework/tools/lincoln-installer/tests/utils/detectHarness.test.ts +40 -0
- package/framework/tools/lincoln-installer/tests/utils/runSetup.test.ts +45 -0
- package/framework/tools/lincoln-installer/tests/utils/updateRelease.test.ts +559 -0
- package/framework/tools/lincoln-installer/tsconfig.json +22 -0
- package/framework/tools/lincoln-installer/tsconfig.tests.json +8 -0
- package/framework/tools/lincoln-installer/tsup.config.ts +17 -0
- package/framework/tools/lincoln-installer/vitest.config.ts +20 -0
- package/framework/tools/lincoln-record/Cargo.lock +1896 -0
- package/framework/tools/lincoln-record/Cargo.toml +24 -0
- package/framework/tools/lincoln-record/diarize/diarize.py +117 -0
- package/framework/tools/lincoln-record/diarize/merge.py +55 -0
- package/framework/tools/lincoln-record/src/audio/capture/microphone.rs +194 -0
- package/framework/tools/lincoln-record/src/audio/capture/mod.rs +1 -0
- package/framework/tools/lincoln-record/src/audio/devices.rs +20 -0
- package/framework/tools/lincoln-record/src/audio/mod.rs +5 -0
- package/framework/tools/lincoln-record/src/audio/resampler.rs +44 -0
- package/framework/tools/lincoln-record/src/audio/saver.rs +87 -0
- package/framework/tools/lincoln-record/src/audio/source.rs +104 -0
- package/framework/tools/lincoln-record/src/cli.rs +96 -0
- package/framework/tools/lincoln-record/src/config.rs +135 -0
- package/framework/tools/lincoln-record/src/lib.rs +6 -0
- package/framework/tools/lincoln-record/src/main.rs +242 -0
- package/framework/tools/lincoln-record/src/model/mod.rs +248 -0
- package/framework/tools/lincoln-record/src/output/metadata.rs +30 -0
- package/framework/tools/lincoln-record/src/output/mod.rs +2 -0
- package/framework/tools/lincoln-record/src/output/transcript.rs +42 -0
- package/framework/tools/lincoln-record/src/transcription/diarization.rs +64 -0
- package/framework/tools/lincoln-record/src/transcription/mod.rs +3 -0
- package/framework/tools/lincoln-record/src/transcription/provider.rs +43 -0
- package/framework/tools/lincoln-record/src/transcription/whisper.rs +176 -0
- package/framework/tools/lincoln-record/tests/cli_args.rs +103 -0
- package/framework/tools/lincoln-record/tests/config_test.rs +70 -0
- package/framework/tools/lincoln-record/tests/devices_test.rs +23 -0
- package/framework/tools/lincoln-record/tests/diarization_tests.rs +101 -0
- package/framework/tools/lincoln-record/tests/integration_tests.rs +44 -0
- package/framework/tools/lincoln-record/tests/model_test.rs +68 -0
- package/framework/tools/lincoln-record/tests/transcription_tests.rs +73 -0
- package/package.json +19 -13
package/dist/main.js
CHANGED
|
@@ -1,1009 +1,1379 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/
|
|
4
|
-
import
|
|
3
|
+
// src/main.ts
|
|
4
|
+
import fs11 from "fs";
|
|
5
|
+
import path12 from "path";
|
|
6
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5
7
|
|
|
6
|
-
// src/
|
|
7
|
-
|
|
8
|
+
// src/cli.ts
|
|
9
|
+
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
10
|
+
"yes",
|
|
11
|
+
"y",
|
|
12
|
+
"dry-run",
|
|
13
|
+
"force",
|
|
14
|
+
"check",
|
|
15
|
+
"json",
|
|
16
|
+
"help",
|
|
17
|
+
"h",
|
|
18
|
+
"no-venv"
|
|
19
|
+
]);
|
|
8
20
|
function parseArgs(argv) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
const args = argv.slice(2);
|
|
22
|
+
const flags = {};
|
|
23
|
+
const positional = [];
|
|
24
|
+
for (let i = 0; i < args.length; i++) {
|
|
25
|
+
const arg = args[i];
|
|
26
|
+
if (arg.startsWith("--")) {
|
|
27
|
+
const key = arg.replace(/^--/, "");
|
|
28
|
+
const next = args[i + 1];
|
|
29
|
+
if (!BOOLEAN_FLAGS.has(key) && next && !next.startsWith("-")) {
|
|
30
|
+
flags[key] = next;
|
|
31
|
+
i++;
|
|
32
|
+
} else {
|
|
33
|
+
flags[key] = true;
|
|
34
|
+
}
|
|
35
|
+
} else if (arg.startsWith("-")) {
|
|
36
|
+
const key = arg.replace(/^-/, "");
|
|
37
|
+
const next = args[i + 1];
|
|
38
|
+
if (!BOOLEAN_FLAGS.has(key) && next && !next.startsWith("-")) {
|
|
39
|
+
flags[key] = next;
|
|
40
|
+
i++;
|
|
41
|
+
} else {
|
|
42
|
+
flags[key] = true;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
positional.push(arg);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const command = positional[0] || "help";
|
|
49
|
+
const validCommands = /* @__PURE__ */ new Set([
|
|
50
|
+
"install",
|
|
51
|
+
"update",
|
|
52
|
+
"use",
|
|
53
|
+
"doctor",
|
|
54
|
+
"init-project",
|
|
55
|
+
"migrate-project",
|
|
56
|
+
"record",
|
|
57
|
+
"help",
|
|
58
|
+
"--help",
|
|
59
|
+
"-h"
|
|
60
|
+
]);
|
|
61
|
+
if (command === "help" || command === "--help" || command === "-h") {
|
|
62
|
+
return { command: "help", args: positional.slice(1), flags };
|
|
63
|
+
}
|
|
64
|
+
if (!validCommands.has(command)) {
|
|
65
|
+
return { command: "help", args: positional, flags };
|
|
66
|
+
}
|
|
67
|
+
return { command, args: positional.slice(1), flags };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/commands/doctor.ts
|
|
71
|
+
import fs2 from "fs";
|
|
72
|
+
import path3 from "path";
|
|
73
|
+
import { spawn } from "child_process";
|
|
74
|
+
|
|
75
|
+
// src/lib/paths.ts
|
|
76
|
+
import path from "path";
|
|
77
|
+
import os from "os";
|
|
78
|
+
function resolveLincolnPaths(overrideHomeDir) {
|
|
79
|
+
const homeDir = overrideHomeDir ?? os.homedir();
|
|
80
|
+
const lincolnHome = process.env.LINCOLN_HOME ? path.resolve(process.env.LINCOLN_HOME) : path.join(homeDir, ".lincoln");
|
|
22
81
|
return {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
82
|
+
homeDir,
|
|
83
|
+
lincolnHome,
|
|
84
|
+
versionsDir: path.join(lincolnHome, "versions"),
|
|
85
|
+
currentDir: path.join(lincolnHome, "current"),
|
|
86
|
+
versionMarker: path.join(lincolnHome, "marker.json"),
|
|
87
|
+
venvDir: path.join(lincolnHome, "venv"),
|
|
88
|
+
claudeDir: path.join(homeDir, ".claude"),
|
|
89
|
+
codexDir: path.join(homeDir, ".codex"),
|
|
90
|
+
opencodeDir: path.join(homeDir, ".opencode")
|
|
29
91
|
};
|
|
30
92
|
}
|
|
31
93
|
|
|
32
|
-
// src/
|
|
33
|
-
import
|
|
34
|
-
import
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const isJson = trimmed.startsWith("{") || trimmed.startsWith("[");
|
|
46
|
-
const raw = isJson ? JSON.parse(trimmed) : yaml.load(trimmed);
|
|
47
|
-
if (raw === null || typeof raw !== "object") {
|
|
48
|
-
return {};
|
|
94
|
+
// src/lib/versionMarker.ts
|
|
95
|
+
import fs from "fs";
|
|
96
|
+
import path2 from "path";
|
|
97
|
+
function readVersionMarker(paths) {
|
|
98
|
+
try {
|
|
99
|
+
const raw = fs.readFileSync(paths.versionMarker, "utf8");
|
|
100
|
+
const parsed = JSON.parse(raw);
|
|
101
|
+
if (typeof parsed.version === "string" && typeof parsed.installedAt === "string" && Array.isArray(parsed.harnesses)) {
|
|
102
|
+
return parsed;
|
|
103
|
+
}
|
|
104
|
+
return void 0;
|
|
105
|
+
} catch {
|
|
106
|
+
return void 0;
|
|
49
107
|
}
|
|
50
|
-
|
|
108
|
+
}
|
|
109
|
+
function writeVersionMarker(paths, marker) {
|
|
110
|
+
fs.mkdirSync(path2.dirname(paths.versionMarker), { recursive: true });
|
|
111
|
+
fs.writeFileSync(paths.versionMarker, JSON.stringify(marker, null, 2) + "\n");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/commands/doctor.ts
|
|
115
|
+
var MIN_NODE_MAJOR = 20;
|
|
116
|
+
var MIN_PYTHON_MAJOR = 3;
|
|
117
|
+
var MIN_PYTHON_MINOR = 10;
|
|
118
|
+
function createDefaultDeps() {
|
|
119
|
+
const paths = resolveLincolnPaths();
|
|
120
|
+
const pythonCommand = resolvePythonCommand(paths);
|
|
51
121
|
return {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
122
|
+
paths,
|
|
123
|
+
nodeVersion: () => process.version,
|
|
124
|
+
pythonVersion: () => queryCommandVersion(pythonCommand, ["--version"]),
|
|
125
|
+
pyyamlVersion: () => queryPyyamlVersion(pythonCommand),
|
|
126
|
+
npmVersion: () => queryCommandVersion("npm", ["--version"]),
|
|
127
|
+
projectRoot: process.cwd()
|
|
58
128
|
};
|
|
59
129
|
}
|
|
60
|
-
function
|
|
61
|
-
|
|
130
|
+
async function doctor(options = {}, deps = createDefaultDeps()) {
|
|
131
|
+
const checks = [];
|
|
132
|
+
checks.push(checkNode(deps.nodeVersion()));
|
|
133
|
+
checks.push(await checkPython(deps.pythonVersion));
|
|
134
|
+
checks.push(await checkPyyaml(deps.pyyamlVersion));
|
|
135
|
+
checks.push(await checkNpm(deps.npmVersion));
|
|
136
|
+
checks.push(checkGlobalMarker(deps.paths));
|
|
137
|
+
checks.push(checkPayloadHooks(deps.paths));
|
|
138
|
+
checks.push(checkVenv(deps.paths));
|
|
139
|
+
checks.push(checkProjectMarker(deps.projectRoot));
|
|
140
|
+
const hasError = checks.some((c) => c.status === "error");
|
|
141
|
+
const result = { code: hasError ? 1 : 0, checks };
|
|
142
|
+
if (options.json) {
|
|
143
|
+
console.log(JSON.stringify({ checks }, null, 2));
|
|
144
|
+
} else {
|
|
145
|
+
for (const check of checks) {
|
|
146
|
+
const icon = check.status === "ok" ? "\u2713" : check.status === "error" ? "\u2717" : check.status === "warn" ? "!" : "-";
|
|
147
|
+
console.log(`${icon} ${check.name}: ${check.message}`);
|
|
148
|
+
}
|
|
149
|
+
if (hasError) {
|
|
150
|
+
console.error("\nOne or more checks failed.");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
62
154
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
155
|
+
function checkNode(version) {
|
|
156
|
+
const major = parseNodeMajor(version);
|
|
157
|
+
if (major === void 0) {
|
|
158
|
+
return { name: "node", status: "warn", message: `Could not parse Node version: ${version}` };
|
|
159
|
+
}
|
|
160
|
+
if (major < MIN_NODE_MAJOR) {
|
|
161
|
+
return { name: "node", status: "error", message: `Node ${version} is below the minimum required v${MIN_NODE_MAJOR}` };
|
|
162
|
+
}
|
|
163
|
+
return { name: "node", status: "ok", message: `Node ${version}` };
|
|
65
164
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
165
|
+
async function checkPython(query) {
|
|
166
|
+
const version = (await query())?.trim();
|
|
167
|
+
if (!version) {
|
|
168
|
+
return { name: "python", status: "error", message: "Python 3 is not available" };
|
|
69
169
|
}
|
|
70
|
-
|
|
170
|
+
const parsed = parsePythonVersion(version);
|
|
171
|
+
if (!parsed) {
|
|
172
|
+
return { name: "python", status: "warn", message: `Could not parse Python version: ${version}` };
|
|
173
|
+
}
|
|
174
|
+
if (parsed.major < MIN_PYTHON_MAJOR || parsed.major === MIN_PYTHON_MAJOR && parsed.minor < MIN_PYTHON_MINOR) {
|
|
175
|
+
return {
|
|
176
|
+
name: "python",
|
|
177
|
+
status: "error",
|
|
178
|
+
message: `Python ${version} is below the minimum required ${MIN_PYTHON_MAJOR}.${MIN_PYTHON_MINOR}`
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const display = version.replace(/^Python\s+/, "");
|
|
182
|
+
return { name: "python", status: "ok", message: `Python ${display}` };
|
|
71
183
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
} catch (error) {
|
|
77
|
-
throw new Error(`Config file not found: ${String(path)}`);
|
|
184
|
+
async function checkPyyaml(query) {
|
|
185
|
+
const version = await query();
|
|
186
|
+
if (!version) {
|
|
187
|
+
return { name: "pyyaml", status: "error", message: "PyYAML is not installed for Python 3" };
|
|
78
188
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
189
|
+
return { name: "pyyaml", status: "ok", message: `PyYAML ${version}` };
|
|
190
|
+
}
|
|
191
|
+
async function checkNpm(query) {
|
|
192
|
+
const version = await query();
|
|
193
|
+
if (!version) {
|
|
194
|
+
return { name: "npm", status: "warn", message: "npm is not available" };
|
|
195
|
+
}
|
|
196
|
+
return { name: "npm", status: "ok", message: `npm ${version}` };
|
|
197
|
+
}
|
|
198
|
+
function checkGlobalMarker(paths) {
|
|
199
|
+
const marker = readVersionMarker(paths);
|
|
200
|
+
if (!marker) {
|
|
201
|
+
return { name: "global-marker", status: "warn", message: `No version marker at ${paths.versionMarker}` };
|
|
202
|
+
}
|
|
203
|
+
return { name: "global-marker", status: "ok", message: `Lincoln ${marker.version} installed` };
|
|
204
|
+
}
|
|
205
|
+
function checkPayloadHooks(paths) {
|
|
206
|
+
const hooksDir = path3.join(paths.currentDir, ".claude", "hooks");
|
|
207
|
+
if (!fs2.existsSync(hooksDir)) {
|
|
208
|
+
return { name: "payload-hooks", status: "warn", message: `Payload hooks not found at ${hooksDir}` };
|
|
209
|
+
}
|
|
210
|
+
const required = ["on-session-start.sh"];
|
|
211
|
+
const missing = required.filter((f) => !fs2.existsSync(path3.join(hooksDir, f)));
|
|
212
|
+
if (missing.length > 0) {
|
|
213
|
+
return { name: "payload-hooks", status: "warn", message: `Missing hooks: ${missing.join(", ")}` };
|
|
214
|
+
}
|
|
215
|
+
return { name: "payload-hooks", status: "ok", message: `Payload hooks present at ${hooksDir}` };
|
|
216
|
+
}
|
|
217
|
+
function checkVenv(paths) {
|
|
218
|
+
if (!fs2.existsSync(paths.venvDir)) {
|
|
219
|
+
return { name: "venv", status: "warn", message: `Virtual environment not found at ${paths.venvDir}` };
|
|
220
|
+
}
|
|
221
|
+
const pythonExe = path3.join(paths.venvDir, process.platform === "win32" ? "Scripts" : "bin", "python");
|
|
222
|
+
if (!fs2.existsSync(pythonExe)) {
|
|
223
|
+
return { name: "venv", status: "warn", message: `Virtual environment exists but python executable is missing` };
|
|
224
|
+
}
|
|
225
|
+
return { name: "venv", status: "ok", message: `Virtual environment present at ${paths.venvDir}` };
|
|
226
|
+
}
|
|
227
|
+
function checkProjectMarker(projectRoot) {
|
|
228
|
+
const markerPath = path3.join(projectRoot, ".lincoln.yaml");
|
|
229
|
+
if (!fs2.existsSync(markerPath)) {
|
|
230
|
+
return { name: "project-marker", status: "skip", message: `No .lincoln.yaml in ${projectRoot}` };
|
|
231
|
+
}
|
|
232
|
+
return { name: "project-marker", status: "ok", message: `Project marker found at ${markerPath}` };
|
|
233
|
+
}
|
|
234
|
+
function resolvePythonCommand(paths) {
|
|
235
|
+
const venvPython = path3.join(
|
|
236
|
+
paths.venvDir,
|
|
237
|
+
process.platform === "win32" ? "Scripts" : "bin",
|
|
238
|
+
process.platform === "win32" ? "python.exe" : "python"
|
|
239
|
+
);
|
|
240
|
+
if (fs2.existsSync(venvPython)) {
|
|
241
|
+
return venvPython;
|
|
242
|
+
}
|
|
243
|
+
return "python3";
|
|
244
|
+
}
|
|
245
|
+
function parseNodeMajor(version) {
|
|
246
|
+
const match = /^v?(\d+)/.exec(version);
|
|
247
|
+
if (!match) {
|
|
248
|
+
return void 0;
|
|
249
|
+
}
|
|
250
|
+
return Number(match[1]);
|
|
251
|
+
}
|
|
252
|
+
function parsePythonVersion(version) {
|
|
253
|
+
const match = /(\d+)\.(\d+)/.exec(version);
|
|
254
|
+
if (!match) {
|
|
255
|
+
return void 0;
|
|
84
256
|
}
|
|
257
|
+
return { major: Number(match[1]), minor: Number(match[2]) };
|
|
85
258
|
}
|
|
86
|
-
function
|
|
259
|
+
async function queryCommandVersion(command, args) {
|
|
260
|
+
return new Promise((resolvePromise) => {
|
|
261
|
+
const child = spawn(command, args, {
|
|
262
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
263
|
+
shell: process.platform === "win32"
|
|
264
|
+
});
|
|
265
|
+
let stdout = "";
|
|
266
|
+
child.stdout?.on("data", (chunk) => {
|
|
267
|
+
stdout += chunk.toString();
|
|
268
|
+
});
|
|
269
|
+
child.on("close", (code) => {
|
|
270
|
+
const text = stdout.trim();
|
|
271
|
+
resolvePromise(code === 0 && text.length > 0 ? text : void 0);
|
|
272
|
+
});
|
|
273
|
+
child.on("error", () => resolvePromise(void 0));
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
async function queryPyyamlVersion(pythonCommand) {
|
|
277
|
+
return new Promise((resolvePromise) => {
|
|
278
|
+
const child = spawn(
|
|
279
|
+
pythonCommand,
|
|
280
|
+
["-c", "import yaml; print(yaml.__version__)"],
|
|
281
|
+
{ stdio: ["ignore", "pipe", "ignore"], shell: process.platform === "win32" }
|
|
282
|
+
);
|
|
283
|
+
let stdout = "";
|
|
284
|
+
child.stdout?.on("data", (chunk) => {
|
|
285
|
+
stdout += chunk.toString();
|
|
286
|
+
});
|
|
287
|
+
child.on("close", (code) => {
|
|
288
|
+
const text = stdout.trim();
|
|
289
|
+
resolvePromise(code === 0 && text.length > 0 ? text : void 0);
|
|
290
|
+
});
|
|
291
|
+
child.on("error", () => resolvePromise(void 0));
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/lib/packageInfo.ts
|
|
296
|
+
import fs3 from "fs";
|
|
297
|
+
import path4 from "path";
|
|
298
|
+
import { fileURLToPath } from "url";
|
|
299
|
+
function readLocalPackageRoot() {
|
|
87
300
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
301
|
+
let dir = path4.dirname(fileURLToPath(import.meta.url));
|
|
302
|
+
const root = path4.parse(dir).root;
|
|
303
|
+
while (dir !== root) {
|
|
304
|
+
const pkgPath = path4.join(dir, "package.json");
|
|
305
|
+
if (fs3.existsSync(pkgPath)) {
|
|
306
|
+
const parsed = JSON.parse(fs3.readFileSync(pkgPath, "utf8"));
|
|
307
|
+
if (parsed.name === "@sushanglewis/lincoln") {
|
|
308
|
+
return dir;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
dir = path4.dirname(dir);
|
|
93
312
|
}
|
|
94
|
-
|
|
313
|
+
} catch {
|
|
314
|
+
}
|
|
315
|
+
return void 0;
|
|
316
|
+
}
|
|
317
|
+
function readLocalPackageVersion() {
|
|
318
|
+
try {
|
|
319
|
+
const root = readLocalPackageRoot();
|
|
320
|
+
if (!root) return void 0;
|
|
321
|
+
const parsed = JSON.parse(fs3.readFileSync(path4.join(root, "package.json"), "utf8"));
|
|
322
|
+
return typeof parsed.version === "string" ? parsed.version : void 0;
|
|
323
|
+
} catch {
|
|
324
|
+
return void 0;
|
|
95
325
|
}
|
|
96
326
|
}
|
|
327
|
+
function resolvePayloadRoot() {
|
|
328
|
+
const root = readLocalPackageRoot();
|
|
329
|
+
if (!root) return void 0;
|
|
330
|
+
const payload = path4.join(root, "framework");
|
|
331
|
+
return fs3.existsSync(payload) ? payload : void 0;
|
|
332
|
+
}
|
|
97
333
|
|
|
98
|
-
// src/
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
334
|
+
// src/lib/marker.ts
|
|
335
|
+
import fs4 from "fs";
|
|
336
|
+
import path5 from "path";
|
|
337
|
+
import yaml from "js-yaml";
|
|
338
|
+
function readProjectMarker(projectRoot) {
|
|
339
|
+
const markerPath = path5.join(projectRoot, ".lincoln.yaml");
|
|
340
|
+
if (!fs4.existsSync(markerPath)) {
|
|
341
|
+
return void 0;
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
const parsed = yaml.load(fs4.readFileSync(markerPath, "utf8"));
|
|
345
|
+
if (!parsed || typeof parsed !== "object") {
|
|
346
|
+
return void 0;
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
enabled: Boolean(parsed.enabled),
|
|
350
|
+
workflow_template: typeof parsed.workflow_template === "string" ? parsed.workflow_template : void 0,
|
|
351
|
+
min_lincoln_version: typeof parsed.min_lincoln_version === "string" ? parsed.min_lincoln_version : void 0
|
|
352
|
+
};
|
|
353
|
+
} catch {
|
|
354
|
+
return void 0;
|
|
355
|
+
}
|
|
104
356
|
}
|
|
105
|
-
function
|
|
106
|
-
|
|
107
|
-
|
|
357
|
+
function writeProjectMarker(projectRoot, marker, opts = {}) {
|
|
358
|
+
const markerPath = path5.join(projectRoot, ".lincoln.yaml");
|
|
359
|
+
if (fs4.existsSync(markerPath) && !opts.force) {
|
|
360
|
+
throw new Error(`.lincoln.yaml already exists at ${markerPath}; use --force to overwrite`);
|
|
361
|
+
}
|
|
362
|
+
const content = yaml.dump(marker, { sortKeys: false, lineWidth: -1 });
|
|
363
|
+
if (!opts.dryRun) {
|
|
364
|
+
fs4.mkdirSync(projectRoot, { recursive: true });
|
|
365
|
+
fs4.writeFileSync(markerPath, content);
|
|
108
366
|
}
|
|
109
|
-
const normalized = descriptor.trim().toLowerCase().replace(/[^a-z0-9一-龥]+/g, "-").replace(/^-+|-+$/g, "");
|
|
110
|
-
return normalized.slice(0, 80) || "recording";
|
|
111
367
|
}
|
|
112
368
|
|
|
113
|
-
// src/
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
141
|
-
const globalConfig = loadConfigOptional(join(home, ".lincolnrc"));
|
|
142
|
-
const localConfig = loadConfigOptional(join(cwd, ".lincolnrc"));
|
|
143
|
-
const topic = pickFirst(args.topic, localConfig.defaultTopic, globalConfig.defaultTopic);
|
|
144
|
-
const designId = pickFirst(args.designId, localConfig.defaultDesignId, globalConfig.defaultDesignId);
|
|
145
|
-
const branch = pickFirst(args.branch, localConfig.defaultBranch, globalConfig.defaultBranch);
|
|
146
|
-
const descriptor = designId || topic || void 0;
|
|
147
|
-
const sessionId = args.sessionId || uniqueSessionId(cwd, now, descriptor);
|
|
148
|
-
return {
|
|
149
|
-
workspaceRoot: cwd,
|
|
150
|
-
sessionId,
|
|
151
|
-
topic,
|
|
152
|
-
designId,
|
|
153
|
-
branch,
|
|
154
|
-
noTui: args.noTui ?? false,
|
|
155
|
-
autoProcess: localConfig.autoProcess ?? globalConfig.autoProcess ?? false,
|
|
156
|
-
showAudioMeter: localConfig.showAudioMeter ?? globalConfig.showAudioMeter ?? true,
|
|
157
|
-
audioMeterStyle: localConfig.audioMeterStyle ?? globalConfig.audioMeterStyle ?? "bar"
|
|
158
|
-
};
|
|
369
|
+
// src/commands/initProject.ts
|
|
370
|
+
function initProject(projectRoot, options = {}) {
|
|
371
|
+
if (!options.force && readProjectMarker(projectRoot) !== void 0) {
|
|
372
|
+
console.error(`Project already has a .lincoln.yaml. Use --force to overwrite.`);
|
|
373
|
+
return 1;
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
writeProjectMarker(
|
|
377
|
+
projectRoot,
|
|
378
|
+
{
|
|
379
|
+
enabled: true,
|
|
380
|
+
workflow_template: "interview-to-knowledge",
|
|
381
|
+
min_lincoln_version: readLocalPackageVersion() ?? "1.5.0"
|
|
382
|
+
},
|
|
383
|
+
{ force: options.force, dryRun: options.dryRun }
|
|
384
|
+
);
|
|
385
|
+
} catch (err) {
|
|
386
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
387
|
+
console.error(`Failed to write .lincoln.yaml: ${message}`);
|
|
388
|
+
return 1;
|
|
389
|
+
}
|
|
390
|
+
if (options.dryRun) {
|
|
391
|
+
console.log(`Dry run: would create ${projectRoot}/.lincoln.yaml`);
|
|
392
|
+
} else {
|
|
393
|
+
console.log(`Created ${projectRoot}/.lincoln.yaml`);
|
|
394
|
+
}
|
|
395
|
+
return 0;
|
|
159
396
|
}
|
|
160
397
|
|
|
161
|
-
// src/
|
|
162
|
-
import
|
|
163
|
-
import
|
|
398
|
+
// src/commands/install.ts
|
|
399
|
+
import fs7 from "fs";
|
|
400
|
+
import path8 from "path";
|
|
401
|
+
import { spawn as spawn2 } from "child_process";
|
|
164
402
|
|
|
165
|
-
// src/
|
|
166
|
-
import
|
|
403
|
+
// src/lib/syncClaude.ts
|
|
404
|
+
import fs5 from "fs";
|
|
405
|
+
import path6 from "path";
|
|
406
|
+
import crypto from "crypto";
|
|
167
407
|
|
|
168
|
-
// src/
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
}
|
|
408
|
+
// src/lib/claudeMdMerge.ts
|
|
409
|
+
var BEGIN = "<!-- lincoln:begin -->";
|
|
410
|
+
var END = "<!-- lincoln:end -->";
|
|
411
|
+
function mergeManagedBlock(existing, block) {
|
|
412
|
+
const wrapped = `${BEGIN}
|
|
413
|
+
${block}
|
|
414
|
+
${END}`;
|
|
415
|
+
const text = existing ?? "";
|
|
416
|
+
const beginIndex = text.indexOf(BEGIN);
|
|
417
|
+
const endIndex = text.indexOf(END);
|
|
418
|
+
if (beginIndex !== -1 && endIndex !== -1 && endIndex > beginIndex) {
|
|
419
|
+
return text.slice(0, beginIndex) + wrapped + text.slice(endIndex + END.length);
|
|
420
|
+
}
|
|
421
|
+
if (text.trim().length === 0) {
|
|
422
|
+
return wrapped;
|
|
423
|
+
}
|
|
424
|
+
return `${text.trimEnd()}
|
|
175
425
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
function StatusPanel({
|
|
179
|
-
sessionId,
|
|
180
|
-
topic,
|
|
181
|
-
designId,
|
|
182
|
-
branch,
|
|
183
|
-
status,
|
|
184
|
-
duration
|
|
185
|
-
}) {
|
|
186
|
-
const statusLabel = {
|
|
187
|
-
idle: "Ready",
|
|
188
|
-
recording: `Recording ${formatDuration(duration)}`,
|
|
189
|
-
stopped: "Stopped",
|
|
190
|
-
cancelled: "Cancelled",
|
|
191
|
-
error: "Error"
|
|
192
|
-
}[status];
|
|
193
|
-
const statusColor = status === "recording" ? "red" : status === "error" ? "red" : status === "cancelled" ? "yellow" : "green";
|
|
194
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
195
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", justifyContent: "space-between", alignItems: "center", children: [
|
|
196
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: "Lincoln Recorder" }),
|
|
197
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
198
|
-
/* @__PURE__ */ jsx(Text, { color: statusColor, children: status === "recording" ? "\u25CF" : "\u25CB" }),
|
|
199
|
-
/* @__PURE__ */ jsx(Text, { children: statusLabel })
|
|
200
|
-
] })
|
|
201
|
-
] }),
|
|
202
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingY: 1, children: [
|
|
203
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
204
|
-
"Session: ",
|
|
205
|
-
sessionId
|
|
206
|
-
] }),
|
|
207
|
-
topic ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
208
|
-
"Topic: ",
|
|
209
|
-
topic
|
|
210
|
-
] }) : null,
|
|
211
|
-
designId ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
212
|
-
"Design: ",
|
|
213
|
-
designId
|
|
214
|
-
] }) : null,
|
|
215
|
-
branch ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
216
|
-
"Branch: ",
|
|
217
|
-
branch
|
|
218
|
-
] }) : null
|
|
219
|
-
] })
|
|
220
|
-
] });
|
|
426
|
+
${wrapped}
|
|
427
|
+
`;
|
|
221
428
|
}
|
|
222
429
|
|
|
223
|
-
// src/
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
visible.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No events yet." }) : visible.map((log) => /* @__PURE__ */ jsx2(Text2, { color: TYPE_COLORS[log.type ?? "info"], children: log.message }, log.id))
|
|
237
|
-
] });
|
|
430
|
+
// src/lib/syncClaude.ts
|
|
431
|
+
var COPY_SUBDIRS = [
|
|
432
|
+
"agents",
|
|
433
|
+
"skills",
|
|
434
|
+
"workflows",
|
|
435
|
+
"stages",
|
|
436
|
+
"schemas",
|
|
437
|
+
"templates",
|
|
438
|
+
"harnesses"
|
|
439
|
+
];
|
|
440
|
+
function sha256(filePath) {
|
|
441
|
+
const data = fs5.readFileSync(filePath);
|
|
442
|
+
return crypto.createHash("sha256").update(data).digest("hex");
|
|
238
443
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
import { Box as Box3, Text as Text3 } from "ink";
|
|
242
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
243
|
-
var HINTS = {
|
|
244
|
-
idle: "[r] record [d] devices [m] model [q] quit",
|
|
245
|
-
recording: "[s] stop [c] cancel",
|
|
246
|
-
stopped: "[any key] exit",
|
|
247
|
-
cancelled: "[q] exit",
|
|
248
|
-
error: "[q] exit",
|
|
249
|
-
menu: "[\u2191\u2193] select [enter] confirm [esc] back"
|
|
250
|
-
};
|
|
251
|
-
function HintBar({ mode }) {
|
|
252
|
-
return /* @__PURE__ */ jsx3(Box3, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: HINTS[mode] }) });
|
|
444
|
+
function sameContent(a, b) {
|
|
445
|
+
return sha256(a) === sha256(b);
|
|
253
446
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
useInput((_input, key) => {
|
|
266
|
-
if (key.escape) {
|
|
267
|
-
onClose();
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (key.upArrow) {
|
|
271
|
-
setIndex((i) => i > 0 ? i - 1 : items.length - 1);
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
if (key.downArrow) {
|
|
275
|
-
setIndex((i) => i < items.length - 1 ? i + 1 : 0);
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
if (key.return && items.length > 0) {
|
|
279
|
-
onSelect(items[Math.min(index, items.length - 1)].key);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingX: 1, children: [
|
|
283
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, children: title }),
|
|
284
|
-
items.length === 0 ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "(none)" }) : items.map((item, i) => /* @__PURE__ */ jsxs3(Text4, { color: i === index ? "cyan" : void 0, children: [
|
|
285
|
-
i === index ? "\u203A" : " ",
|
|
286
|
-
" ",
|
|
287
|
-
item.label
|
|
288
|
-
] }, item.key)),
|
|
289
|
-
footer ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: footer }) : null
|
|
290
|
-
] });
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// src/components/DevicesMenu.tsx
|
|
294
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
295
|
-
function DevicesMenu({ listDevicesFn, onSelect, onClose }) {
|
|
296
|
-
const [loadState, setLoadState] = useState2({ status: "loading" });
|
|
297
|
-
useEffect(() => {
|
|
298
|
-
let cancelled = false;
|
|
299
|
-
listDevicesFn().then((list2) => {
|
|
300
|
-
if (!cancelled) setLoadState({ status: "loaded", list: list2 });
|
|
301
|
-
}).catch((error) => {
|
|
302
|
-
if (!cancelled) {
|
|
303
|
-
setLoadState({
|
|
304
|
-
status: "error",
|
|
305
|
-
message: error instanceof Error ? error.message : String(error)
|
|
306
|
-
});
|
|
447
|
+
function deepMergeSettings(existing, incoming) {
|
|
448
|
+
if (Array.isArray(existing) && Array.isArray(incoming)) {
|
|
449
|
+
return incoming;
|
|
450
|
+
}
|
|
451
|
+
if (typeof existing === "object" && existing !== null && typeof incoming === "object" && incoming !== null) {
|
|
452
|
+
const result = { ...existing };
|
|
453
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
454
|
+
if (key in result) {
|
|
455
|
+
result[key] = deepMergeSettings(result[key], value);
|
|
456
|
+
} else {
|
|
457
|
+
result[key] = value;
|
|
307
458
|
}
|
|
308
|
-
});
|
|
309
|
-
return () => {
|
|
310
|
-
cancelled = true;
|
|
311
|
-
};
|
|
312
|
-
}, [listDevicesFn]);
|
|
313
|
-
useInput2(
|
|
314
|
-
(_input, key) => {
|
|
315
|
-
if (key.escape) onClose();
|
|
316
|
-
},
|
|
317
|
-
{ isActive: loadState.status !== "loaded" }
|
|
318
|
-
);
|
|
319
|
-
if (loadState.status === "loading") {
|
|
320
|
-
return /* @__PURE__ */ jsx5(Box5, { paddingX: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Loading devices\u2026" }) });
|
|
321
|
-
}
|
|
322
|
-
if (loadState.status === "error") {
|
|
323
|
-
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", paddingX: 1, children: [
|
|
324
|
-
/* @__PURE__ */ jsxs4(Text5, { color: "red", children: [
|
|
325
|
-
"Failed to list devices: ",
|
|
326
|
-
loadState.message
|
|
327
|
-
] }),
|
|
328
|
-
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[esc] back" })
|
|
329
|
-
] });
|
|
330
|
-
}
|
|
331
|
-
const { list } = loadState;
|
|
332
|
-
const items = list.devices.map((name) => ({
|
|
333
|
-
key: name,
|
|
334
|
-
label: name === list.defaultDevice ? `${name} (default)` : name
|
|
335
|
-
}));
|
|
336
|
-
return /* @__PURE__ */ jsx5(
|
|
337
|
-
SelectMenu,
|
|
338
|
-
{
|
|
339
|
-
title: "Devices",
|
|
340
|
-
items,
|
|
341
|
-
onSelect,
|
|
342
|
-
onClose,
|
|
343
|
-
footer: "[\u2191\u2193] select [enter] confirm [esc] back"
|
|
344
459
|
}
|
|
345
|
-
|
|
460
|
+
return result;
|
|
461
|
+
}
|
|
462
|
+
return incoming;
|
|
346
463
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
useEffect2(() => {
|
|
355
|
-
let cancelled = false;
|
|
356
|
-
listModelStatusesFn().then((models) => {
|
|
357
|
-
if (!cancelled) setMenuState({ status: "loaded", models });
|
|
358
|
-
}).catch((error) => {
|
|
359
|
-
if (!cancelled) {
|
|
360
|
-
setMenuState({
|
|
361
|
-
status: "error",
|
|
362
|
-
message: error instanceof Error ? error.message : String(error)
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
return () => {
|
|
367
|
-
cancelled = true;
|
|
368
|
-
};
|
|
369
|
-
}, [listModelStatusesFn]);
|
|
370
|
-
useInput3(
|
|
371
|
-
(_input, key) => {
|
|
372
|
-
if (key.escape) onClose();
|
|
373
|
-
},
|
|
374
|
-
{ isActive: menuState.status === "error" }
|
|
375
|
-
);
|
|
376
|
-
const handleSelect = (name) => {
|
|
377
|
-
if (menuState.status !== "loaded") return;
|
|
378
|
-
const target = menuState.models.find((m) => m.name === name);
|
|
379
|
-
if (!target) return;
|
|
380
|
-
if (target.cached) {
|
|
381
|
-
onSelect(name);
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
setMenuState({ status: "downloading", model: name, percent: null, downloaded: 0 });
|
|
385
|
-
runWarmupFn(name, (progress) => {
|
|
386
|
-
setMenuState({
|
|
387
|
-
status: "downloading",
|
|
388
|
-
model: name,
|
|
389
|
-
percent: progress.percent,
|
|
390
|
-
downloaded: progress.downloaded
|
|
391
|
-
});
|
|
392
|
-
}).then(() => onSelect(name)).catch((error) => {
|
|
393
|
-
setMenuState({
|
|
394
|
-
status: "error",
|
|
395
|
-
message: error instanceof Error ? error.message : String(error)
|
|
396
|
-
});
|
|
397
|
-
});
|
|
464
|
+
function syncClaudeCode(opts) {
|
|
465
|
+
const report = {
|
|
466
|
+
written: [],
|
|
467
|
+
skipped: [],
|
|
468
|
+
preserved: [],
|
|
469
|
+
warnings: [],
|
|
470
|
+
settingsTouched: []
|
|
398
471
|
};
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
412
|
-
"Downloading model '",
|
|
413
|
-
menuState.model,
|
|
414
|
-
"'\u2026 ",
|
|
415
|
-
progressText
|
|
416
|
-
] }),
|
|
417
|
-
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "please wait" })
|
|
418
|
-
] });
|
|
419
|
-
}
|
|
420
|
-
const items = menuState.models.map((m) => ({
|
|
421
|
-
key: m.name,
|
|
422
|
-
label: m.cached ? `\u2713 ${m.name}` : `\xB7 ${m.name} (not downloaded)`
|
|
423
|
-
}));
|
|
424
|
-
return /* @__PURE__ */ jsx6(
|
|
425
|
-
SelectMenu,
|
|
426
|
-
{
|
|
427
|
-
title: "Model",
|
|
428
|
-
items,
|
|
429
|
-
onSelect: handleSelect,
|
|
430
|
-
onClose,
|
|
431
|
-
footer: "[\u2191\u2193] select [enter] confirm [esc] back"
|
|
472
|
+
const payloadClaude = path6.join(opts.payloadRoot, ".claude");
|
|
473
|
+
if (!fs5.existsSync(payloadClaude)) {
|
|
474
|
+
report.warnings.push(`payload .claude directory not found: ${payloadClaude}`);
|
|
475
|
+
return report;
|
|
476
|
+
}
|
|
477
|
+
if (!opts.dryRun) {
|
|
478
|
+
fs5.mkdirSync(opts.targetDir, { recursive: true });
|
|
479
|
+
}
|
|
480
|
+
for (const subdir of COPY_SUBDIRS) {
|
|
481
|
+
const srcDir = path6.join(payloadClaude, subdir);
|
|
482
|
+
if (!fs5.existsSync(srcDir)) {
|
|
483
|
+
continue;
|
|
432
484
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
onDevices,
|
|
445
|
-
onModel,
|
|
446
|
-
onAnyKey
|
|
447
|
-
}) {
|
|
448
|
-
useInput4(
|
|
449
|
-
(input, key) => {
|
|
450
|
-
if (key.escape || input === "q" || input === "Q") {
|
|
451
|
-
onQuit?.();
|
|
452
|
-
return;
|
|
485
|
+
const destDir = path6.join(opts.targetDir, subdir);
|
|
486
|
+
if (!opts.dryRun) {
|
|
487
|
+
fs5.mkdirSync(destDir, { recursive: true });
|
|
488
|
+
}
|
|
489
|
+
for (const entry of walkSync(srcDir)) {
|
|
490
|
+
const relativePath = path6.relative(srcDir, entry);
|
|
491
|
+
const srcFile = entry;
|
|
492
|
+
const destFile = path6.join(destDir, relativePath);
|
|
493
|
+
if (fs5.existsSync(destFile) && sameContent(srcFile, destFile)) {
|
|
494
|
+
report.skipped.push(path6.join(".claude", subdir, relativePath));
|
|
495
|
+
continue;
|
|
453
496
|
}
|
|
454
|
-
if (
|
|
455
|
-
|
|
456
|
-
|
|
497
|
+
if (!opts.dryRun) {
|
|
498
|
+
fs5.mkdirSync(path6.dirname(destFile), { recursive: true });
|
|
499
|
+
fs5.copyFileSync(srcFile, destFile);
|
|
457
500
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
return;
|
|
475
|
-
case "m":
|
|
476
|
-
case "M":
|
|
477
|
-
onModel?.();
|
|
478
|
-
return;
|
|
501
|
+
report.written.push(path6.join(".claude", subdir, relativePath));
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const payloadSettings = path6.join(payloadClaude, "settings.json");
|
|
505
|
+
const targetSettings = path6.join(opts.targetDir, "settings.json");
|
|
506
|
+
if (fs5.existsSync(payloadSettings)) {
|
|
507
|
+
const incoming = JSON.parse(fs5.readFileSync(payloadSettings, "utf8"));
|
|
508
|
+
let merged = incoming;
|
|
509
|
+
if (fs5.existsSync(targetSettings)) {
|
|
510
|
+
const existing = JSON.parse(fs5.readFileSync(targetSettings, "utf8"));
|
|
511
|
+
merged = deepMergeSettings(existing, incoming);
|
|
512
|
+
}
|
|
513
|
+
const wouldChange = !fs5.existsSync(targetSettings) || JSON.stringify(merged) !== JSON.stringify(JSON.parse(fs5.readFileSync(targetSettings, "utf8")));
|
|
514
|
+
if (wouldChange) {
|
|
515
|
+
if (!opts.dryRun) {
|
|
516
|
+
fs5.writeFileSync(targetSettings, JSON.stringify(merged, null, 2) + "\n");
|
|
479
517
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
518
|
+
report.written.push(".claude/settings.json");
|
|
519
|
+
report.settingsTouched = [".claude/settings.json"];
|
|
520
|
+
} else {
|
|
521
|
+
report.skipped.push(".claude/settings.json");
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
const payloadClaudeMd = path6.join(opts.payloadRoot, "CLAUDE.md");
|
|
525
|
+
const targetClaudeMd = path6.join(path6.dirname(opts.targetDir), "CLAUDE.md");
|
|
526
|
+
if (fs5.existsSync(payloadClaudeMd)) {
|
|
527
|
+
const incomingBlock = fs5.readFileSync(payloadClaudeMd, "utf8");
|
|
528
|
+
const existing = fs5.existsSync(targetClaudeMd) ? fs5.readFileSync(targetClaudeMd, "utf8") : void 0;
|
|
529
|
+
const merged = mergeManagedBlock(existing, incomingBlock);
|
|
530
|
+
if (merged !== existing) {
|
|
531
|
+
if (!opts.dryRun) {
|
|
532
|
+
fs5.writeFileSync(targetClaudeMd, merged);
|
|
533
|
+
}
|
|
534
|
+
report.written.push("CLAUDE.md");
|
|
535
|
+
} else {
|
|
536
|
+
report.skipped.push("CLAUDE.md");
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return report;
|
|
540
|
+
}
|
|
541
|
+
function* walkSync(dir) {
|
|
542
|
+
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
543
|
+
for (const entry of entries) {
|
|
544
|
+
const fullPath = path6.join(dir, entry.name);
|
|
545
|
+
if (entry.isDirectory()) {
|
|
546
|
+
yield* walkSync(fullPath);
|
|
547
|
+
} else {
|
|
548
|
+
yield fullPath;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
484
551
|
}
|
|
485
552
|
|
|
486
|
-
// src/
|
|
487
|
-
import
|
|
553
|
+
// src/lib/harnessDetect.ts
|
|
554
|
+
import fs6 from "fs";
|
|
555
|
+
import path7 from "path";
|
|
556
|
+
import os2 from "os";
|
|
557
|
+
var HARNESS_SPECS = [
|
|
558
|
+
{
|
|
559
|
+
id: "claude-code",
|
|
560
|
+
configDirName: ".claude",
|
|
561
|
+
pluginMarker: "plugins/lincoln"
|
|
562
|
+
},
|
|
563
|
+
{ id: "codex", configDirName: ".codex" },
|
|
564
|
+
{ id: "opencode", configDirName: ".opencode" }
|
|
565
|
+
];
|
|
566
|
+
function detectGlobalHarnesses(overrideHomeDir) {
|
|
567
|
+
const homeDir = overrideHomeDir ?? os2.homedir();
|
|
568
|
+
return HARNESS_SPECS.map((spec) => {
|
|
569
|
+
const configDir = path7.join(homeDir, spec.configDirName);
|
|
570
|
+
const installed = fs6.existsSync(configDir);
|
|
571
|
+
const pluginManaged = spec.pluginMarker ? fs6.existsSync(path7.join(configDir, spec.pluginMarker)) : false;
|
|
572
|
+
return {
|
|
573
|
+
id: spec.id,
|
|
574
|
+
installed,
|
|
575
|
+
configDir,
|
|
576
|
+
pluginManaged
|
|
577
|
+
};
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
function installedHarnessIds(homeDir) {
|
|
581
|
+
return detectGlobalHarnesses(homeDir).filter((h) => h.installed).map((h) => h.id);
|
|
582
|
+
}
|
|
488
583
|
|
|
489
|
-
// src/
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
exitPromise;
|
|
496
|
-
resolveExit = () => {
|
|
584
|
+
// src/commands/install.ts
|
|
585
|
+
function createDefaultDeps2() {
|
|
586
|
+
return {
|
|
587
|
+
paths: resolveLincolnPaths(),
|
|
588
|
+
payloadRoot: resolvePayloadRoot() || "",
|
|
589
|
+
syncClaude: syncClaudeCode
|
|
497
590
|
};
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
591
|
+
}
|
|
592
|
+
async function install(options, deps = createDefaultDeps2()) {
|
|
593
|
+
if (!options.dryRun && !options.yes) {
|
|
594
|
+
console.error("This will install Lincoln globally. Run with --yes to proceed.");
|
|
595
|
+
return 1;
|
|
596
|
+
}
|
|
597
|
+
const version = readLocalPackageVersion();
|
|
598
|
+
if (!version) {
|
|
599
|
+
console.error("Could not determine Lincoln version");
|
|
600
|
+
return 1;
|
|
601
|
+
}
|
|
602
|
+
const harnesses = options.harnesses.length > 0 ? options.harnesses : installedHarnessIds(deps.paths.homeDir);
|
|
603
|
+
if (harnesses.length === 0) {
|
|
604
|
+
console.error("No agent harness detected. Install Claude Code, Codex, or OpenCode first.");
|
|
605
|
+
return 1;
|
|
606
|
+
}
|
|
607
|
+
const payloadRoot = deps.payloadRoot;
|
|
608
|
+
if (!payloadRoot || !fs7.existsSync(payloadRoot)) {
|
|
609
|
+
console.error(
|
|
610
|
+
`Lincoln payload not found. Run "npm install -g @sushanglewis/lincoln" first.`
|
|
611
|
+
);
|
|
612
|
+
return 1;
|
|
613
|
+
}
|
|
614
|
+
const versionDir = path8.join(deps.paths.versionsDir, version);
|
|
615
|
+
if (!options.dryRun) {
|
|
616
|
+
fs7.mkdirSync(versionDir, { recursive: true });
|
|
617
|
+
fs7.cpSync(payloadRoot, versionDir, { recursive: true, force: true });
|
|
618
|
+
try {
|
|
619
|
+
fs7.rmSync(deps.paths.currentDir, { recursive: true, force: true });
|
|
620
|
+
fs7.symlinkSync(versionDir, deps.paths.currentDir);
|
|
621
|
+
} catch {
|
|
622
|
+
fs7.rmSync(deps.paths.currentDir, { recursive: true, force: true });
|
|
623
|
+
fs7.cpSync(versionDir, deps.paths.currentDir, { recursive: true, force: true });
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
const report = deps.syncClaude({
|
|
627
|
+
payloadRoot: deps.paths.currentDir,
|
|
628
|
+
targetDir: deps.paths.claudeDir,
|
|
629
|
+
version,
|
|
630
|
+
dryRun: options.dryRun
|
|
631
|
+
});
|
|
632
|
+
if (!options.dryRun && !options.noVenv) {
|
|
633
|
+
const python = await resolvePythonForVenv();
|
|
634
|
+
if (!python) {
|
|
635
|
+
console.error(
|
|
636
|
+
"Python 3.10+ is required but was not found. Set LINCOLN_PYTHON to a compatible Python executable."
|
|
637
|
+
);
|
|
638
|
+
return 1;
|
|
639
|
+
}
|
|
640
|
+
await setupVenv(deps.paths, payloadRoot, python);
|
|
641
|
+
}
|
|
642
|
+
if (!options.dryRun) {
|
|
643
|
+
writeVersionMarker(deps.paths, {
|
|
644
|
+
version,
|
|
645
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
646
|
+
harnesses,
|
|
647
|
+
managedFiles: report.written
|
|
504
648
|
});
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
649
|
+
}
|
|
650
|
+
if (options.dryRun) {
|
|
651
|
+
console.log(`Dry run: would install Lincoln ${version} for harnesses: ${harnesses.join(", ")}`);
|
|
652
|
+
console.log(`Would write ${report.written.length} files`);
|
|
653
|
+
} else {
|
|
654
|
+
console.log(`Installed Lincoln ${version} for harnesses: ${harnesses.join(", ")}`);
|
|
655
|
+
console.log(`Wrote ${report.written.length} files`);
|
|
656
|
+
}
|
|
657
|
+
return 0;
|
|
658
|
+
}
|
|
659
|
+
function runCommand(command, args) {
|
|
660
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
661
|
+
const child = spawn2(command, args, { stdio: "inherit" });
|
|
662
|
+
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
663
|
+
child.on("error", (err) => rejectPromise(err));
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
var MIN_PYTHON_MAJOR2 = 3;
|
|
667
|
+
var MIN_PYTHON_MINOR2 = 10;
|
|
668
|
+
var DEFAULT_PYTHON_CANDIDATES = ["python3.12", "python3.11", "python3.10", "python3"];
|
|
669
|
+
function parsePythonVersion2(version) {
|
|
670
|
+
const match = /(\d+)\.(\d+)/.exec(version);
|
|
671
|
+
if (!match) {
|
|
672
|
+
return void 0;
|
|
673
|
+
}
|
|
674
|
+
return { major: Number(match[1]), minor: Number(match[2]) };
|
|
675
|
+
}
|
|
676
|
+
async function queryPythonVersion(command) {
|
|
677
|
+
return new Promise((resolvePromise) => {
|
|
678
|
+
const child = spawn2(command, ["--version"], {
|
|
679
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
680
|
+
shell: process.platform === "win32"
|
|
508
681
|
});
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
682
|
+
let stdout = "";
|
|
683
|
+
child.stdout?.on("data", (chunk) => {
|
|
684
|
+
stdout += chunk.toString();
|
|
512
685
|
});
|
|
513
|
-
|
|
514
|
-
|
|
686
|
+
child.on("close", (code) => {
|
|
687
|
+
const text = stdout.trim();
|
|
688
|
+
resolvePromise(code === 0 && text.length > 0 ? text : void 0);
|
|
515
689
|
});
|
|
516
|
-
|
|
517
|
-
|
|
690
|
+
child.on("error", () => resolvePromise(void 0));
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
async function resolvePythonForVenv(envOverride = process.env.LINCOLN_PYTHON, candidates = DEFAULT_PYTHON_CANDIDATES, queryVersion = queryPythonVersion) {
|
|
694
|
+
const list = envOverride ? [envOverride] : candidates;
|
|
695
|
+
for (const cmd of list) {
|
|
696
|
+
const version = await queryVersion(cmd);
|
|
697
|
+
if (!version) {
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
const parsed = parsePythonVersion2(version);
|
|
701
|
+
if (parsed && parsed.major >= MIN_PYTHON_MAJOR2 && (parsed.major > MIN_PYTHON_MAJOR2 || parsed.minor >= MIN_PYTHON_MINOR2)) {
|
|
702
|
+
return cmd;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return void 0;
|
|
706
|
+
}
|
|
707
|
+
async function setupVenv(paths, payloadRoot, pythonCommand) {
|
|
708
|
+
const pythonExe = path8.join(
|
|
709
|
+
paths.venvDir,
|
|
710
|
+
process.platform === "win32" ? "Scripts" : "bin",
|
|
711
|
+
process.platform === "win32" ? "python.exe" : "python"
|
|
712
|
+
);
|
|
713
|
+
if (!fs7.existsSync(pythonExe)) {
|
|
714
|
+
console.log("Creating Lincoln virtual environment...");
|
|
715
|
+
await runCommand(pythonCommand, ["-m", "venv", paths.venvDir]);
|
|
716
|
+
}
|
|
717
|
+
const requirementsPath = path8.join(payloadRoot, "requirements.txt");
|
|
718
|
+
if (fs7.existsSync(requirementsPath)) {
|
|
719
|
+
console.log("Installing Python dependencies...");
|
|
720
|
+
const pipExe = path8.join(
|
|
721
|
+
paths.venvDir,
|
|
722
|
+
process.platform === "win32" ? "Scripts" : "bin",
|
|
723
|
+
process.platform === "win32" ? "pip.exe" : "pip"
|
|
724
|
+
);
|
|
725
|
+
await runCommand(pipExe, ["install", "-r", requirementsPath]);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// src/commands/update.ts
|
|
730
|
+
import { spawn as spawn3 } from "child_process";
|
|
731
|
+
|
|
732
|
+
// src/lib/npmRegistry.ts
|
|
733
|
+
var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org";
|
|
734
|
+
var FETCH_TIMEOUT_MS = 15e3;
|
|
735
|
+
function createRegistryClient(registryUrl = DEFAULT_REGISTRY_URL, fetchImpl = fetch) {
|
|
736
|
+
const baseUrl = registryUrl.replace(/\/+$/, "");
|
|
737
|
+
async function fetchPackument(packageName) {
|
|
738
|
+
const url = `${baseUrl}/${encodePackageName(packageName)}`;
|
|
739
|
+
const response = await fetchImpl(url, {
|
|
740
|
+
headers: { Accept: "application/json" },
|
|
741
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
518
742
|
});
|
|
519
|
-
|
|
743
|
+
if (!response.ok) {
|
|
744
|
+
throw new Error(
|
|
745
|
+
`npm registry returned ${response.status} ${response.statusText} for ${packageName}`
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
return await response.json();
|
|
520
749
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
750
|
+
return {
|
|
751
|
+
async latestVersion(packageName) {
|
|
752
|
+
const packument = await fetchPackument(packageName);
|
|
753
|
+
const latest = packument["dist-tags"]?.latest;
|
|
754
|
+
if (!latest) {
|
|
755
|
+
throw new Error(`npm registry has no latest dist-tag for ${packageName}`);
|
|
756
|
+
}
|
|
757
|
+
return latest;
|
|
758
|
+
},
|
|
759
|
+
async versions(packageName) {
|
|
760
|
+
const packument = await fetchPackument(packageName);
|
|
761
|
+
return Object.keys(packument.versions ?? {});
|
|
762
|
+
},
|
|
763
|
+
async resolveVersion(packageName, spec) {
|
|
764
|
+
const packument = await fetchPackument(packageName);
|
|
765
|
+
const tagTarget = packument["dist-tags"]?.[spec];
|
|
766
|
+
if (tagTarget) {
|
|
767
|
+
return tagTarget;
|
|
768
|
+
}
|
|
769
|
+
if (packument.versions && spec in packument.versions) {
|
|
770
|
+
return spec;
|
|
771
|
+
}
|
|
772
|
+
throw new Error(`Version not found for ${packageName}: ${spec}`);
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function encodePackageName(packageName) {
|
|
777
|
+
if (packageName.startsWith("@")) {
|
|
778
|
+
const slash = packageName.indexOf("/");
|
|
779
|
+
if (slash === -1) {
|
|
780
|
+
return encodeURIComponent(packageName);
|
|
525
781
|
}
|
|
782
|
+
const scope = packageName.slice(1, slash);
|
|
783
|
+
const name = packageName.slice(slash + 1);
|
|
784
|
+
return `@${encodeURIComponent(scope)}%2F${encodeURIComponent(name)}`;
|
|
785
|
+
}
|
|
786
|
+
return encodeURIComponent(packageName);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// src/lib/semver.ts
|
|
790
|
+
var SEMVER_CORE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
791
|
+
var NUMERIC_IDENTIFIER = /^\d+$/;
|
|
792
|
+
function compareVersions(a, b) {
|
|
793
|
+
const pa = parseVersion(a);
|
|
794
|
+
const pb = parseVersion(b);
|
|
795
|
+
if (!pa || !pb) {
|
|
796
|
+
return void 0;
|
|
797
|
+
}
|
|
798
|
+
if (pa.major !== pb.major) return pa.major - pb.major;
|
|
799
|
+
if (pa.minor !== pb.minor) return pa.minor - pb.minor;
|
|
800
|
+
if (pa.patch !== pb.patch) return pa.patch - pb.patch;
|
|
801
|
+
return comparePrerelease(pa.prerelease, pb.prerelease);
|
|
802
|
+
}
|
|
803
|
+
function parseVersion(version) {
|
|
804
|
+
const match = SEMVER_CORE.exec(version.trim());
|
|
805
|
+
if (!match) {
|
|
806
|
+
return void 0;
|
|
526
807
|
}
|
|
527
|
-
|
|
528
|
-
|
|
808
|
+
return {
|
|
809
|
+
major: Number(match[1]),
|
|
810
|
+
minor: Number(match[2]),
|
|
811
|
+
patch: Number(match[3]),
|
|
812
|
+
prerelease: match[4] ? match[4].split(".") : []
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
function comparePrerelease(a, b) {
|
|
816
|
+
if (a.length === 0 && b.length === 0) return 0;
|
|
817
|
+
if (a.length === 0) return 1;
|
|
818
|
+
if (b.length === 0) return -1;
|
|
819
|
+
const shared = Math.min(a.length, b.length);
|
|
820
|
+
for (let i = 0; i < shared; i++) {
|
|
821
|
+
const x = a[i];
|
|
822
|
+
const y = b[i];
|
|
823
|
+
if (x === y) continue;
|
|
824
|
+
const xNumeric = NUMERIC_IDENTIFIER.test(x);
|
|
825
|
+
const yNumeric = NUMERIC_IDENTIFIER.test(y);
|
|
826
|
+
if (xNumeric && yNumeric) return Number(x) - Number(y);
|
|
827
|
+
if (xNumeric) return -1;
|
|
828
|
+
if (yNumeric) return 1;
|
|
829
|
+
return x < y ? -1 : 1;
|
|
529
830
|
}
|
|
530
|
-
|
|
531
|
-
|
|
831
|
+
return a.length - b.length;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// src/commands/update.ts
|
|
835
|
+
var PACKAGE_NAME = "@sushanglewis/lincoln";
|
|
836
|
+
function createDefaultDeps3() {
|
|
837
|
+
const paths = resolveLincolnPaths();
|
|
838
|
+
const registry = createRegistryClient();
|
|
839
|
+
return {
|
|
840
|
+
paths,
|
|
841
|
+
latestVersion: () => registry.latestVersion(PACKAGE_NAME),
|
|
842
|
+
currentVersion: () => readVersionMarker(paths)?.version ?? readLocalPackageVersion(),
|
|
843
|
+
npmInstallGlobal: (version) => runNpmInstallGlobal(PACKAGE_NAME, version),
|
|
844
|
+
runInstall: (options) => install(options)
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
async function update(options, deps = {}) {
|
|
848
|
+
const resolved = { ...createDefaultDeps3(), ...deps };
|
|
849
|
+
let latest;
|
|
850
|
+
try {
|
|
851
|
+
latest = await resolved.latestVersion();
|
|
852
|
+
} catch (err) {
|
|
853
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
854
|
+
console.error(`Failed to query npm registry: ${message}`);
|
|
855
|
+
return 1;
|
|
532
856
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
857
|
+
const current = resolved.currentVersion();
|
|
858
|
+
if (current !== void 0) {
|
|
859
|
+
const comparison = compareVersions(current, latest);
|
|
860
|
+
if (comparison !== void 0 ? comparison > 0 : false) {
|
|
861
|
+
console.log(
|
|
862
|
+
`Lincoln ${current} is ahead of the latest release (${latest}); nothing to do.`
|
|
863
|
+
);
|
|
864
|
+
return 0;
|
|
536
865
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
return
|
|
866
|
+
if (comparison !== void 0 ? comparison === 0 : current === latest) {
|
|
867
|
+
console.log(`Lincoln ${current} is already up to date.`);
|
|
868
|
+
return 0;
|
|
540
869
|
}
|
|
541
|
-
this.child.kill(signal);
|
|
542
|
-
const timeout = setTimeout(() => {
|
|
543
|
-
if (!this.child.killed) {
|
|
544
|
-
this.child.kill("SIGKILL");
|
|
545
|
-
}
|
|
546
|
-
}, 5e3);
|
|
547
|
-
this.exitPromise.finally(() => clearTimeout(timeout));
|
|
548
|
-
return this.exitPromise;
|
|
549
870
|
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
if (
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
871
|
+
const summary = `${current ?? "unknown"} -> ${latest}`;
|
|
872
|
+
if (options.check) {
|
|
873
|
+
console.log(`Lincoln update available: ${summary}`);
|
|
874
|
+
return 0;
|
|
875
|
+
}
|
|
876
|
+
if (options.dryRun) {
|
|
877
|
+
console.log(`Dry run: would update Lincoln ${summary}`);
|
|
878
|
+
return 0;
|
|
879
|
+
}
|
|
880
|
+
if (!options.yes) {
|
|
881
|
+
console.error(`Will update Lincoln ${summary}. Run with --yes to proceed.`);
|
|
882
|
+
return 1;
|
|
883
|
+
}
|
|
884
|
+
const installCode = await resolved.npmInstallGlobal(latest);
|
|
885
|
+
if (installCode !== 0) {
|
|
886
|
+
console.error(`npm install -g ${PACKAGE_NAME}@${latest} failed with exit code ${installCode}`);
|
|
887
|
+
return 1;
|
|
888
|
+
}
|
|
889
|
+
const syncCode = await resolved.runInstall(defaultInstallOptions());
|
|
890
|
+
if (syncCode !== 0) {
|
|
891
|
+
console.error(`lincoln install failed with exit code ${syncCode}`);
|
|
892
|
+
return 1;
|
|
893
|
+
}
|
|
894
|
+
console.log(`Updated Lincoln to ${latest}`);
|
|
895
|
+
return 0;
|
|
896
|
+
}
|
|
897
|
+
function defaultInstallOptions() {
|
|
898
|
+
return { yes: true, dryRun: false, force: false, harnesses: [], noVenv: true };
|
|
899
|
+
}
|
|
900
|
+
function runNpmInstallGlobal(packageName, version) {
|
|
901
|
+
return new Promise((resolvePromise) => {
|
|
902
|
+
const child = spawn3("npm", ["install", "-g", `${packageName}@${version}`], {
|
|
903
|
+
stdio: "inherit",
|
|
904
|
+
shell: process.platform === "win32"
|
|
905
|
+
});
|
|
906
|
+
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
907
|
+
child.on("error", () => resolvePromise(1));
|
|
575
908
|
});
|
|
576
|
-
return new RecorderProcessImpl(child);
|
|
577
909
|
}
|
|
578
910
|
|
|
579
|
-
// src/
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
errorMessage: null
|
|
597
|
-
});
|
|
598
|
-
const recorderRef = useRef(null);
|
|
599
|
-
const intervalRef = useRef(null);
|
|
600
|
-
const durationRef = useRef(0);
|
|
601
|
-
const terminatingRef = useRef(false);
|
|
602
|
-
const clearRecordingInterval = useCallback(() => {
|
|
603
|
-
if (intervalRef.current) {
|
|
604
|
-
clearInterval(intervalRef.current);
|
|
605
|
-
intervalRef.current = null;
|
|
606
|
-
}
|
|
607
|
-
}, []);
|
|
608
|
-
const start = useCallback(() => {
|
|
609
|
-
if (recorderRef.current) {
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
terminatingRef.current = false;
|
|
613
|
-
setState({ status: "recording", duration: 0, amplitude: 0.3, errorMessage: null });
|
|
614
|
-
durationRef.current = 0;
|
|
615
|
-
try {
|
|
616
|
-
const recorder = spawnRecorder({
|
|
617
|
-
workspaceRoot,
|
|
618
|
-
sessionId,
|
|
619
|
-
lincolnRecordPath,
|
|
620
|
-
mic,
|
|
621
|
-
model
|
|
622
|
-
});
|
|
623
|
-
recorderRef.current = recorder;
|
|
624
|
-
recorder.on("ready", () => {
|
|
625
|
-
});
|
|
626
|
-
recorder.on("error", (error) => {
|
|
627
|
-
setState((s) => ({ ...s, status: "error", errorMessage: error.message }));
|
|
628
|
-
clearRecordingInterval();
|
|
629
|
-
});
|
|
630
|
-
recorder.on("exit", (code, signal) => {
|
|
631
|
-
recorderRef.current = null;
|
|
632
|
-
clearRecordingInterval();
|
|
633
|
-
if (terminatingRef.current) {
|
|
634
|
-
return;
|
|
635
|
-
}
|
|
636
|
-
const reason = code !== null && code !== void 0 ? `lincoln-record exited unexpectedly with code ${code}` : `lincoln-record exited unexpectedly with signal ${signal}`;
|
|
637
|
-
setState((s) => ({ ...s, status: "error", errorMessage: reason }));
|
|
638
|
-
});
|
|
639
|
-
intervalRef.current = setInterval(() => {
|
|
640
|
-
durationRef.current += 1;
|
|
641
|
-
setState((s) => ({
|
|
642
|
-
...s,
|
|
643
|
-
duration: durationRef.current,
|
|
644
|
-
amplitude: mockAmplitude(durationRef.current)
|
|
645
|
-
}));
|
|
646
|
-
}, 1e3);
|
|
647
|
-
} catch (error) {
|
|
648
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
649
|
-
setState((s) => ({ ...s, status: "error", errorMessage: message }));
|
|
650
|
-
}
|
|
651
|
-
}, [workspaceRoot, sessionId, lincolnRecordPath, mic, model, clearRecordingInterval]);
|
|
652
|
-
const stop = useCallback(async () => {
|
|
653
|
-
const recorder = recorderRef.current;
|
|
654
|
-
if (!recorder) return;
|
|
655
|
-
terminatingRef.current = true;
|
|
656
|
-
clearRecordingInterval();
|
|
657
|
-
setState((s) => ({ ...s, status: "stopped" }));
|
|
658
|
-
await recorder.stop();
|
|
659
|
-
}, [clearRecordingInterval]);
|
|
660
|
-
const cancel = useCallback(async () => {
|
|
661
|
-
const recorder = recorderRef.current;
|
|
662
|
-
if (!recorder) return;
|
|
663
|
-
terminatingRef.current = true;
|
|
664
|
-
clearRecordingInterval();
|
|
665
|
-
setState((s) => ({ ...s, status: "cancelled" }));
|
|
666
|
-
await recorder.cancel();
|
|
667
|
-
}, [clearRecordingInterval]);
|
|
668
|
-
useEffect3(() => {
|
|
669
|
-
if (startOnMount) {
|
|
670
|
-
start();
|
|
671
|
-
}
|
|
672
|
-
return () => {
|
|
673
|
-
clearRecordingInterval();
|
|
674
|
-
if (recorderRef.current) {
|
|
675
|
-
recorderRef.current.cancel().catch(() => {
|
|
676
|
-
});
|
|
677
|
-
recorderRef.current = null;
|
|
911
|
+
// src/commands/use.ts
|
|
912
|
+
import fs8 from "fs";
|
|
913
|
+
import path9 from "path";
|
|
914
|
+
import { spawn as spawn4 } from "child_process";
|
|
915
|
+
var PACKAGE_NAME2 = "@sushanglewis/lincoln";
|
|
916
|
+
var SEMVER_REGEX = /^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
917
|
+
var STRICT_SEMVER_REGEX = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
918
|
+
var DIST_TAG_REGEX = /^[a-zA-Z][a-zA-Z0-9._-]*$/;
|
|
919
|
+
function createDefaultDeps4() {
|
|
920
|
+
const paths = resolveLincolnPaths();
|
|
921
|
+
const registry = createRegistryClient();
|
|
922
|
+
return {
|
|
923
|
+
paths,
|
|
924
|
+
resolveVersion: async (spec) => {
|
|
925
|
+
const normalized = spec.startsWith("v") ? spec.slice(1) : spec;
|
|
926
|
+
if (STRICT_SEMVER_REGEX.test(normalized)) {
|
|
927
|
+
return normalized;
|
|
678
928
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
929
|
+
return registry.resolveVersion(PACKAGE_NAME2, spec);
|
|
930
|
+
},
|
|
931
|
+
ensureVersionAvailable: async (version) => {
|
|
932
|
+
const code = await runNpmInstallGlobal2(PACKAGE_NAME2, version);
|
|
933
|
+
if (code !== 0) {
|
|
934
|
+
throw new Error(`npm install -g ${PACKAGE_NAME2}@${version} exited with ${code}`);
|
|
935
|
+
}
|
|
936
|
+
},
|
|
937
|
+
npmGlobalRoot: () => runNpmRootGlobal(),
|
|
938
|
+
runInstall: (options) => install(options)
|
|
939
|
+
};
|
|
682
940
|
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
941
|
+
async function use(spec, options, deps = {}) {
|
|
942
|
+
if (!isValidVersion(spec)) {
|
|
943
|
+
console.error(`Invalid version: ${spec}`);
|
|
944
|
+
return 1;
|
|
945
|
+
}
|
|
946
|
+
const resolved = { ...createDefaultDeps4(), ...deps };
|
|
947
|
+
let version;
|
|
948
|
+
try {
|
|
949
|
+
version = await resolved.resolveVersion(spec);
|
|
950
|
+
} catch (err) {
|
|
951
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
952
|
+
console.error(`Failed to resolve version ${spec}: ${message}`);
|
|
953
|
+
return 1;
|
|
954
|
+
}
|
|
955
|
+
const versionDir = path9.join(resolved.paths.versionsDir, version);
|
|
956
|
+
const alreadyInstalled = fs8.existsSync(versionDir);
|
|
957
|
+
if (options.dryRun) {
|
|
958
|
+
if (alreadyInstalled) {
|
|
959
|
+
console.log(`Dry run: would switch ${resolved.paths.currentDir} to ${versionDir}`);
|
|
960
|
+
} else {
|
|
961
|
+
console.log(
|
|
962
|
+
`Dry run: would install ${PACKAGE_NAME2}@${version} globally, then switch ${resolved.paths.currentDir} to ${versionDir}`
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
return 0;
|
|
966
|
+
}
|
|
967
|
+
if (!options.yes) {
|
|
968
|
+
console.error(`Will switch Lincoln to ${version}. Run with --yes to proceed.`);
|
|
969
|
+
return 1;
|
|
970
|
+
}
|
|
971
|
+
if (!alreadyInstalled) {
|
|
972
|
+
try {
|
|
973
|
+
await resolved.ensureVersionAvailable(version);
|
|
974
|
+
} catch (err) {
|
|
975
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
976
|
+
console.error(`Failed to install ${PACKAGE_NAME2}@${version}: ${message}`);
|
|
977
|
+
return 1;
|
|
978
|
+
}
|
|
979
|
+
if (!fs8.existsSync(versionDir)) {
|
|
980
|
+
try {
|
|
981
|
+
await copyVersionFromNpmGlobal(resolved, versionDir);
|
|
982
|
+
} catch (err) {
|
|
983
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
984
|
+
console.error(`Failed to populate ${versionDir}: ${message}`);
|
|
985
|
+
return 1;
|
|
986
|
+
}
|
|
699
987
|
}
|
|
700
|
-
|
|
988
|
+
if (!fs8.existsSync(versionDir)) {
|
|
989
|
+
console.error(
|
|
990
|
+
`Provisioning ${PACKAGE_NAME2}@${version} did not produce ${versionDir}; cannot switch versions.`
|
|
991
|
+
);
|
|
992
|
+
return 1;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
try {
|
|
996
|
+
switchCurrentLink(resolved.paths, versionDir);
|
|
997
|
+
} catch (err) {
|
|
998
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
999
|
+
console.error(`Failed to switch ${resolved.paths.currentDir}: ${message}`);
|
|
1000
|
+
return 1;
|
|
1001
|
+
}
|
|
1002
|
+
const syncCode = await resolved.runInstall(defaultInstallOptions2());
|
|
1003
|
+
if (syncCode !== 0) {
|
|
1004
|
+
console.error(`lincoln install failed with exit code ${syncCode}`);
|
|
1005
|
+
return 1;
|
|
1006
|
+
}
|
|
1007
|
+
try {
|
|
1008
|
+
switchCurrentLink(resolved.paths, versionDir);
|
|
1009
|
+
} catch (err) {
|
|
1010
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1011
|
+
console.error(`Failed to switch ${resolved.paths.currentDir}: ${message}`);
|
|
1012
|
+
return 1;
|
|
701
1013
|
}
|
|
702
|
-
|
|
1014
|
+
console.log(`Switched Lincoln to ${version}`);
|
|
1015
|
+
return 0;
|
|
703
1016
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
var execFileAsync = promisify(execFile);
|
|
707
|
-
async function listDevices(lincolnRecordPath = "lincoln-record") {
|
|
708
|
-
const { stdout } = await execFileAsync(lincolnRecordPath, ["devices"]);
|
|
709
|
-
return parseDevicesOutput(stdout);
|
|
1017
|
+
function isValidVersion(version) {
|
|
1018
|
+
return SEMVER_REGEX.test(version) || DIST_TAG_REGEX.test(version);
|
|
710
1019
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1020
|
+
async function copyVersionFromNpmGlobal(deps, versionDir) {
|
|
1021
|
+
const globalRoot = await deps.npmGlobalRoot();
|
|
1022
|
+
if (!globalRoot) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
const packageRoot = path9.join(globalRoot, ...PACKAGE_NAME2.split("/"));
|
|
1026
|
+
if (!fs8.existsSync(packageRoot)) {
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
fs8.mkdirSync(path9.dirname(versionDir), { recursive: true });
|
|
1030
|
+
fs8.cpSync(packageRoot, versionDir, { recursive: true });
|
|
1031
|
+
}
|
|
1032
|
+
function switchCurrentLink(paths, versionDir) {
|
|
1033
|
+
fs8.mkdirSync(paths.lincolnHome, { recursive: true });
|
|
1034
|
+
try {
|
|
1035
|
+
fs8.rmSync(paths.currentDir, { recursive: true, force: true });
|
|
1036
|
+
fs8.symlinkSync(versionDir, paths.currentDir);
|
|
1037
|
+
} catch {
|
|
1038
|
+
fs8.rmSync(paths.currentDir, { recursive: true, force: true });
|
|
1039
|
+
fs8.cpSync(versionDir, paths.currentDir, { recursive: true, force: true });
|
|
1040
|
+
}
|
|
728
1041
|
}
|
|
729
|
-
function
|
|
730
|
-
return
|
|
1042
|
+
function defaultInstallOptions2() {
|
|
1043
|
+
return { yes: true, dryRun: false, force: false, harnesses: [], noVenv: true };
|
|
731
1044
|
}
|
|
732
|
-
function
|
|
733
|
-
return
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
1045
|
+
function runNpmInstallGlobal2(packageName, version) {
|
|
1046
|
+
return new Promise((resolvePromise) => {
|
|
1047
|
+
const child = spawn4("npm", ["install", "-g", `${packageName}@${version}`], {
|
|
1048
|
+
stdio: "inherit",
|
|
1049
|
+
shell: process.platform === "win32"
|
|
1050
|
+
});
|
|
1051
|
+
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
1052
|
+
child.on("error", () => resolvePromise(1));
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
function runNpmRootGlobal() {
|
|
1056
|
+
return new Promise((resolvePromise) => {
|
|
1057
|
+
const child = spawn4("npm", ["root", "-g"], {
|
|
1058
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1059
|
+
shell: process.platform === "win32"
|
|
1060
|
+
});
|
|
1061
|
+
let stdout = "";
|
|
1062
|
+
child.stdout?.on("data", (chunk) => {
|
|
1063
|
+
stdout += chunk.toString();
|
|
1064
|
+
});
|
|
1065
|
+
child.on("close", (code) => {
|
|
1066
|
+
const root = stdout.trim();
|
|
1067
|
+
resolvePromise(code === 0 && root.length > 0 ? root : void 0);
|
|
1068
|
+
});
|
|
1069
|
+
child.on("error", () => resolvePromise(void 0));
|
|
1070
|
+
});
|
|
737
1071
|
}
|
|
738
1072
|
|
|
739
|
-
// src/
|
|
740
|
-
import
|
|
1073
|
+
// src/commands/migrateProject.ts
|
|
1074
|
+
import fs10 from "fs";
|
|
1075
|
+
import path11 from "path";
|
|
741
1076
|
|
|
742
|
-
// src/
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
1077
|
+
// src/lib/projectFiles.ts
|
|
1078
|
+
import fs9 from "fs";
|
|
1079
|
+
import path10 from "path";
|
|
1080
|
+
import crypto2 from "crypto";
|
|
1081
|
+
var FRAMEWORK_ALLOWLIST_DIRS = [".claude", ".claude-plugin", "scripts", "tools"];
|
|
1082
|
+
var FRAMEWORK_ALLOWLIST_FILES = [
|
|
1083
|
+
"README.md",
|
|
1084
|
+
"README.en.md",
|
|
1085
|
+
"USAGE.md",
|
|
1086
|
+
"CONTRIBUTING.md",
|
|
1087
|
+
"CLAUDE.md",
|
|
1088
|
+
"LICENSE",
|
|
1089
|
+
"RELEASE.md",
|
|
1090
|
+
".version-bump.json",
|
|
1091
|
+
"requirements.txt",
|
|
1092
|
+
"SKILL.md"
|
|
1093
|
+
];
|
|
1094
|
+
var FRAMEWORK_DENYLIST_NAMES = /* @__PURE__ */ new Set([
|
|
1095
|
+
".git",
|
|
1096
|
+
".context",
|
|
1097
|
+
".venv",
|
|
1098
|
+
"venv",
|
|
1099
|
+
"dist",
|
|
1100
|
+
"oss",
|
|
1101
|
+
".pytest_cache",
|
|
1102
|
+
"__pycache__",
|
|
1103
|
+
".DS_Store",
|
|
1104
|
+
"node_modules"
|
|
1105
|
+
]);
|
|
1106
|
+
var FRAMEWORK_DENYLIST_PREFIXES = ["issue-"];
|
|
1107
|
+
var FRAMEWORK_SKIP_PATHS = /* @__PURE__ */ new Set([
|
|
1108
|
+
".claude/templates/issue-package",
|
|
1109
|
+
"tools/lincoln-installer/dist",
|
|
1110
|
+
"tools/lincoln-installer/node_modules",
|
|
1111
|
+
"tools/lincoln-installer/coverage"
|
|
1112
|
+
]);
|
|
1113
|
+
function sha2562(filePath) {
|
|
1114
|
+
return crypto2.createHash("sha256").update(fs9.readFileSync(filePath)).digest("hex");
|
|
1115
|
+
}
|
|
1116
|
+
function isDenied(relativePath) {
|
|
1117
|
+
const parts = relativePath.split(path10.sep);
|
|
1118
|
+
for (const part of parts) {
|
|
1119
|
+
if (FRAMEWORK_DENYLIST_NAMES.has(part)) return true;
|
|
1120
|
+
for (const prefix of FRAMEWORK_DENYLIST_PREFIXES) {
|
|
1121
|
+
if (part.startsWith(prefix)) return true;
|
|
1122
|
+
}
|
|
753
1123
|
}
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
return {
|
|
757
|
-
downloaded: Number(withoutTotal[1]),
|
|
758
|
-
total: null,
|
|
759
|
-
percent: null
|
|
760
|
-
};
|
|
1124
|
+
for (const skip of FRAMEWORK_SKIP_PATHS) {
|
|
1125
|
+
if (relativePath === skip || relativePath.startsWith(skip + path10.sep)) return true;
|
|
761
1126
|
}
|
|
762
|
-
return
|
|
1127
|
+
return false;
|
|
763
1128
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
return
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1129
|
+
function isAllowlisted(relativePath) {
|
|
1130
|
+
if (FRAMEWORK_ALLOWLIST_FILES.includes(relativePath)) return true;
|
|
1131
|
+
for (const dir of FRAMEWORK_ALLOWLIST_DIRS) {
|
|
1132
|
+
if (relativePath === dir || relativePath.startsWith(dir + path10.sep)) return true;
|
|
1133
|
+
}
|
|
1134
|
+
return false;
|
|
1135
|
+
}
|
|
1136
|
+
function isPreservedDir(relativePath) {
|
|
1137
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
1138
|
+
if (normalized === ".context" || normalized.startsWith(".context/")) return true;
|
|
1139
|
+
const parts = normalized.split("/");
|
|
1140
|
+
for (const part of parts) {
|
|
1141
|
+
if (part.startsWith("issue-")) return true;
|
|
1142
|
+
}
|
|
1143
|
+
return false;
|
|
1144
|
+
}
|
|
1145
|
+
function isPreserved(relativePath) {
|
|
1146
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
1147
|
+
if (normalized === ".github/openspec-config.yml") return true;
|
|
1148
|
+
return isPreservedDir(relativePath);
|
|
1149
|
+
}
|
|
1150
|
+
function listVendoredFrameworkFiles(payloadRoot, projectRoot) {
|
|
1151
|
+
const report = { removable: [], modified: [], preserved: [] };
|
|
1152
|
+
function walk(dir) {
|
|
1153
|
+
const entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
1154
|
+
for (const entry of entries) {
|
|
1155
|
+
const fullPath = path10.join(dir, entry.name);
|
|
1156
|
+
const relativePath = path10.relative(projectRoot, fullPath);
|
|
1157
|
+
if (entry.isDirectory()) {
|
|
1158
|
+
if (isPreservedDir(relativePath)) {
|
|
1159
|
+
walk(fullPath);
|
|
1160
|
+
} else if (!isDenied(relativePath)) {
|
|
1161
|
+
walk(fullPath);
|
|
1162
|
+
}
|
|
1163
|
+
continue;
|
|
778
1164
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
if (progress) {
|
|
783
|
-
onProgress?.(progress);
|
|
1165
|
+
if (isPreserved(relativePath)) {
|
|
1166
|
+
report.preserved.push(relativePath);
|
|
1167
|
+
continue;
|
|
784
1168
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
if (
|
|
789
|
-
|
|
1169
|
+
if (isDenied(relativePath)) continue;
|
|
1170
|
+
if (!isAllowlisted(relativePath)) continue;
|
|
1171
|
+
const payloadFile = path10.join(payloadRoot, relativePath);
|
|
1172
|
+
if (!fs9.existsSync(payloadFile)) {
|
|
1173
|
+
report.modified.push(relativePath);
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
if (sha2562(fullPath) === sha2562(payloadFile)) {
|
|
1177
|
+
report.removable.push(relativePath);
|
|
790
1178
|
} else {
|
|
791
|
-
|
|
1179
|
+
report.modified.push(relativePath);
|
|
792
1180
|
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
if (fs9.existsSync(projectRoot)) {
|
|
1184
|
+
walk(projectRoot);
|
|
1185
|
+
}
|
|
1186
|
+
return report;
|
|
795
1187
|
}
|
|
796
1188
|
|
|
797
|
-
// src/
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
const handleQuit = useCallback2(() => {
|
|
848
|
-
exit();
|
|
849
|
-
}, [exit]);
|
|
850
|
-
const handleRecord = useCallback2(() => {
|
|
851
|
-
if (state.status === "idle") {
|
|
852
|
-
start();
|
|
853
|
-
}
|
|
854
|
-
}, [state.status, start]);
|
|
855
|
-
const handleStop = useCallback2(() => {
|
|
856
|
-
if (state.status === "recording") {
|
|
857
|
-
stop().catch(() => {
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
}, [state.status, stop]);
|
|
861
|
-
const handleCancel = useCallback2(() => {
|
|
862
|
-
if (state.status === "recording") {
|
|
863
|
-
cancel().catch(() => {
|
|
864
|
-
});
|
|
865
|
-
}
|
|
866
|
-
}, [state.status, cancel]);
|
|
867
|
-
const handleDevices = useCallback2(() => {
|
|
868
|
-
if (state.status === "idle") {
|
|
869
|
-
setMode("devices");
|
|
870
|
-
}
|
|
871
|
-
}, [state.status]);
|
|
872
|
-
const handleModel = useCallback2(() => {
|
|
873
|
-
if (state.status === "idle") {
|
|
874
|
-
setMode("model");
|
|
875
|
-
}
|
|
876
|
-
}, [state.status]);
|
|
877
|
-
const handleDeviceSelect = useCallback2(
|
|
878
|
-
(device) => {
|
|
879
|
-
setMic(device);
|
|
880
|
-
addLog(`Input device: ${device}`, "success");
|
|
881
|
-
setMode("main");
|
|
882
|
-
},
|
|
883
|
-
[addLog]
|
|
884
|
-
);
|
|
885
|
-
const handleModelSelect = useCallback2(
|
|
886
|
-
(name) => {
|
|
887
|
-
setModel(name);
|
|
888
|
-
addLog(`Model: ${name}`, "success");
|
|
889
|
-
setMode("main");
|
|
890
|
-
},
|
|
891
|
-
[addLog]
|
|
892
|
-
);
|
|
893
|
-
const handleMenuClose = useCallback2(() => {
|
|
894
|
-
setMode("main");
|
|
895
|
-
}, []);
|
|
896
|
-
const isTerminal = state.status === "stopped" || state.status === "cancelled" || state.status === "error";
|
|
897
|
-
useKeyHandler({
|
|
898
|
-
enabled: mode === "main",
|
|
899
|
-
onRecord: handleRecord,
|
|
900
|
-
onStop: handleStop,
|
|
901
|
-
onCancel: handleCancel,
|
|
902
|
-
onQuit: handleQuit,
|
|
903
|
-
onDevices: handleDevices,
|
|
904
|
-
onModel: handleModel,
|
|
905
|
-
onAnyKey: isTerminal ? handleQuit : void 0
|
|
906
|
-
});
|
|
907
|
-
const hintMode = useMemo(() => {
|
|
908
|
-
if (mode !== "main") return "menu";
|
|
909
|
-
if (state.status === "idle") return "idle";
|
|
910
|
-
if (state.status === "recording") return "recording";
|
|
911
|
-
if (state.status === "stopped") return "stopped";
|
|
912
|
-
if (state.status === "cancelled") return "cancelled";
|
|
913
|
-
return "error";
|
|
914
|
-
}, [mode, state.status]);
|
|
915
|
-
const devicesLoader = useCallback2(
|
|
916
|
-
() => (listDevicesFn ?? (() => listDevices(lincolnRecordPath)))(),
|
|
917
|
-
[listDevicesFn, lincolnRecordPath]
|
|
918
|
-
);
|
|
919
|
-
const modelsLoader = useCallback2(
|
|
920
|
-
() => (listModelStatusesFn ?? (() => Promise.resolve(listModelStatuses(defaultModelCacheDir()))))(),
|
|
921
|
-
[listModelStatusesFn]
|
|
922
|
-
);
|
|
923
|
-
const warmupRunner = useCallback2(
|
|
924
|
-
(name, onProgress) => runWarmupFn ? runWarmupFn(name, onProgress) : runWarmup({ model: name, lincolnRecordPath, onProgress }),
|
|
925
|
-
[runWarmupFn, lincolnRecordPath]
|
|
926
|
-
);
|
|
927
|
-
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "gray", height: 24, children: [
|
|
928
|
-
/* @__PURE__ */ jsx7(
|
|
929
|
-
StatusPanel,
|
|
930
|
-
{
|
|
931
|
-
sessionId,
|
|
932
|
-
topic,
|
|
933
|
-
designId,
|
|
934
|
-
branch,
|
|
935
|
-
status: state.status,
|
|
936
|
-
duration: state.duration
|
|
937
|
-
}
|
|
938
|
-
),
|
|
939
|
-
mode === "devices" && /* @__PURE__ */ jsx7(
|
|
940
|
-
DevicesMenu,
|
|
941
|
-
{
|
|
942
|
-
listDevicesFn: devicesLoader,
|
|
943
|
-
onSelect: handleDeviceSelect,
|
|
944
|
-
onClose: handleMenuClose
|
|
1189
|
+
// src/commands/migrateProject.ts
|
|
1190
|
+
function createDefaultDeps5() {
|
|
1191
|
+
return {
|
|
1192
|
+
paths: resolveLincolnPaths(),
|
|
1193
|
+
listVendoredFrameworkFiles,
|
|
1194
|
+
writeProjectMarker
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
async function migrateProject(projectRoot, options = {}, deps = createDefaultDeps5()) {
|
|
1198
|
+
const payloadRoot = deps.paths.currentDir;
|
|
1199
|
+
if (!fs10.existsSync(payloadRoot)) {
|
|
1200
|
+
console.error(`Lincoln payload not found at ${payloadRoot}. Run "lincoln install" first.`);
|
|
1201
|
+
return 1;
|
|
1202
|
+
}
|
|
1203
|
+
const absoluteProjectRoot = path11.resolve(projectRoot);
|
|
1204
|
+
const report = deps.listVendoredFrameworkFiles(payloadRoot, absoluteProjectRoot);
|
|
1205
|
+
if (options.dryRun) {
|
|
1206
|
+
console.log(`Dry run: would migrate ${absoluteProjectRoot}`);
|
|
1207
|
+
if (report.removable.length > 0) {
|
|
1208
|
+
console.log("Would remove unmodified framework files:");
|
|
1209
|
+
for (const f of report.removable) console.log(` - ${f}`);
|
|
1210
|
+
}
|
|
1211
|
+
if (report.modified.length > 0) {
|
|
1212
|
+
console.log("Would preserve modified framework files:");
|
|
1213
|
+
for (const f of report.modified) console.log(` - ${f}`);
|
|
1214
|
+
}
|
|
1215
|
+
if (report.preserved.length > 0) {
|
|
1216
|
+
console.log("Would preserve project-local files:");
|
|
1217
|
+
for (const f of report.preserved) console.log(` - ${f}`);
|
|
1218
|
+
}
|
|
1219
|
+
console.log("Would create .lincoln.yaml");
|
|
1220
|
+
return 0;
|
|
1221
|
+
}
|
|
1222
|
+
if (!options.yes) {
|
|
1223
|
+
console.error("This will remove vendored framework files. Run with --yes to proceed.");
|
|
1224
|
+
return 1;
|
|
1225
|
+
}
|
|
1226
|
+
for (const file of report.removable) {
|
|
1227
|
+
const filePath = path11.join(absoluteProjectRoot, file);
|
|
1228
|
+
try {
|
|
1229
|
+
fs10.rmSync(filePath);
|
|
1230
|
+
let dir = path11.dirname(filePath);
|
|
1231
|
+
while (dir !== absoluteProjectRoot && fs10.existsSync(dir)) {
|
|
1232
|
+
const entries = fs10.readdirSync(dir);
|
|
1233
|
+
if (entries.length === 0) {
|
|
1234
|
+
fs10.rmdirSync(dir);
|
|
1235
|
+
dir = path11.dirname(dir);
|
|
1236
|
+
} else {
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
945
1239
|
}
|
|
946
|
-
)
|
|
947
|
-
|
|
948
|
-
|
|
1240
|
+
} catch (err) {
|
|
1241
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1242
|
+
console.error(`Failed to remove ${file}: ${message}`);
|
|
1243
|
+
return 1;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (report.modified.length > 0) {
|
|
1247
|
+
console.log("Preserved modified framework files:");
|
|
1248
|
+
for (const f of report.modified) console.log(` - ${f}`);
|
|
1249
|
+
}
|
|
1250
|
+
if (report.preserved.length > 0) {
|
|
1251
|
+
console.log("Preserved project-local files:");
|
|
1252
|
+
for (const f of report.preserved) console.log(` - ${f}`);
|
|
1253
|
+
}
|
|
1254
|
+
try {
|
|
1255
|
+
deps.writeProjectMarker(
|
|
1256
|
+
absoluteProjectRoot,
|
|
949
1257
|
{
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
}
|
|
955
|
-
)
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1258
|
+
enabled: true,
|
|
1259
|
+
workflow_template: "interview-to-knowledge",
|
|
1260
|
+
min_lincoln_version: readLocalPackageVersion() ?? "1.5.0"
|
|
1261
|
+
},
|
|
1262
|
+
{ force: options.force }
|
|
1263
|
+
);
|
|
1264
|
+
} catch (err) {
|
|
1265
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1266
|
+
console.error(`Failed to write .lincoln.yaml: ${message}`);
|
|
1267
|
+
return 1;
|
|
1268
|
+
}
|
|
1269
|
+
console.log(`Migrated project at ${absoluteProjectRoot}`);
|
|
1270
|
+
console.log(`Removed ${report.removable.length} unmodified framework files`);
|
|
1271
|
+
return 0;
|
|
960
1272
|
}
|
|
961
1273
|
|
|
962
|
-
// src/
|
|
963
|
-
import {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
/* @__PURE__ */ jsx8(Text7, { bold: true, children: "lincoln" }),
|
|
968
|
-
/* @__PURE__ */ jsx8(Text7, { children: "Cross-tool TUI for Lincoln interview recording." }),
|
|
969
|
-
/* @__PURE__ */ jsx8(Text7, {}),
|
|
970
|
-
/* @__PURE__ */ jsx8(Text7, { bold: true, children: "Usage:" }),
|
|
971
|
-
/* @__PURE__ */ jsx8(Text7, { children: " lincoln [options]" }),
|
|
972
|
-
/* @__PURE__ */ jsx8(Text7, {}),
|
|
973
|
-
/* @__PURE__ */ jsx8(Text7, { bold: true, children: "Options:" }),
|
|
974
|
-
/* @__PURE__ */ jsx8(Text7, { children: " --topic Interview topic" }),
|
|
975
|
-
/* @__PURE__ */ jsx8(Text7, { children: " --design-id Design ID for the session" }),
|
|
976
|
-
/* @__PURE__ */ jsx8(Text7, { children: " --branch Current branch name" }),
|
|
977
|
-
/* @__PURE__ */ jsx8(Text7, { children: " --session-id Explicit session ID" }),
|
|
978
|
-
/* @__PURE__ */ jsx8(Text7, { children: " --no-tui Run without the terminal UI" }),
|
|
979
|
-
/* @__PURE__ */ jsx8(Text7, { children: " --help, -h Show this help message" }),
|
|
980
|
-
/* @__PURE__ */ jsx8(Text7, {}),
|
|
981
|
-
/* @__PURE__ */ jsx8(Text7, { dimColor: true, children: "Configuration files: ~/.lincolnrc, ./.lincolnrc" })
|
|
982
|
-
] });
|
|
983
|
-
}
|
|
984
|
-
return /* @__PURE__ */ jsx8(
|
|
985
|
-
RecordingApp,
|
|
986
|
-
{
|
|
987
|
-
workspaceRoot: config.workspaceRoot,
|
|
988
|
-
sessionId: config.sessionId,
|
|
989
|
-
topic: config.topic,
|
|
990
|
-
designId: config.designId,
|
|
991
|
-
branch: config.branch,
|
|
992
|
-
audioMeterStyle: config.audioMeterStyle
|
|
993
|
-
}
|
|
994
|
-
);
|
|
1274
|
+
// src/commands/record.ts
|
|
1275
|
+
import { spawn as spawn5 } from "child_process";
|
|
1276
|
+
import { EventEmitter } from "events";
|
|
1277
|
+
function createDefaultDeps6() {
|
|
1278
|
+
return { spawn: spawn5 };
|
|
995
1279
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1280
|
+
function record(args, deps = createDefaultDeps6()) {
|
|
1281
|
+
return new Promise((resolve) => {
|
|
1282
|
+
const child = deps.spawn("lincoln-record", args, { stdio: "inherit" });
|
|
1283
|
+
child.on("error", (err) => {
|
|
1284
|
+
console.error(`Failed to start lincoln-record: ${err.message}`);
|
|
1285
|
+
resolve(1);
|
|
1286
|
+
});
|
|
1287
|
+
child.on("close", (code) => {
|
|
1288
|
+
resolve(code ?? 0);
|
|
1289
|
+
});
|
|
1290
|
+
});
|
|
1005
1291
|
}
|
|
1006
1292
|
|
|
1007
|
-
// src/main.
|
|
1008
|
-
|
|
1293
|
+
// src/main.ts
|
|
1294
|
+
var USAGE = `Lincoln \u2014 Global agent harness plugin CLI
|
|
1295
|
+
|
|
1296
|
+
Usage:
|
|
1297
|
+
lincoln <command> [options]
|
|
1298
|
+
|
|
1299
|
+
Commands:
|
|
1300
|
+
install One-time global setup: sync to ~/.claude/, ~/.codex/, ~/.opencode/
|
|
1301
|
+
update Pull latest release and re-sync globally
|
|
1302
|
+
use <version> Switch active global version
|
|
1303
|
+
doctor Diagnose harness integration
|
|
1304
|
+
init-project Create .lincoln.yaml in current project
|
|
1305
|
+
migrate-project Remove vendored framework files from an existing project
|
|
1306
|
+
record Launch the Lincoln interview recorder TUI
|
|
1307
|
+
help Show this help message
|
|
1308
|
+
|
|
1309
|
+
Options:
|
|
1310
|
+
--yes, -y Skip confirmation prompts
|
|
1311
|
+
--dry-run Show what would be done without making changes
|
|
1312
|
+
--force Force re-install even if up to date
|
|
1313
|
+
--check Check for available updates without installing (update)
|
|
1314
|
+
--json Output machine-readable JSON (where supported)
|
|
1315
|
+
--help, -h Show this help message
|
|
1316
|
+
`;
|
|
1317
|
+
async function main(argv) {
|
|
1318
|
+
const parsed = parseArgs(argv);
|
|
1319
|
+
if (parsed.command === "help") {
|
|
1320
|
+
console.log(USAGE);
|
|
1321
|
+
return 0;
|
|
1322
|
+
}
|
|
1323
|
+
if (parsed.command === "install") {
|
|
1324
|
+
return install({
|
|
1325
|
+
yes: Boolean(parsed.flags.yes || parsed.flags.y),
|
|
1326
|
+
dryRun: Boolean(parsed.flags["dry-run"]),
|
|
1327
|
+
force: Boolean(parsed.flags.force),
|
|
1328
|
+
harnesses: parsed.args,
|
|
1329
|
+
noVenv: Boolean(parsed.flags["no-venv"])
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
if (parsed.command === "update") {
|
|
1333
|
+
return update({
|
|
1334
|
+
check: Boolean(parsed.flags.check),
|
|
1335
|
+
dryRun: Boolean(parsed.flags["dry-run"]),
|
|
1336
|
+
yes: Boolean(parsed.flags.yes || parsed.flags.y)
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
if (parsed.command === "use") {
|
|
1340
|
+
const version = parsed.args[0];
|
|
1341
|
+
if (!version) {
|
|
1342
|
+
console.error("Usage: lincoln use <version> [--yes] [--dry-run]");
|
|
1343
|
+
return 1;
|
|
1344
|
+
}
|
|
1345
|
+
return use(version, {
|
|
1346
|
+
dryRun: Boolean(parsed.flags["dry-run"]),
|
|
1347
|
+
yes: Boolean(parsed.flags.yes || parsed.flags.y)
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
if (parsed.command === "doctor") {
|
|
1351
|
+
const result = await doctor({ json: Boolean(parsed.flags.json) });
|
|
1352
|
+
return result.code;
|
|
1353
|
+
}
|
|
1354
|
+
if (parsed.command === "init-project") {
|
|
1355
|
+
return initProject(process.cwd(), {
|
|
1356
|
+
force: Boolean(parsed.flags.force),
|
|
1357
|
+
dryRun: Boolean(parsed.flags["dry-run"])
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
if (parsed.command === "migrate-project") {
|
|
1361
|
+
return migrateProject(process.cwd(), {
|
|
1362
|
+
dryRun: Boolean(parsed.flags["dry-run"]),
|
|
1363
|
+
yes: Boolean(parsed.flags.yes || parsed.flags.y),
|
|
1364
|
+
force: Boolean(parsed.flags.force)
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
if (parsed.command === "record") {
|
|
1368
|
+
return record(parsed.args);
|
|
1369
|
+
}
|
|
1370
|
+
console.log(USAGE);
|
|
1371
|
+
return 0;
|
|
1372
|
+
}
|
|
1373
|
+
if (process.argv[1] && path12.resolve(fs11.realpathSync(fileURLToPath2(import.meta.url))) === path12.resolve(fs11.realpathSync(process.argv[1]))) {
|
|
1374
|
+
main(process.argv).then((code) => process.exit(code));
|
|
1375
|
+
}
|
|
1376
|
+
export {
|
|
1377
|
+
main
|
|
1378
|
+
};
|
|
1009
1379
|
//# sourceMappingURL=main.js.map
|