@sushanglewis/lincoln 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/dist/main.d.ts +3 -0
  2. package/dist/main.js +1231 -906
  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,4 @@
1
+ # Lincoln runtime dependencies for scripts/
2
+ pyyaml>=6.0
3
+ pytest>=7.0
4
+ jsonschema>=4.0
File without changes
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env python3
2
+ """Scan a codebase and emit a machine-readable feature map."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+
12
+ DEFAULT_SOURCE_DIRS = ("products", "src", "lib", "app", "packages", "server", "client")
13
+ IGNORE_DIRS = {".git", "node_modules", ".venv", "venv", "__pycache__", "dist", "build"}
14
+ SOURCE_EXTENSIONS = {".py", ".ts", ".js", ".tsx", ".go", ".rs"}
15
+
16
+
17
+ def find_source_root(root: Path) -> Path | None:
18
+ for candidate in DEFAULT_SOURCE_DIRS:
19
+ path = root / candidate
20
+ if path.is_dir():
21
+ return path
22
+ if any(
23
+ p.suffix in SOURCE_EXTENSIONS for p in root.iterdir() if p.is_file()
24
+ ):
25
+ return root
26
+ return None
27
+
28
+
29
+ def scan_features(root: Path, max_features: int = 10) -> dict[str, Any]:
30
+ root = root.resolve()
31
+ source_root = find_source_root(root)
32
+ features: list[dict[str, Any]] = []
33
+
34
+ if source_root:
35
+ for child in sorted(source_root.iterdir()):
36
+ if not child.is_dir() or child.name in IGNORE_DIRS:
37
+ continue
38
+ scan_root = child
39
+ if source_root.name == "products":
40
+ nested_source = find_source_root(child)
41
+ if nested_source:
42
+ scan_root = nested_source
43
+ entry_points = sorted(
44
+ p.relative_to(root)
45
+ for p in scan_root.rglob("*")
46
+ if p.is_file() and p.suffix in SOURCE_EXTENSIONS
47
+ )[:5]
48
+ features.append(
49
+ {
50
+ "name": child.name,
51
+ "path": str(child.relative_to(root)),
52
+ "entry_points": [str(ep) for ep in entry_points],
53
+ "has_tests": (root / "tests" / child.name).exists(),
54
+ }
55
+ )
56
+ if len(features) >= max_features:
57
+ break
58
+
59
+ return {
60
+ "root": str(root),
61
+ "source_root": str(source_root) if source_root else None,
62
+ "features": features,
63
+ }
64
+
65
+
66
+ def main() -> None:
67
+ parser = argparse.ArgumentParser(description="Build a feature map from an existing codebase.")
68
+ parser.add_argument("--root", default=".", help="Project root")
69
+ parser.add_argument("--max-features", type=int, default=10, help="Maximum features to emit")
70
+ args = parser.parse_args()
71
+ result = scan_features(Path(args.root), max_features=args.max_features)
72
+ print(json.dumps(result, indent=2, ensure_ascii=False))
73
+
74
+
75
+ if __name__ == "__main__":
76
+ main()
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ """版本锁步工具(#68:借鉴 superpowers 的 plugin/marketplace 版本漂移教训)。
3
+
4
+ `.version-bump.json` 是版本号唯一事实源,用 RFC 6901 JSON Pointer 列出所有
5
+ 携带版本号的 manifest 位置。用法:
6
+
7
+ python3 scripts/bump_version.py bump 1.3.0 # 锁步更新事实源与所有 manifest
8
+ python3 scripts/bump_version.py --check # CI:验证所有 manifest 与事实源一致
9
+ python3 scripts/bump_version.py --audit 1.2.0 # 发布前:列出残留的旧版本引用
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import re
16
+ import subprocess
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ ROOT = Path(__file__).resolve().parents[1]
21
+ SEMVER = re.compile(r"^\d+\.\d+\.\d+$")
22
+
23
+ # audit 模式中合理保留旧版本号的位置(历史记录,不是漂移);
24
+ # package-lock 内依赖自身版本号易误报,其产品版本由 bump 按 pointer 精确维护
25
+ AUDIT_EXCLUDES = (
26
+ ":!RELEASE.md",
27
+ ":!knowledge",
28
+ ":!issue-*",
29
+ ":!.context",
30
+ ":!tools/lincoln/package-lock.json",
31
+ )
32
+
33
+
34
+ def load_source(root: Path) -> dict:
35
+ source = root / ".version-bump.json"
36
+ if not source.exists():
37
+ sys.exit("missing version source: .version-bump.json")
38
+ data = json.loads(source.read_text(encoding="utf-8"))
39
+ if not SEMVER.match(data.get("version", "")):
40
+ sys.exit(f".version-bump.json has invalid version: {data.get('version')!r}")
41
+ return data
42
+
43
+
44
+ def parse_pointer(pointer: str) -> list[str]:
45
+ if not pointer.startswith("/"):
46
+ raise ValueError(f"pointer must start with '/': {pointer!r}")
47
+ return [t.replace("~1", "/").replace("~0", "~") for t in pointer.split("/")[1:]]
48
+
49
+
50
+ def resolve(container, tokens: list[str]):
51
+ """沿 pointer tokens 走到末段的父容器,返回 (父容器, 末段 key)。"""
52
+ node = container
53
+ for token in tokens[:-1]:
54
+ node = node[int(token)] if isinstance(node, list) else node[token]
55
+ last = tokens[-1]
56
+ return node, int(last) if isinstance(node, list) else last
57
+
58
+
59
+ def iter_versions(data: dict, root: Path):
60
+ """yield (manifest_path, pointer, current_value);manifest 缺失即失败。"""
61
+ for manifest in data["manifests"]:
62
+ path = root / manifest["path"]
63
+ if not path.exists():
64
+ sys.exit(f"manifest listed in .version-bump.json is missing: {manifest['path']}")
65
+ doc = json.loads(path.read_text(encoding="utf-8"))
66
+ for pointer in manifest["pointers"]:
67
+ parent, key = resolve(doc, parse_pointer(pointer))
68
+ yield manifest["path"], pointer, parent[key]
69
+
70
+
71
+ def cmd_check(data: dict, root: Path) -> int:
72
+ expected = data["version"]
73
+ drift = [
74
+ f" {path}{pointer}: {value!r} != {expected!r}"
75
+ for path, pointer, value in iter_versions(data, root)
76
+ if value != expected
77
+ ]
78
+ if drift:
79
+ print("version drift detected:", file=sys.stderr)
80
+ print("\n".join(drift), file=sys.stderr)
81
+ print(f"fix: python3 scripts/bump_version.py bump {expected}", file=sys.stderr)
82
+ return 1
83
+ print(f"version lockstep OK: {expected} ({len(data['manifests'])} manifests)")
84
+ return 0
85
+
86
+
87
+ def cmd_bump(data: dict, root: Path, new_version: str, dry_run: bool = False) -> int:
88
+ if not SEMVER.match(new_version):
89
+ sys.exit(f"invalid semver (want X.Y.Z): {new_version!r}")
90
+ old_version = data["version"]
91
+ for manifest in data["manifests"]:
92
+ path = root / manifest["path"]
93
+ doc = json.loads(path.read_text(encoding="utf-8"))
94
+ for pointer in manifest["pointers"]:
95
+ parent, key = resolve(doc, parse_pointer(pointer))
96
+ parent[key] = new_version
97
+ if dry_run:
98
+ print(f" would bump {manifest['path']}")
99
+ else:
100
+ path.write_text(
101
+ json.dumps(doc, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
102
+ )
103
+ print(f" bumped {manifest['path']}")
104
+ data["version"] = new_version
105
+ if dry_run:
106
+ print(f"would bump .version-bump.json {old_version} -> {new_version}")
107
+ else:
108
+ (root / ".version-bump.json").write_text(
109
+ json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
110
+ )
111
+ print(f"bumped {old_version} -> {new_version}")
112
+
113
+ # Keep harness artifacts in lockstep with the bumped version.
114
+ adapter = root / "scripts" / "lincoln_harness_adapter.py"
115
+ if adapter.exists():
116
+ for harness in ("codex", "opencode"):
117
+ artifact = root / ".claude" / "harnesses" / f"{harness}.yaml"
118
+ if not artifact.exists():
119
+ continue
120
+ if dry_run:
121
+ print(f" would regenerate harness {harness}.yaml")
122
+ continue
123
+ result = subprocess.run(
124
+ [sys.executable, str(adapter), "--harness", harness],
125
+ cwd=root,
126
+ capture_output=True,
127
+ text=True,
128
+ )
129
+ if result.returncode != 0:
130
+ print(result.stderr, file=sys.stderr)
131
+ sys.exit(f"harness generation failed for {harness}")
132
+ print(f" regenerated harness {harness}.yaml")
133
+
134
+ if dry_run:
135
+ print(f"next (dry run complete): review changes, then run bump {new_version}")
136
+ else:
137
+ print(f"next: python3 scripts/bump_version.py --audit {old_version}")
138
+ return 0
139
+
140
+
141
+ def cmd_audit(root: Path, old_version: str) -> int:
142
+ if not SEMVER.match(old_version):
143
+ sys.exit(f"invalid semver (want X.Y.Z): {old_version!r}")
144
+ result = subprocess.run(
145
+ ["git", "grep", "-n", "-F", old_version, "--", ".", *AUDIT_EXCLUDES],
146
+ cwd=root,
147
+ capture_output=True,
148
+ text=True,
149
+ )
150
+ if result.returncode not in (0, 1):
151
+ sys.exit(f"git grep failed: {result.stderr.strip()}")
152
+ if result.returncode == 1:
153
+ print(f"audit OK: no stale {old_version} references")
154
+ return 0
155
+ print(f"stale {old_version} references (review each; RELEASE.md/knowledge 等历史记录已排除):")
156
+ print(result.stdout, end="")
157
+ return 1
158
+
159
+
160
+ def main(argv: list[str], root: Path = ROOT) -> int:
161
+ raw_args = argv[1:]
162
+ dry_run = "--dry-run" in raw_args
163
+ args = [a for a in raw_args if a != "--dry-run"]
164
+
165
+ if dry_run and not (len(args) == 2 and args[0] == "bump"):
166
+ print("--dry-run can only be used with 'bump X.Y.Z'", file=sys.stderr)
167
+ print(__doc__, file=sys.stderr)
168
+ return 2
169
+
170
+ if args == ["--check"]:
171
+ return cmd_check(load_source(root), root)
172
+ if len(args) == 2 and args[0] == "bump":
173
+ return cmd_bump(load_source(root), root, args[1], dry_run=dry_run)
174
+ if len(args) == 2 and args[0] == "--audit":
175
+ return cmd_audit(root, args[1])
176
+ print(__doc__, file=sys.stderr)
177
+ return 2
178
+
179
+
180
+ if __name__ == "__main__":
181
+ sys.exit(main(sys.argv))
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ """Check upstream drift for pinned external skill dependencies (#62).
3
+
4
+ Compares each git-sourced skill/plugin's pinned `ref` in
5
+ `.claude/skills/dependencies.yaml` against the current upstream branch head
6
+ (`pinned_from`, default `main`). Prints a report; exits 1 when any dependency
7
+ has drifted (i.e. an upgrade review is due), 0 when all pins are current.
8
+
9
+ This tool needs network access and is run manually (or from scheduled jobs),
10
+ never from the offline test suite.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import subprocess
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ import yaml
20
+
21
+ ROOT = Path(__file__).resolve().parents[1]
22
+ DEPENDENCIES = ROOT / ".claude" / "skills" / "dependencies.yaml"
23
+ GIT_SOURCE_PREFIXES = ("http://", "https://", "git@")
24
+
25
+
26
+ def upstream_head(source: str, branch: str) -> str | None:
27
+ proc = subprocess.run(
28
+ ["git", "ls-remote", source, branch],
29
+ capture_output=True,
30
+ text=True,
31
+ timeout=60,
32
+ )
33
+ if proc.returncode != 0 or not proc.stdout.strip():
34
+ return None
35
+ return proc.stdout.split()[0]
36
+
37
+
38
+ def main() -> int:
39
+ data = yaml.safe_load(DEPENDENCIES.read_text(encoding="utf-8"))
40
+ drifted = False
41
+ for name, dep in data.get("skills", {}).items():
42
+ if dep.get("type") not in ("skill", "plugin"):
43
+ continue
44
+ source = str(dep.get("source", ""))
45
+ if not source.startswith(GIT_SOURCE_PREFIXES):
46
+ continue
47
+ ref = str(dep.get("ref", ""))
48
+ branch = str(dep.get("pinned_from", "main"))
49
+ try:
50
+ head = upstream_head(source, branch)
51
+ except (subprocess.TimeoutExpired, OSError) as exc:
52
+ print(f"WARN {name}: upstream check failed ({exc}); skipped")
53
+ continue
54
+ if head is None:
55
+ print(f"WARN {name}: cannot resolve {branch} at {source}; skipped")
56
+ continue
57
+ if head == ref:
58
+ print(f"OK {name}: pinned at {ref[:12]} (current {branch})")
59
+ else:
60
+ drifted = True
61
+ print(
62
+ f"DRIFT {name}: pinned {ref[:12]}, upstream {branch} is {head[:12]}"
63
+ " — review upstream changes, run the benchmark, then update the pin"
64
+ )
65
+ return 1 if drifted else 0
66
+
67
+
68
+ if __name__ == "__main__":
69
+ sys.exit(main())
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ # Harness drift check (CI-friendly, lightweight):
3
+ # 1. Regenerate codex/opencode artifacts into a temp dir — proves manifests
4
+ # load and generation succeeds (catches broken sources / bad manifests).
5
+ # 2. If generated artifacts already exist in the project (someone ran
6
+ # generate-harness locally), verify they have not drifted from .claude/.
7
+ set -uo pipefail
8
+
9
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
10
+ cd "$ROOT"
11
+
12
+ if [ -d "$ROOT/.venv" ] && [ -x "$ROOT/.venv/bin/python3" ]; then
13
+ PYTHON="$ROOT/.venv/bin/python3"
14
+ else
15
+ PYTHON="python3"
16
+ fi
17
+
18
+ FAIL=0
19
+ TMP="$(mktemp -d)"
20
+ trap 'rm -rf "$TMP"' EXIT
21
+ mkdir -p "$TMP/project" "$TMP/home"
22
+
23
+ for HARNESS in codex opencode; do
24
+ echo "==> Harness smoke generation: $HARNESS"
25
+ if ! "$PYTHON" scripts/lincoln_harness_adapter.py \
26
+ --harness "$HARNESS" --root "$ROOT" \
27
+ --project-dir "$TMP/project" --home-dir "$TMP/home" > /dev/null; then
28
+ echo "❌ generation failed for harness: $HARNESS"
29
+ FAIL=1
30
+ continue
31
+ fi
32
+
33
+ # Drift comparison only when artifacts were generated into the project.
34
+ case "$HARNESS" in
35
+ opencode) MARKER="$ROOT/.opencode" ;;
36
+ codex)
37
+ if [ -e "$ROOT/.codex-plugin" ]; then
38
+ MARKER="$ROOT/.codex-plugin"
39
+ else
40
+ MARKER="$ROOT/AGENTS.md"
41
+ fi
42
+ ;;
43
+ esac
44
+ if [ -e "$MARKER" ]; then
45
+ echo "==> Drift check: $HARNESS (project artifacts present)"
46
+ if ! "$PYTHON" scripts/lincoln_harness_adapter.py \
47
+ --harness "$HARNESS" --root "$ROOT" \
48
+ --project-dir "$ROOT" --home-dir "$HOME" --check; then
49
+ FAIL=1
50
+ fi
51
+ fi
52
+ done
53
+
54
+ if [ "$FAIL" -eq 0 ]; then
55
+ echo "✅ harness drift check passed"
56
+ fi
57
+ exit "$FAIL"
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env python3
2
+ """Reject branch-only Lincoln process artifacts from main-bound PRs."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
12
+ from scripts.lincoln_paths import RESERVED_PROCESS_DIRS, STATE_FILENAME
13
+
14
+ ROOT = Path(__file__).resolve().parents[1]
15
+
16
+
17
+ ROOT_PROCESS_DIRS = {
18
+ "designs",
19
+ "interviews",
20
+ "recordings",
21
+ "requirements",
22
+ }
23
+
24
+ PROCESS_SUBPATHS = {
25
+ "designs",
26
+ "docs/research",
27
+ "handoffs",
28
+ "interviews",
29
+ "openspec/changes",
30
+ "recordings",
31
+ "requirements",
32
+ }
33
+
34
+ ALLOWED_ROOT_PREFIXES = (
35
+ ".claude/",
36
+ ".claude-plugin/",
37
+ ".conductor/",
38
+ ".github/",
39
+ "CLAUDE.md",
40
+ "LICENSE",
41
+ "README.md",
42
+ "RELEASE.md",
43
+ "knowledge/",
44
+ "oss/README.md",
45
+ "oss/projects.yaml",
46
+ "products/",
47
+ "requirements.txt",
48
+ "scripts/",
49
+ "tests/",
50
+ "tools/",
51
+ )
52
+
53
+
54
+ def changed_paths(base: str) -> list[str]:
55
+ result = subprocess.run(
56
+ ["git", "diff", "--name-only", f"{base}...HEAD"],
57
+ capture_output=True,
58
+ text=True,
59
+ check=False,
60
+ )
61
+ if result.returncode != 0:
62
+ return []
63
+ return [line.strip() for line in result.stdout.splitlines() if line.strip()]
64
+
65
+
66
+ def is_process_package_dir(top_dir: str) -> bool:
67
+ """A directory is a Lincoln process package if it contains workflow-stage.yaml."""
68
+ if top_dir in RESERVED_PROCESS_DIRS or top_dir in ROOT_PROCESS_DIRS:
69
+ return False
70
+ return (ROOT / top_dir / STATE_FILENAME).is_file()
71
+
72
+
73
+ def is_process_package_path(path: str) -> bool:
74
+ parts = Path(path).parts
75
+ if not parts:
76
+ return False
77
+ top = parts[0]
78
+ if top in RESERVED_PROCESS_DIRS or top in ROOT_PROCESS_DIRS:
79
+ return False
80
+ # Reject every file inside a process package directory, not only known subpaths.
81
+ if is_process_package_dir(top):
82
+ return True
83
+ if len(parts) == 2 and parts[1] == "workflow-stage.yaml":
84
+ return True
85
+ rest = "/".join(parts[1:])
86
+ return any(rest == sub or rest.startswith(f"{sub}/") for sub in PROCESS_SUBPATHS)
87
+
88
+
89
+ def is_root_process_artifact(path: str) -> bool:
90
+ return any(path.startswith(f"{prefix}/") for prefix in ROOT_PROCESS_DIRS) or path.startswith("openspec/changes/") or path.startswith("docs/research/")
91
+
92
+
93
+ def allowed_durable_path(path: str) -> bool:
94
+ return any(path == prefix.rstrip("/") or path.startswith(prefix) for prefix in ALLOWED_ROOT_PREFIXES)
95
+
96
+
97
+ def violations(paths: list[str]) -> list[str]:
98
+ rejected: list[str] = []
99
+ for path in paths:
100
+ if is_process_package_path(path) or is_root_process_artifact(path):
101
+ rejected.append(path)
102
+ continue
103
+ if path.startswith("oss/clones/"):
104
+ rejected.append(path)
105
+ return rejected
106
+
107
+
108
+ def main() -> int:
109
+ parser = argparse.ArgumentParser(description="Check Lincoln main merge hygiene")
110
+ parser.add_argument("--base", default="origin/main")
111
+ parser.add_argument("--path", action="append", dest="paths", help="Changed path to check; repeatable")
112
+ args = parser.parse_args()
113
+
114
+ paths = args.paths if args.paths is not None else changed_paths(args.base)
115
+ bad = violations(paths)
116
+ if bad:
117
+ print("FAIL: branch-only Lincoln process artifacts must not merge to main:")
118
+ for path in bad:
119
+ print(f" - {path}")
120
+ print("Move durable knowledge to knowledge/ and keep process work in the feature branch.")
121
+ return 1
122
+
123
+ print("PASS: no branch-only Lincoln process artifacts detected.")
124
+ return 0
125
+
126
+
127
+ if __name__ == "__main__":
128
+ sys.exit(main())
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Check Lincoln skill/CLI dependencies.
5
+ # Usage:
6
+ # scripts/check-skill-dependencies.sh
7
+ # scripts/check-skill-dependencies.sh --silent
8
+
9
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
10
+ cd "$ROOT"
11
+
12
+ PYTHON="${PYTHON:-python3}"
13
+ SILENT=false
14
+ if [[ "${1:-}" == "--silent" ]]; then
15
+ SILENT=true
16
+ fi
17
+
18
+ DEP_FILE="$ROOT/.claude/skills/dependencies.yaml"
19
+ LEGACY_DEP_FILE="$ROOT/.claude/skill-dependencies.yaml"
20
+ if [[ ! -f "$DEP_FILE" && -f "$LEGACY_DEP_FILE" ]]; then
21
+ DEP_FILE="$LEGACY_DEP_FILE"
22
+ fi
23
+
24
+ if [[ "$SILENT" == false ]]; then
25
+ echo "==> Validate $(basename "$DEP_FILE")"
26
+ fi
27
+ "$PYTHON" -c "import yaml; yaml.safe_load(open('$DEP_FILE'))"
28
+
29
+ if [[ "$SILENT" == false ]]; then
30
+ echo "==> Check declared skills and CLIs"
31
+ fi
32
+
33
+ "$PYTHON" - "$ROOT" "$DEP_FILE" "$SILENT" <<'PY'
34
+ import sys
35
+ import shutil
36
+ import platform
37
+ from pathlib import Path
38
+ import yaml
39
+
40
+ root = Path(sys.argv[1])
41
+ dep_file = Path(sys.argv[2])
42
+ silent = sys.argv[3].lower() == "true"
43
+
44
+ manifest = yaml.safe_load(dep_file.read_text(encoding="utf-8"))
45
+
46
+ skill_root = Path.home() / ".claude" / "skills"
47
+ errors = []
48
+ warnings = []
49
+ install_commands = []
50
+
51
+ system = platform.system().lower()
52
+ if system == "darwin":
53
+ platform_name = "macos"
54
+ elif system == "linux":
55
+ platform_name = "linux"
56
+ else:
57
+ platform_name = system
58
+
59
+ def get_install_command(cfg):
60
+ if "platforms" in cfg and isinstance(cfg["platforms"], dict):
61
+ if platform_name in cfg["platforms"]:
62
+ return cfg["platforms"][platform_name]
63
+ if "linux" in cfg["platforms"]:
64
+ return cfg["platforms"]["linux"]
65
+ return cfg.get("install")
66
+
67
+ for name, cfg in manifest.get("skills", {}).items():
68
+ typ = cfg.get("type", "skill")
69
+ is_required = cfg.get("required", True)
70
+ source = cfg.get("source", "")
71
+ if typ == "cli":
72
+ binary = cfg.get("binary", name)
73
+ if not shutil.which(binary):
74
+ msg = f"CLI missing: {binary} (skill: {name})"
75
+ cmd = get_install_command(cfg)
76
+ if cmd:
77
+ install_commands.append(f"# Install {name}: {cmd}")
78
+ if is_required:
79
+ errors.append(msg)
80
+ else:
81
+ warnings.append(msg)
82
+ else:
83
+ path = cfg.get("path")
84
+ if path:
85
+ expected = root / path / "SKILL.md"
86
+ else:
87
+ expected = skill_root / name / "SKILL.md"
88
+ if not expected.exists():
89
+ msg = f"Skill missing: {name} (expected {expected})"
90
+ if source and source != "inline":
91
+ ref = cfg.get("ref", "")
92
+ ref_arg = f" --branch {ref}" if ref else ""
93
+ install_commands.append(f"# Install {name}: git clone{ref_arg} --single-branch --depth 1 {source} {skill_root / name}")
94
+ if is_required:
95
+ errors.append(msg)
96
+ else:
97
+ warnings.append(msg)
98
+
99
+ if warnings and not silent:
100
+ print("Optional dependencies missing (warnings only):")
101
+ for w in warnings:
102
+ print(f" - {w}")
103
+
104
+ if errors and not silent:
105
+ print("Required dependencies missing:")
106
+ for e in errors:
107
+ print(f" - {e}")
108
+
109
+ if install_commands and not silent:
110
+ print("")
111
+ print("Suggested installation commands:")
112
+ for cmd in install_commands:
113
+ print(f" {cmd}")
114
+
115
+ if errors:
116
+ sys.exit(1)
117
+
118
+ if not silent:
119
+ print("All declared skills/CLIs are present.")
120
+ PY
121
+
122
+ if [[ "$SILENT" == false ]]; then
123
+ echo "==> All skill dependencies satisfied"
124
+ fi