@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.
Files changed (305) hide show
  1. package/dist/main.d.ts +3 -0
  2. package/dist/main.js +1286 -916
  3. package/dist/main.js.map +1 -1
  4. package/dist/postinstall.d.ts +3 -0
  5. package/dist/postinstall.js +18 -0
  6. package/dist/postinstall.js.map +1 -0
  7. package/framework/.claude/agents/_contract.md +79 -0
  8. package/framework/.claude/agents/architect.md +31 -0
  9. package/framework/.claude/agents/default.md +151 -0
  10. package/framework/.claude/agents/designer.md +33 -0
  11. package/framework/.claude/agents/engineer.md +42 -0
  12. package/framework/.claude/agents/external/NOTICES.md +12 -0
  13. package/framework/.claude/agents/external/everything-claude-code.manifest.yaml +23 -0
  14. package/framework/.claude/agents/external/oh-my-claudecode.manifest.yaml +26 -0
  15. package/framework/.claude/agents/external/wshobson-agents.manifest.yaml +23 -0
  16. package/framework/.claude/agents/frontend-engineer.md +32 -0
  17. package/framework/.claude/agents/knowledge-curator.md +28 -0
  18. package/framework/.claude/agents/pm.md +38 -0
  19. package/framework/.claude/agents/qa.md +28 -0
  20. package/framework/.claude/agents/release-coordinator.md +25 -0
  21. package/framework/.claude/agents/researcher.md +41 -0
  22. package/framework/.claude/harnesses/claude-code.yaml +15 -0
  23. package/framework/.claude/harnesses/codex.yaml +40 -0
  24. package/framework/.claude/harnesses/command-map.yaml +255 -0
  25. package/framework/.claude/harnesses/opencode.yaml +32 -0
  26. package/framework/.claude/harnesses/scenarios.yaml +45 -0
  27. package/framework/.claude/hooks/on-pr-event.sh +69 -0
  28. package/framework/.claude/hooks/on-session-start.sh +427 -0
  29. package/framework/.claude/hooks/on-stop.sh +104 -0
  30. package/framework/.claude/hooks/post-tool-use.sh +161 -0
  31. package/framework/.claude/hooks/pre-tool-use.sh +246 -0
  32. package/framework/.claude/schemas/agent-definition.schema.json +35 -0
  33. package/framework/.claude/schemas/benchmark-report.schema.json +148 -0
  34. package/framework/.claude/schemas/pm-to-ux-handoff.schema.yaml +128 -0
  35. package/framework/.claude/schemas/stage-definition.schema.json +233 -0
  36. package/framework/.claude/schemas/workflow-stage.schema.json +86 -0
  37. package/framework/.claude/schemas/workflow-template.schema.json +88 -0
  38. package/framework/.claude/settings.json +14 -0
  39. package/framework/.claude/skills/build-product-prototype/SKILL.md +35 -0
  40. package/framework/.claude/skills/build-product-prototype/prompts/main.md +78 -0
  41. package/framework/.claude/skills/clarify-requirements/SKILL.md +32 -0
  42. package/framework/.claude/skills/clarify-requirements/prompts/main.md +81 -0
  43. package/framework/.claude/skills/dependencies.yaml +139 -0
  44. package/framework/.claude/skills/draft-product-design/SKILL.md +40 -0
  45. package/framework/.claude/skills/draft-product-design/prompts/main.md +47 -0
  46. package/framework/.claude/skills/lc-analyze-frameworks/SKILL.md +43 -0
  47. package/framework/.claude/skills/lc-analyze-frameworks/prompts/main.md +95 -0
  48. package/framework/.claude/skills/lc-benchmark/SKILL.md +61 -0
  49. package/framework/.claude/skills/lc-build-codebase-knowledge/SKILL.md +38 -0
  50. package/framework/.claude/skills/lc-build-codebase-knowledge/prompts/build-codebase-knowledge.md +61 -0
  51. package/framework/.claude/skills/lc-collect-intelligence/SKILL.md +43 -0
  52. package/framework/.claude/skills/lc-collect-intelligence/prompts/main.md +72 -0
  53. package/framework/.claude/skills/lc-competitive-analysis/SKILL.md +43 -0
  54. package/framework/.claude/skills/lc-competitive-analysis/prompts/main.md +70 -0
  55. package/framework/.claude/skills/lc-explore-opensource/SKILL.md +36 -0
  56. package/framework/.claude/skills/lc-explore-opensource/prompts/explore-opensource.md +77 -0
  57. package/framework/.claude/skills/lc-first-principles/SKILL.md +43 -0
  58. package/framework/.claude/skills/lc-first-principles/prompts/main.md +73 -0
  59. package/framework/.claude/skills/lc-handoff/SKILL.md +34 -0
  60. package/framework/.claude/skills/lc-init-branch/SKILL.md +52 -0
  61. package/framework/.claude/skills/lc-market-research/SKILL.md +43 -0
  62. package/framework/.claude/skills/lc-market-research/prompts/main.md +79 -0
  63. package/framework/.claude/skills/lc-product-research/SKILL.md +43 -0
  64. package/framework/.claude/skills/lc-product-research/prompts/main.md +80 -0
  65. package/framework/.claude/skills/lc-research-report/SKILL.md +43 -0
  66. package/framework/.claude/skills/lc-research-report/prompts/main.md +90 -0
  67. package/framework/.claude/skills/lc-research-scope/SKILL.md +43 -0
  68. package/framework/.claude/skills/lc-research-scope/prompts/main.md +82 -0
  69. package/framework/.claude/skills/lc-setup/SKILL.md +68 -0
  70. package/framework/.claude/skills/lc-setup/prompts/main.md +88 -0
  71. package/framework/.claude/skills/lc-stage/SKILL.md +45 -0
  72. package/framework/.claude/skills/lc-stakeholder-research/SKILL.md +43 -0
  73. package/framework/.claude/skills/lc-stakeholder-research/prompts/main.md +65 -0
  74. package/framework/.claude/skills/lc-status/SKILL.md +25 -0
  75. package/framework/.claude/skills/lc-storytelling/SKILL.md +43 -0
  76. package/framework/.claude/skills/lc-storytelling/prompts/main.md +77 -0
  77. package/framework/.claude/skills/lc-wf/SKILL.md +54 -0
  78. package/framework/.claude/skills/lc-workflow/SKILL.md +48 -0
  79. package/framework/.claude/skills/lc-workflow/validators/validate.py +755 -0
  80. package/framework/.claude/skills/lc-workflow-router/SKILL.md +41 -0
  81. package/framework/.claude/skills/lc-workflow-router/prompts/intake-prompt.md +91 -0
  82. package/framework/.claude/skills/lc-workflow-router/prompts/router-prompt.md +44 -0
  83. package/framework/.claude/skills/plan-tdd-development/SKILL.md +31 -0
  84. package/framework/.claude/skills/plan-tdd-development/prompts/main.md +44 -0
  85. package/framework/.claude/skills/process-interview/SKILL.md +32 -0
  86. package/framework/.claude/skills/process-interview/prompts/main.md +47 -0
  87. package/framework/.claude/skills/propose-with-openspec/SKILL.md +37 -0
  88. package/framework/.claude/skills/propose-with-openspec/prompts/main.md +53 -0
  89. package/framework/.claude/skills/split-to-github/SKILL.md +32 -0
  90. package/framework/.claude/skills/split-to-github/prompts/main.md +42 -0
  91. package/framework/.claude/skills/sync-to-knowledge/SKILL.md +35 -0
  92. package/framework/.claude/skills/sync-to-knowledge/prompts/main.md +54 -0
  93. package/framework/.claude/skills/workflow-continue/SKILL.md +24 -0
  94. package/framework/.claude/skills/workflow-continue/prompts/main.md +25 -0
  95. package/framework/.claude/stages/build-codebase-knowledge.yaml +42 -0
  96. package/framework/.claude/stages/clarify.yaml +59 -0
  97. package/framework/.claude/stages/explore-opensource.yaml +40 -0
  98. package/framework/.claude/stages/implement.yaml +60 -0
  99. package/framework/.claude/stages/ingest.yaml +40 -0
  100. package/framework/.claude/stages/lc-analyze-frameworks.yaml +37 -0
  101. package/framework/.claude/stages/lc-collect-intelligence.yaml +37 -0
  102. package/framework/.claude/stages/lc-competitive-analysis.yaml +37 -0
  103. package/framework/.claude/stages/lc-first-principles.yaml +37 -0
  104. package/framework/.claude/stages/lc-market-research.yaml +37 -0
  105. package/framework/.claude/stages/lc-product-research.yaml +37 -0
  106. package/framework/.claude/stages/lc-research-report.yaml +38 -0
  107. package/framework/.claude/stages/lc-research-scope.yaml +38 -0
  108. package/framework/.claude/stages/lc-stakeholder-research.yaml +37 -0
  109. package/framework/.claude/stages/lc-storytelling.yaml +37 -0
  110. package/framework/.claude/stages/product-design-docs.yaml +66 -0
  111. package/framework/.claude/stages/product-prototype.yaml +53 -0
  112. package/framework/.claude/stages/propose.yaml +45 -0
  113. package/framework/.claude/stages/split.yaml +41 -0
  114. package/framework/.claude/stages/sync-knowledge.yaml +49 -0
  115. package/framework/.claude/stages/tdd-development-plan.yaml +43 -0
  116. package/framework/.claude/stages/workflow-router.yaml +45 -0
  117. package/framework/.claude/templates/solo-workflow-context.yaml +23 -0
  118. package/framework/.claude/workflows/README.md +93 -0
  119. package/framework/.claude/workflows/bug-fix.yaml +81 -0
  120. package/framework/.claude/workflows/design-spike.yaml +55 -0
  121. package/framework/.claude/workflows/existing-project-iteration.yaml +106 -0
  122. package/framework/.claude/workflows/interview-to-knowledge.yaml +189 -0
  123. package/framework/.claude/workflows/oss-first-design.yaml +100 -0
  124. package/framework/.claude/workflows/pm-research.yaml +115 -0
  125. package/framework/.claude-plugin/hooks.json +6 -0
  126. package/framework/.claude-plugin/marketplace.json +32 -0
  127. package/framework/.claude-plugin/plugin.json +57 -0
  128. package/framework/.version-bump.json +43 -0
  129. package/framework/CLAUDE.md +140 -0
  130. package/framework/CONTRIBUTING.md +219 -0
  131. package/framework/LICENSE +21 -0
  132. package/framework/README.en.md +139 -0
  133. package/framework/README.md +139 -0
  134. package/framework/RELEASE.md +334 -0
  135. package/framework/SKILL.md +24 -0
  136. package/framework/USAGE.md +356 -0
  137. package/framework/manifest.json +1214 -0
  138. package/framework/requirements.txt +4 -0
  139. package/framework/scripts/__init__.py +0 -0
  140. package/framework/scripts/build_codebase_knowledge.py +76 -0
  141. package/framework/scripts/bump_version.py +181 -0
  142. package/framework/scripts/check-dependency-drift.py +69 -0
  143. package/framework/scripts/check-harness-drift.sh +57 -0
  144. package/framework/scripts/check-main-merge-hygiene.py +128 -0
  145. package/framework/scripts/check-skill-dependencies.sh +124 -0
  146. package/framework/scripts/init-lincoln-branch.sh +300 -0
  147. package/framework/scripts/init-project.sh +184 -0
  148. package/framework/scripts/lc-benchmark-cli.py +66 -0
  149. package/framework/scripts/lincoln-audit.py +288 -0
  150. package/framework/scripts/lincoln-setup.py +651 -0
  151. package/framework/scripts/lincoln-status.py +448 -0
  152. package/framework/scripts/lincoln_benchmark.py +224 -0
  153. package/framework/scripts/lincoln_benchmark_eval.py +104 -0
  154. package/framework/scripts/lincoln_benchmark_metrics.py +818 -0
  155. package/framework/scripts/lincoln_benchmark_report.py +141 -0
  156. package/framework/scripts/lincoln_command_map.py +289 -0
  157. package/framework/scripts/lincoln_dependency_manager.py +335 -0
  158. package/framework/scripts/lincoln_documents.py +175 -0
  159. package/framework/scripts/lincoln_harness_adapter.py +319 -0
  160. package/framework/scripts/lincoln_index.py +255 -0
  161. package/framework/scripts/lincoln_paths.py +198 -0
  162. package/framework/scripts/lincoln_prd.py +227 -0
  163. package/framework/scripts/lincoln_role.py +46 -0
  164. package/framework/scripts/lincoln_scenario.py +59 -0
  165. package/framework/scripts/lincoln_session_start_metrics.py +71 -0
  166. package/framework/scripts/lincoln_skill_prompt.py +48 -0
  167. package/framework/scripts/lincoln_trace.py +335 -0
  168. package/framework/scripts/lincoln_workflow.py +199 -0
  169. package/framework/scripts/list-active-lincoln-branches.sh +87 -0
  170. package/framework/scripts/package-lincoln-plugin.py +340 -0
  171. package/framework/scripts/run-infrastructure-tests.py +84 -0
  172. package/framework/scripts/stage_loader.py +1071 -0
  173. package/framework/scripts/static-check.sh +356 -0
  174. package/framework/scripts/sync-external-agents.sh +210 -0
  175. package/framework/scripts/sync-framework-package.mjs +218 -0
  176. package/framework/scripts/task_tool_guard.py +213 -0
  177. package/framework/scripts/track-artifacts.py +140 -0
  178. package/framework/scripts/validate_stage.py +350 -0
  179. package/{README.md → framework/tools/lincoln/README.md} +4 -4
  180. package/framework/tools/lincoln/package-lock.json +3349 -0
  181. package/framework/tools/lincoln/package.json +48 -0
  182. package/framework/tools/lincoln/src/cli.tsx +60 -0
  183. package/framework/tools/lincoln/src/components/AudioMeter.tsx +34 -0
  184. package/framework/tools/lincoln/src/components/CancelledScreen.tsx +11 -0
  185. package/framework/tools/lincoln/src/components/DevicesMenu.tsx +79 -0
  186. package/framework/tools/lincoln/src/components/HintBar.tsx +25 -0
  187. package/framework/tools/lincoln/src/components/LogView.tsx +36 -0
  188. package/framework/tools/lincoln/src/components/ModelMenu.tsx +122 -0
  189. package/framework/tools/lincoln/src/components/ReadyScreen.tsx +54 -0
  190. package/framework/tools/lincoln/src/components/RecordingApp.tsx +211 -0
  191. package/framework/tools/lincoln/src/components/RecordingScreen.tsx +41 -0
  192. package/framework/tools/lincoln/src/components/SelectMenu.tsx +53 -0
  193. package/framework/tools/lincoln/src/components/StatusPanel.tsx +52 -0
  194. package/framework/tools/lincoln/src/components/StopConfirmation.tsx +32 -0
  195. package/framework/tools/lincoln/src/config/args.ts +35 -0
  196. package/framework/tools/lincoln/src/config/loadConfig.ts +81 -0
  197. package/framework/tools/lincoln/src/config/resolveConfig.ts +85 -0
  198. package/framework/tools/lincoln/src/devices/listDevices.ts +11 -0
  199. package/framework/tools/lincoln/src/devices/parseDevices.ts +25 -0
  200. package/framework/tools/lincoln/src/hooks/useKeyHandler.ts +63 -0
  201. package/framework/tools/lincoln/src/main.tsx +4 -0
  202. package/framework/tools/lincoln/src/models/models.ts +34 -0
  203. package/framework/tools/lincoln/src/models/runWarmup.ts +46 -0
  204. package/framework/tools/lincoln/src/models/warmupProgress.ts +30 -0
  205. package/framework/tools/lincoln/src/recording/spawnRecorder.ts +127 -0
  206. package/framework/tools/lincoln/src/recording/useRecorder.ts +146 -0
  207. package/framework/tools/lincoln/src/utils/amplitudeToMeter.ts +4 -0
  208. package/framework/tools/lincoln/src/utils/formatDuration.ts +6 -0
  209. package/framework/tools/lincoln/src/utils/sessionId.ts +25 -0
  210. package/framework/tools/lincoln/tests/cli.test.tsx +52 -0
  211. package/framework/tools/lincoln/tests/components/AudioMeter.test.tsx +31 -0
  212. package/framework/tools/lincoln/tests/components/CancelledScreen.test.tsx +12 -0
  213. package/framework/tools/lincoln/tests/components/ReadyScreen.test.tsx +68 -0
  214. package/framework/tools/lincoln/tests/components/RecordingApp.menus.test.tsx +158 -0
  215. package/framework/tools/lincoln/tests/components/RecordingApp.test.tsx +248 -0
  216. package/framework/tools/lincoln/tests/components/RecordingScreen.test.tsx +37 -0
  217. package/framework/tools/lincoln/tests/components/SelectMenu.test.tsx +59 -0
  218. package/framework/tools/lincoln/tests/components/StopConfirmation.test.tsx +38 -0
  219. package/framework/tools/lincoln/tests/config/args.test.ts +49 -0
  220. package/framework/tools/lincoln/tests/config/loadConfig.test.ts +59 -0
  221. package/framework/tools/lincoln/tests/config/resolveConfig.test.ts +72 -0
  222. package/framework/tools/lincoln/tests/devices/parseDevices.test.ts +21 -0
  223. package/framework/tools/lincoln/tests/hooks/useKeyHandler.enabled.test.tsx +44 -0
  224. package/framework/tools/lincoln/tests/hooks/useKeyHandler.test.tsx +130 -0
  225. package/framework/tools/lincoln/tests/models/models.test.ts +27 -0
  226. package/framework/tools/lincoln/tests/models/warmupProgress.test.ts +25 -0
  227. package/framework/tools/lincoln/tests/recording/spawnRecorder.test.ts +85 -0
  228. package/framework/tools/lincoln/tests/recording/useRecorder.test.tsx +172 -0
  229. package/framework/tools/lincoln/tests/utils/amplitudeToMeter.test.ts +22 -0
  230. package/framework/tools/lincoln/tests/utils/formatDuration.test.ts +11 -0
  231. package/framework/tools/lincoln/tests/utils/sessionId.test.ts +30 -0
  232. package/framework/tools/lincoln/tsconfig.json +22 -0
  233. package/framework/tools/lincoln/tsconfig.tests.json +10 -0
  234. package/framework/tools/lincoln/tsup.config.ts +17 -0
  235. package/framework/tools/lincoln/vitest.config.ts +20 -0
  236. package/framework/tools/lincoln-installer/package-lock.json +3611 -0
  237. package/framework/tools/lincoln-installer/package.json +53 -0
  238. package/framework/tools/lincoln-installer/src/cli.tsx +63 -0
  239. package/framework/tools/lincoln-installer/src/components/HarnessSelectScreen.tsx +43 -0
  240. package/framework/tools/lincoln-installer/src/components/InstallerApp.tsx +98 -0
  241. package/framework/tools/lincoln-installer/src/components/OptionsScreen.tsx +56 -0
  242. package/framework/tools/lincoln-installer/src/components/ProgressScreen.tsx +25 -0
  243. package/framework/tools/lincoln-installer/src/components/ResultScreen.tsx +40 -0
  244. package/framework/tools/lincoln-installer/src/components/SelectMenu.tsx +73 -0
  245. package/framework/tools/lincoln-installer/src/components/SummaryScreen.tsx +49 -0
  246. package/framework/tools/lincoln-installer/src/components/UpdateApp.tsx +135 -0
  247. package/framework/tools/lincoln-installer/src/components/WelcomeScreen.tsx +22 -0
  248. package/framework/tools/lincoln-installer/src/config/args.ts +76 -0
  249. package/framework/tools/lincoln-installer/src/config/resolveConfig.ts +33 -0
  250. package/framework/tools/lincoln-installer/src/config/updateArgs.ts +67 -0
  251. package/framework/tools/lincoln-installer/src/hooks/useSetup.ts +149 -0
  252. package/framework/tools/lincoln-installer/src/main.tsx +11 -0
  253. package/framework/tools/lincoln-installer/src/types.ts +19 -0
  254. package/framework/tools/lincoln-installer/src/update-main.tsx +11 -0
  255. package/framework/tools/lincoln-installer/src/update.tsx +90 -0
  256. package/framework/tools/lincoln-installer/src/utils/detectHarness.ts +51 -0
  257. package/framework/tools/lincoln-installer/src/utils/runSetup.ts +62 -0
  258. package/framework/tools/lincoln-installer/src/utils/updateRelease.ts +454 -0
  259. package/framework/tools/lincoln-installer/tests/components/InstallerApp.test.tsx +88 -0
  260. package/framework/tools/lincoln-installer/tests/components/SelectMenu.test.tsx +26 -0
  261. package/framework/tools/lincoln-installer/tests/components/UpdateApp.test.tsx +170 -0
  262. package/framework/tools/lincoln-installer/tests/components/screens.test.tsx +310 -0
  263. package/framework/tools/lincoln-installer/tests/config/args.test.ts +66 -0
  264. package/framework/tools/lincoln-installer/tests/config/resolveConfig.test.ts +75 -0
  265. package/framework/tools/lincoln-installer/tests/config/updateArgs.test.ts +52 -0
  266. package/framework/tools/lincoln-installer/tests/hooks/useSetup.test.tsx +213 -0
  267. package/framework/tools/lincoln-installer/tests/update.test.tsx +108 -0
  268. package/framework/tools/lincoln-installer/tests/utils/detectHarness.test.ts +40 -0
  269. package/framework/tools/lincoln-installer/tests/utils/runSetup.test.ts +45 -0
  270. package/framework/tools/lincoln-installer/tests/utils/updateRelease.test.ts +559 -0
  271. package/framework/tools/lincoln-installer/tsconfig.json +22 -0
  272. package/framework/tools/lincoln-installer/tsconfig.tests.json +8 -0
  273. package/framework/tools/lincoln-installer/tsup.config.ts +17 -0
  274. package/framework/tools/lincoln-installer/vitest.config.ts +20 -0
  275. package/framework/tools/lincoln-record/Cargo.lock +1896 -0
  276. package/framework/tools/lincoln-record/Cargo.toml +24 -0
  277. package/framework/tools/lincoln-record/diarize/diarize.py +117 -0
  278. package/framework/tools/lincoln-record/diarize/merge.py +55 -0
  279. package/framework/tools/lincoln-record/src/audio/capture/microphone.rs +194 -0
  280. package/framework/tools/lincoln-record/src/audio/capture/mod.rs +1 -0
  281. package/framework/tools/lincoln-record/src/audio/devices.rs +20 -0
  282. package/framework/tools/lincoln-record/src/audio/mod.rs +5 -0
  283. package/framework/tools/lincoln-record/src/audio/resampler.rs +44 -0
  284. package/framework/tools/lincoln-record/src/audio/saver.rs +87 -0
  285. package/framework/tools/lincoln-record/src/audio/source.rs +104 -0
  286. package/framework/tools/lincoln-record/src/cli.rs +96 -0
  287. package/framework/tools/lincoln-record/src/config.rs +135 -0
  288. package/framework/tools/lincoln-record/src/lib.rs +6 -0
  289. package/framework/tools/lincoln-record/src/main.rs +242 -0
  290. package/framework/tools/lincoln-record/src/model/mod.rs +248 -0
  291. package/framework/tools/lincoln-record/src/output/metadata.rs +30 -0
  292. package/framework/tools/lincoln-record/src/output/mod.rs +2 -0
  293. package/framework/tools/lincoln-record/src/output/transcript.rs +42 -0
  294. package/framework/tools/lincoln-record/src/transcription/diarization.rs +64 -0
  295. package/framework/tools/lincoln-record/src/transcription/mod.rs +3 -0
  296. package/framework/tools/lincoln-record/src/transcription/provider.rs +43 -0
  297. package/framework/tools/lincoln-record/src/transcription/whisper.rs +176 -0
  298. package/framework/tools/lincoln-record/tests/cli_args.rs +103 -0
  299. package/framework/tools/lincoln-record/tests/config_test.rs +70 -0
  300. package/framework/tools/lincoln-record/tests/devices_test.rs +23 -0
  301. package/framework/tools/lincoln-record/tests/diarization_tests.rs +101 -0
  302. package/framework/tools/lincoln-record/tests/integration_tests.rs +44 -0
  303. package/framework/tools/lincoln-record/tests/model_test.rs +68 -0
  304. package/framework/tools/lincoln-record/tests/transcription_tests.rs +73 -0
  305. package/package.json +19 -13
@@ -0,0 +1,651 @@
1
+ #!/usr/bin/env python3
2
+ """Lincoln setup CLI — invoked by Claude, not by end users directly.
3
+
4
+ This script is the implementation backend for the `lc-setup` skill.
5
+ It discovers missing dependencies from `.claude/skills/dependencies.yaml`,
6
+ installs external skills/CLIs, and initializes repository configuration.
7
+
8
+ Usage (called by Claude):
9
+ python scripts/lincoln-setup.py check
10
+ python scripts/lincoln-setup.py install-skills
11
+ python scripts/lincoln-setup.py install-clis
12
+ python scripts/lincoln-setup.py init-repo-config --owner <owner> --name <repo>
13
+ python scripts/lincoln-setup.py init-project
14
+ python scripts/lincoln-setup.py mark-step --step init_project --status completed
15
+ python scripts/lincoln-setup.py is-setup-complete
16
+ python scripts/lincoln-setup.py bootstrap
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import argparse
22
+ import json
23
+ import re
24
+ import subprocess
25
+ import sys
26
+ from pathlib import Path
27
+ from typing import Any
28
+
29
+ # Ensure the project root is on sys.path so `scripts` is importable when this
30
+ # script is invoked directly.
31
+ _PROJECT_ROOT = Path(__file__).resolve().parents[1]
32
+ if str(_PROJECT_ROOT) not in sys.path:
33
+ sys.path.insert(0, str(_PROJECT_ROOT))
34
+
35
+ from scripts import lincoln_dependency_manager, lincoln_harness_adapter
36
+
37
+
38
+ # Steps tracked in `.context/lc-setup-state.yaml`.
39
+ _SETUP_STATE_PATH = Path(".context") / "lc-setup-state.yaml"
40
+
41
+
42
+ def confirm(prompt: str, auto_yes: bool = False) -> bool:
43
+ """Ask the user for confirmation, or return True when auto_yes is set."""
44
+ if auto_yes:
45
+ return True
46
+ try:
47
+ answer = input(f"{prompt} [y/N] ").strip().lower()
48
+ except (EOFError, KeyboardInterrupt):
49
+ return False
50
+ return answer in ("y", "yes", "all")
51
+
52
+
53
+ def _load_state(root: Path) -> dict[str, Any]:
54
+ """Load the per-repo setup state file, returning an empty dict if absent."""
55
+ state_file = root / _SETUP_STATE_PATH
56
+ if not state_file.exists():
57
+ return {"steps": {}}
58
+ try:
59
+ import yaml
60
+
61
+ data = yaml.safe_load(state_file.read_text(encoding="utf-8")) or {}
62
+ data.setdefault("steps", {})
63
+ return data
64
+ except Exception as exc:
65
+ print(f"āš ļø Failed to read {state_file}: {exc}; starting with empty state.")
66
+ return {"steps": {}}
67
+
68
+
69
+ def _save_state(root: Path, state: dict[str, Any]) -> None:
70
+ """Persist the per-repo setup state file."""
71
+ import yaml
72
+
73
+ state_file = root / _SETUP_STATE_PATH
74
+ state_file.parent.mkdir(parents=True, exist_ok=True)
75
+ state_file.write_text(yaml.safe_dump(state, allow_unicode=True, sort_keys=False), encoding="utf-8")
76
+
77
+
78
+ def _mark_step(root: Path, step: str, status: str) -> None:
79
+ """Record that a setup step has been attempted or completed."""
80
+ state = _load_state(root)
81
+ state["steps"][step] = {"status": status}
82
+ _save_state(root, state)
83
+
84
+
85
+ def is_setup_complete(root: Path) -> bool:
86
+ """Return True when all setup steps have been recorded as completed."""
87
+ state = _load_state(root)
88
+ steps = state.get("steps", {})
89
+ required = ("skills", "clis", "repo_config", "init_project")
90
+ return all(steps.get(s, {}).get("status") == "completed" for s in required)
91
+
92
+
93
+ def _github_owner_name_from_remote(root: Path) -> tuple[str, str] | None:
94
+ """Try to infer GitHub owner/name from `git remote get-url origin`."""
95
+ import subprocess
96
+
97
+ try:
98
+ proc = subprocess.run(
99
+ ["git", "remote", "get-url", "origin"],
100
+ cwd=root,
101
+ capture_output=True,
102
+ text=True,
103
+ check=False,
104
+ )
105
+ if proc.returncode != 0:
106
+ return None
107
+ url = proc.stdout.strip()
108
+ # Match git@github.com:owner/repo.git or https://github.com/owner/repo.git
109
+ match = re.search(r"github\.com[:/]([^/]+)/([^/]+?)(?:\.git)?$", url)
110
+ if match:
111
+ return match.group(1), match.group(2)
112
+ except Exception:
113
+ pass
114
+ return None
115
+
116
+
117
+ def run_check(args: argparse.Namespace) -> int:
118
+ """Check all declared dependencies and print a summary."""
119
+ root = Path(args.root).resolve()
120
+ platform_name = lincoln_dependency_manager.detect_platform()
121
+
122
+ try:
123
+ manifest = lincoln_dependency_manager.load_dependencies(root)
124
+ except FileNotFoundError as exc:
125
+ if args.format == "json":
126
+ print(json.dumps({"complete": False, "required": [], "optional": [], "error": str(exc)}))
127
+ else:
128
+ print(f"āŒ {exc}")
129
+ return 1
130
+
131
+ skills_dir = Path.home() / ".claude" / "skills"
132
+ missing_skills = lincoln_dependency_manager.check_skills(manifest, root, skills_dir)
133
+ missing_clis = lincoln_dependency_manager.check_clis(manifest, platform_name)
134
+
135
+ required_missing = [m for m in missing_skills + missing_clis if m.get("required")]
136
+ optional_missing = [m for m in missing_skills + missing_clis if not m.get("required")]
137
+
138
+ if args.format == "json":
139
+ print(
140
+ json.dumps(
141
+ {
142
+ "complete": not required_missing and not optional_missing,
143
+ "required": required_missing,
144
+ "optional": optional_missing,
145
+ }
146
+ )
147
+ )
148
+ return 1 if required_missing else 0
149
+
150
+ if required_missing:
151
+ print("āŒ Required dependencies missing:")
152
+ for dep in required_missing:
153
+ print(f" - {dep['name']} ({dep['type']})")
154
+ if dep.get("install_command"):
155
+ print(f" Install: {dep['install_command']}")
156
+ if dep.get("install_note"):
157
+ print(f" Note: {dep['install_note']}")
158
+
159
+ if optional_missing:
160
+ print("\nā„¹ļø Optional dependencies missing:")
161
+ for dep in optional_missing:
162
+ print(f" - {dep['name']} ({dep['type']})")
163
+ if dep.get("install_command"):
164
+ print(f" Install: {dep['install_command']}")
165
+
166
+ if not required_missing and not optional_missing:
167
+ print("āœ… All declared dependencies are present.")
168
+ return 0
169
+
170
+ return 1 if required_missing else 0
171
+
172
+
173
+ def detect_legacy_skills(skills_dir: Path) -> list[str]:
174
+ """Return old `lincoln-*` skill dir names left over from before the lc-* rename."""
175
+ if not skills_dir.is_dir():
176
+ return []
177
+ return sorted(p.name for p in skills_dir.iterdir() if p.is_dir() and p.name.startswith("lincoln-"))
178
+
179
+
180
+ def _warn_legacy_skills(skills_dir: Path) -> None:
181
+ legacy = detect_legacy_skills(skills_dir)
182
+ if not legacy:
183
+ return
184
+ print("\nāš ļø ę£€ęµ‹åˆ°ę—§ē‰ˆęŠ€čƒ½ē›®å½•(å·²é‡å‘½åäøŗ lc-* ē³»åˆ—,äøå†ē»“ęŠ¤):")
185
+ for name in legacy:
186
+ print(f" - {skills_dir / name}")
187
+ print(" čæē§»ę–¹å¼:ē”®č®¤ę— ęœ¬åœ°ę”¹åŠØåŽę‰‹åŠØåˆ é™¤äøŠčæ°ē›®å½•,é‡ę–°čæč”Œ lc-setup怂")
188
+
189
+
190
+ def run_install_skills(args: argparse.Namespace) -> int:
191
+ """Install missing external skills and plugins."""
192
+ root = Path(args.root).resolve()
193
+ platform_name = lincoln_dependency_manager.detect_platform()
194
+
195
+ try:
196
+ manifest = lincoln_dependency_manager.load_dependencies(root)
197
+ except FileNotFoundError as exc:
198
+ if args.format == "json":
199
+ print(json.dumps({"success": False, "results": [], "error": str(exc)}))
200
+ else:
201
+ print(f"āŒ {exc}")
202
+ return 1
203
+
204
+ skills_dir = Path.home() / ".claude" / "skills"
205
+ if args.format != "json":
206
+ _warn_legacy_skills(skills_dir)
207
+ missing = lincoln_dependency_manager.check_skills(manifest, root, skills_dir)
208
+
209
+ if not missing:
210
+ _mark_step(root, "skills", "completed")
211
+ if args.format == "json":
212
+ print(json.dumps({"success": True, "results": []}))
213
+ else:
214
+ print("āœ… All skills already present.")
215
+ return 0
216
+
217
+ auto_yes = args.yes or args.dry_run
218
+ offline_cache = Path(args.offline_cache) if args.offline_cache else None
219
+ all_ok = True
220
+ results = []
221
+
222
+ for dep in missing:
223
+ if not dep.get("default_install", dep.get("required", True)):
224
+ if args.format != "json":
225
+ print(f"ā­ļø Skipping optional {dep['name']} (not default_install).")
226
+ results.append({"name": dep["name"], "status": "skipped_optional", "reason": "not default_install"})
227
+ continue
228
+
229
+ cmd = dep.get("install_command")
230
+ if not cmd:
231
+ if args.format != "json":
232
+ print(f"āš ļø No install command for {dep['name']}; skipping.")
233
+ all_ok = False
234
+ results.append({"name": dep["name"], "status": "failed", "reason": "no install command"})
235
+ continue
236
+
237
+ prompt = f"Install {dep['name']} ({dep['type']})? Command: {cmd}"
238
+ if not confirm(prompt, auto_yes=auto_yes):
239
+ if args.format != "json":
240
+ print(f"ā­ļø Skipped {dep['name']}.")
241
+ all_ok = False
242
+ results.append({"name": dep["name"], "status": "declined"})
243
+ continue
244
+
245
+ if dep["type"] in ("skill", "plugin"):
246
+ install_result = lincoln_dependency_manager.install_skill(
247
+ dep["name"],
248
+ dep["source"],
249
+ dep.get("ref", ""),
250
+ skills_dir,
251
+ offline_cache=offline_cache,
252
+ dry_run=args.dry_run,
253
+ )
254
+ else:
255
+ install_result = lincoln_dependency_manager.install_cli(dep["name"], cmd, dry_run=args.dry_run)
256
+
257
+ if install_result.get("installed"):
258
+ if args.format != "json":
259
+ print(f"āœ… Installed {dep['name']}.")
260
+ results.append({"name": dep["name"], "status": "installed"})
261
+ elif install_result.get("skipped"):
262
+ if args.format != "json":
263
+ print(f"ā­ļø {dep['name']} already up to date.")
264
+ results.append({"name": dep["name"], "status": "skipped"})
265
+ elif install_result.get("dry_run"):
266
+ if args.format != "json":
267
+ print(f"šŸ” Dry-run: would have installed {dep['name']}.")
268
+ results.append({"name": dep["name"], "status": "dry_run"})
269
+ else:
270
+ error = install_result.get("error", "unknown error")
271
+ if args.format != "json":
272
+ print(f"āŒ Failed to install {dep['name']}: {error}")
273
+ all_ok = False
274
+ results.append({"name": dep["name"], "status": "failed", "error": error})
275
+
276
+ if all_ok:
277
+ _mark_step(root, "skills", "completed")
278
+ if args.format == "json":
279
+ print(json.dumps({"success": True, "results": results}))
280
+ return 0
281
+ if args.format == "json":
282
+ print(json.dumps({"success": False, "results": results}))
283
+ return 1
284
+
285
+
286
+ def run_install_clis(args: argparse.Namespace) -> int:
287
+ """Install missing CLI dependencies."""
288
+ root = Path(args.root).resolve()
289
+ platform_name = lincoln_dependency_manager.detect_platform()
290
+
291
+ try:
292
+ manifest = lincoln_dependency_manager.load_dependencies(root)
293
+ except FileNotFoundError as exc:
294
+ if args.format == "json":
295
+ print(json.dumps({"success": False, "results": [], "error": str(exc)}))
296
+ else:
297
+ print(f"āŒ {exc}")
298
+ return 1
299
+
300
+ missing = lincoln_dependency_manager.check_clis(manifest, platform_name)
301
+ if not missing:
302
+ _mark_step(root, "clis", "completed")
303
+ if args.format == "json":
304
+ print(json.dumps({"success": True, "results": []}))
305
+ else:
306
+ print("āœ… All CLI dependencies already present.")
307
+ return 0
308
+
309
+ auto_yes = args.yes
310
+ all_ok = True
311
+ results = []
312
+
313
+ for dep in missing:
314
+ cmd = dep.get("install_command")
315
+ if not cmd:
316
+ if args.format != "json":
317
+ print(f"āš ļø No install command for {dep['name']} on this platform.")
318
+ print(f" Manual install note: {dep.get('install_note', 'N/A')}")
319
+ all_ok = False
320
+ results.append({"name": dep["name"], "status": "failed", "reason": "no install command"})
321
+ continue
322
+
323
+ prompt = f"Install {dep['name']} ({dep['binary']})? Command: {cmd}"
324
+ if not confirm(prompt, auto_yes=auto_yes):
325
+ if args.format != "json":
326
+ print(f"ā­ļø Skipped {dep['name']}.")
327
+ all_ok = False
328
+ results.append({"name": dep["name"], "status": "declined"})
329
+ continue
330
+
331
+ install_result = lincoln_dependency_manager.install_cli(dep["name"], cmd, dry_run=args.dry_run)
332
+ if install_result.get("installed"):
333
+ if args.format != "json":
334
+ print(f"āœ… Installed {dep['name']}.")
335
+ results.append({"name": dep["name"], "status": "installed"})
336
+ elif install_result.get("dry_run"):
337
+ if args.format != "json":
338
+ print(f"šŸ” Dry-run: would have installed {dep['name']}.")
339
+ results.append({"name": dep["name"], "status": "dry_run"})
340
+ else:
341
+ error = install_result.get("error", "unknown error")
342
+ if args.format != "json":
343
+ print(f"āŒ Failed to install {dep['name']}: {error}")
344
+ all_ok = False
345
+ results.append({"name": dep["name"], "status": "failed", "error": error})
346
+
347
+ if all_ok:
348
+ _mark_step(root, "clis", "completed")
349
+ if args.format == "json":
350
+ print(json.dumps({"success": True, "results": results}))
351
+ return 0
352
+ if args.format == "json":
353
+ print(json.dumps({"success": False, "results": results}))
354
+ return 1
355
+
356
+
357
+ def run_init_repo_config(args: argparse.Namespace) -> int:
358
+ """Initialize `.github/openspec-config.yml` with real owner/name."""
359
+ root = Path(args.root).resolve()
360
+ config_path = root / ".github" / "openspec-config.yml"
361
+
362
+ owner = args.owner
363
+ name = args.name
364
+ branch = args.branch
365
+
366
+ if not owner or not name:
367
+ inferred = _github_owner_name_from_remote(root)
368
+ if inferred:
369
+ default_owner, default_name = inferred
370
+ owner = owner or default_owner
371
+ name = name or default_name
372
+
373
+ if not owner or not name:
374
+ message = "Could not determine GitHub owner/name."
375
+ if args.format == "json":
376
+ print(json.dumps({"success": False, "owner": owner, "name": name, "error": message}))
377
+ else:
378
+ print(f"āŒ {message}")
379
+ print(" Please provide --owner and --name, or ensure origin remote points to GitHub.")
380
+ return 1
381
+
382
+ if args.dry_run:
383
+ if args.format == "json":
384
+ print(json.dumps({"success": True, "owner": owner, "name": name, "branch": branch, "dry_run": True}))
385
+ else:
386
+ print(f"šŸ” Dry-run: would write {config_path} with owner={owner}, name={name}, branch={branch}.")
387
+ return 0
388
+
389
+ result = lincoln_dependency_manager.init_openspec_config(owner, name, branch, config_path)
390
+ if result.get("updated"):
391
+ _mark_step(root, "repo_config", "completed")
392
+ if args.format == "json":
393
+ print(json.dumps({"success": True, "owner": owner, "name": name, "branch": branch, "updated": True}))
394
+ else:
395
+ print(f"āœ… Updated {config_path}: {owner}/{name} ({branch}).")
396
+ return 0
397
+ if result.get("skipped"):
398
+ _mark_step(root, "repo_config", "completed")
399
+ if args.format == "json":
400
+ print(json.dumps({"success": True, "owner": owner, "name": name, "branch": branch, "skipped": True}))
401
+ else:
402
+ print(f"ā„¹ļø {config_path} already contains real values; leaving unchanged.")
403
+ return 0
404
+
405
+ error = result.get("error", "unknown error")
406
+ if args.format == "json":
407
+ print(json.dumps({"success": False, "owner": owner, "name": name, "error": error}))
408
+ else:
409
+ print(f"āŒ Failed to update {config_path}: {error}")
410
+ return 1
411
+
412
+
413
+ def run_init_project(args: argparse.Namespace) -> int:
414
+ """Run scripts/init-project.sh to create directories and initial commit."""
415
+ root = Path(args.root).resolve()
416
+ script = root / "scripts" / "init-project.sh"
417
+
418
+ if not script.exists():
419
+ message = f"{script} not found."
420
+ if args.format == "json":
421
+ print(json.dumps({"success": False, "step": "init_project", "error": message}))
422
+ else:
423
+ print(f"āŒ {message}")
424
+ return 1
425
+
426
+ prompt = f"Run {script} to initialize the project directory structure?"
427
+ if not args.yes and not confirm(prompt, auto_yes=False):
428
+ if args.format == "json":
429
+ print(json.dumps({"success": False, "step": "init_project", "status": "declined"}))
430
+ else:
431
+ print("ā­ļø Skipped project initialization.")
432
+ return 1
433
+
434
+ if args.dry_run:
435
+ _mark_step(root, "init_project", "completed")
436
+ if args.format == "json":
437
+ print(json.dumps({"success": True, "step": "init_project", "dry_run": True}))
438
+ else:
439
+ print(f"šŸ” Dry-run: would run {script}")
440
+ return 0
441
+
442
+ try:
443
+ proc = subprocess.run(
444
+ ["bash", str(script)],
445
+ cwd=root,
446
+ check=False,
447
+ )
448
+ except Exception as exc:
449
+ if args.format == "json":
450
+ print(json.dumps({"success": False, "step": "init_project", "error": str(exc)}))
451
+ else:
452
+ print(f"āŒ Failed to run {script}: {exc}")
453
+ return 1
454
+
455
+ if proc.returncode != 0:
456
+ if args.format == "json":
457
+ print(json.dumps({"success": False, "step": "init_project", "error": f"script exited with code {proc.returncode}"}))
458
+ else:
459
+ print(f"āŒ {script} exited with code {proc.returncode}")
460
+ return proc.returncode
461
+
462
+ _mark_step(root, "init_project", "completed")
463
+ if args.format == "json":
464
+ print(json.dumps({"success": True, "step": "init_project"}))
465
+ else:
466
+ print("āœ… Project initialization complete.")
467
+ return 0
468
+
469
+
470
+ def run_mark_step(args: argparse.Namespace) -> int:
471
+ """Record a setup step status in .context/lc-setup-state.yaml."""
472
+ root = Path(args.root).resolve()
473
+ _mark_step(root, args.step, args.status)
474
+ print(f"āœ… Marked step '{args.step}' as '{args.status}'.")
475
+ return 0
476
+
477
+
478
+ def run_is_setup_complete(args: argparse.Namespace) -> int:
479
+ """Exit 0 when all required setup steps are marked completed."""
480
+ root = Path(args.root).resolve()
481
+ if is_setup_complete(root):
482
+ print("āœ… Lincoln setup is complete.")
483
+ return 0
484
+ print("ā³ Lincoln setup is not complete.")
485
+ return 1
486
+
487
+
488
+ def run_bootstrap(args: argparse.Namespace) -> int:
489
+ """Run the full setup flow: skills, CLIs, config, project init."""
490
+ root = Path(args.root).resolve()
491
+ print("šŸš€ Starting Lincoln bootstrap...\n")
492
+
493
+ # 1. Install skills (includes plugins declared as skill/plugin type).
494
+ print("==> Installing skills and plugins...")
495
+ code = run_install_skills(args)
496
+ if code != 0:
497
+ print("\nāš ļø Skill installation incomplete. Resolve the issues above and re-run bootstrap.")
498
+ return code
499
+
500
+ # 2. Install CLIs.
501
+ print("\n==> Installing CLI dependencies...")
502
+ code = run_install_clis(args)
503
+ if code != 0:
504
+ print("\nāš ļø CLI installation incomplete. Resolve the issues above and re-run bootstrap.")
505
+ return code
506
+
507
+ # 3. Initialize repo config.
508
+ print("\n==> Initializing repository configuration...")
509
+ code = run_init_repo_config(args)
510
+ if code != 0:
511
+ return code
512
+
513
+ # 4. Initialize project directories.
514
+ print("\n==> Initializing project...")
515
+ code = run_init_project(args)
516
+ if code != 0:
517
+ return code
518
+
519
+ # 5. Generate harness adapter artifacts (optional).
520
+ if getattr(args, "harness", None):
521
+ print("\n==> Generating harness adapter artifacts...")
522
+ code = run_generate_harness(args)
523
+ if code != 0:
524
+ return code
525
+
526
+ print("\nšŸŽ‰ Lincoln bootstrap completed.")
527
+ return 0
528
+
529
+
530
+ def _add_harness_args(p: argparse.ArgumentParser) -> None:
531
+ p.add_argument(
532
+ "--harness",
533
+ action="append",
534
+ default=None,
535
+ help="Generate harness adapter artifacts (codex|opencode; repeatable)",
536
+ )
537
+ p.add_argument("--project-dir", default=None, help="Target project dir (default: --root)")
538
+ p.add_argument("--home-dir", default=None, help="Target home dir (default: real home)")
539
+
540
+
541
+ def run_generate_harness(args: argparse.Namespace) -> int:
542
+ """Generate codex/opencode artifacts from .claude/ via harness manifests."""
543
+ root = Path(args.root).resolve()
544
+ project_dir = Path(args.project_dir).resolve() if args.project_dir else root
545
+ home_dir = Path(args.home_dir).resolve() if args.home_dir else Path.home()
546
+ harnesses = args.harness or []
547
+ results = []
548
+ for name in harnesses:
549
+ try:
550
+ if getattr(args, "dry_run", False):
551
+ if args.format != "json":
552
+ print(f"[dry-run] would generate harness '{name}' into {project_dir} / {home_dir}")
553
+ results.append({"harness": name, "written": [], "dry_run": True})
554
+ continue
555
+ written = lincoln_harness_adapter.generate(root, name, project_dir, home_dir)
556
+ written_str = [str(path) for path in written]
557
+ if args.format != "json":
558
+ print(f"āœ… Harness '{name}': {len(written_str)} artifacts generated.")
559
+ for path in written_str:
560
+ print(f" - {path}")
561
+ results.append({"harness": name, "written": written_str})
562
+ except lincoln_harness_adapter.HarnessAdapterError as exc:
563
+ if args.format != "json":
564
+ print(f"āŒ Harness '{name}' failed: {exc}", file=sys.stderr)
565
+ results.append({"harness": name, "written": [], "error": str(exc)})
566
+ return 2
567
+ if args.format == "json":
568
+ print(json.dumps(results))
569
+ return 0
570
+
571
+
572
+ def _add_common_args(p: argparse.ArgumentParser) -> None:
573
+ """Add flags that every subcommand understands."""
574
+ p.add_argument("--root", default=".", help="Project root directory (default: current dir)")
575
+ p.add_argument("--yes", action="store_true", help="Auto-confirm all installations")
576
+ p.add_argument("--dry-run", action="store_true", help="Show what would be done without executing")
577
+ p.add_argument("--offline-cache", default=None, help="Directory with cached skill clones")
578
+ p.add_argument(
579
+ "--format",
580
+ choices=("human", "json"),
581
+ default="human",
582
+ help="Output format (default: human)",
583
+ )
584
+
585
+
586
+ def main(args: list[str] | None = None) -> int:
587
+ parser = argparse.ArgumentParser(
588
+ prog="lc-setup",
589
+ description="Lincoln dependency and configuration setup backend.",
590
+ )
591
+
592
+ subparsers = parser.add_subparsers(dest="command", required=True)
593
+
594
+ check_p = subparsers.add_parser("check", help="Check declared dependencies")
595
+ _add_common_args(check_p)
596
+
597
+ skills_p = subparsers.add_parser("install-skills", help="Install missing skills and plugins")
598
+ _add_common_args(skills_p)
599
+
600
+ clis_p = subparsers.add_parser("install-clis", help="Install missing CLI dependencies")
601
+ _add_common_args(clis_p)
602
+
603
+ init_p = subparsers.add_parser("init-repo-config", help="Initialize .github/openspec-config.yml")
604
+ _add_common_args(init_p)
605
+ init_p.add_argument("--owner", default=None, help="GitHub repository owner")
606
+ init_p.add_argument("--name", default=None, help="GitHub repository name")
607
+ init_p.add_argument("--branch", default="main", help="Default branch (default: main)")
608
+
609
+ project_p = subparsers.add_parser("init-project", help="Run scripts/init-project.sh")
610
+ _add_common_args(project_p)
611
+
612
+ mark_p = subparsers.add_parser("mark-step", help="Mark a setup step status")
613
+ _add_common_args(mark_p)
614
+ mark_p.add_argument("--step", required=True, help="Step name")
615
+ mark_p.add_argument("--status", default="completed", help="Step status")
616
+
617
+ complete_p = subparsers.add_parser("is-setup-complete", help="Exit 0 if setup is complete")
618
+ _add_common_args(complete_p)
619
+
620
+ boot_p = subparsers.add_parser("bootstrap", help="Run the full setup flow")
621
+ _add_common_args(boot_p)
622
+ boot_p.add_argument("--owner", default=None, help="GitHub repository owner")
623
+ boot_p.add_argument("--name", default=None, help="GitHub repository name")
624
+ boot_p.add_argument("--branch", default="main", help="Default branch (default: main)")
625
+ _add_harness_args(boot_p)
626
+
627
+ harness_p = subparsers.add_parser(
628
+ "generate-harness", help="Generate codex/opencode adapter artifacts"
629
+ )
630
+ _add_common_args(harness_p)
631
+ _add_harness_args(harness_p)
632
+
633
+ parsed = parser.parse_args(args)
634
+
635
+ handlers = {
636
+ "check": run_check,
637
+ "install-skills": run_install_skills,
638
+ "install-clis": run_install_clis,
639
+ "init-repo-config": run_init_repo_config,
640
+ "init-project": run_init_project,
641
+ "mark-step": run_mark_step,
642
+ "is-setup-complete": run_is_setup_complete,
643
+ "bootstrap": run_bootstrap,
644
+ "generate-harness": run_generate_harness,
645
+ }
646
+
647
+ return handlers[parsed.command](parsed)
648
+
649
+
650
+ if __name__ == "__main__":
651
+ sys.exit(main())