@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,340 @@
1
+ #!/usr/bin/env python3
2
+ """Deterministic packaging for the Lincoln plugin (#68).
3
+
4
+ Builds a reproducible distribution archive from an explicit allowlist, rejects
5
+ dirty worktrees, regenerates harness artifacts after version bumps, and emits a
6
+ SHA256 checksum. Does not upload to any marketplace or registry.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import hashlib
13
+ import json
14
+ import os
15
+ import shutil
16
+ import subprocess
17
+ import sys
18
+ import tarfile
19
+ import zipfile
20
+ from datetime import datetime, timezone
21
+ from pathlib import Path
22
+ from typing import Iterable
23
+
24
+ ROOT = Path(__file__).resolve().parents[1]
25
+
26
+ ALLOWLIST_DIRS = (".claude", ".claude-plugin", "scripts", "tools")
27
+ ALLOWLIST_FILES = (
28
+ "README.md",
29
+ "README.en.md",
30
+ "USAGE.md",
31
+ "CONTRIBUTING.md",
32
+ "CLAUDE.md",
33
+ "LICENSE",
34
+ "RELEASE.md",
35
+ ".version-bump.json",
36
+ "requirements.txt",
37
+ "SKILL.md",
38
+ )
39
+ DENYLIST_NAMES = {
40
+ ".git",
41
+ ".context",
42
+ ".venv",
43
+ "venv",
44
+ "dist",
45
+ "oss",
46
+ ".pytest_cache",
47
+ "__pycache__",
48
+ ".DS_Store",
49
+ "node_modules",
50
+ }
51
+ DENYLIST_PREFIXES = ("issue-",)
52
+ SKIP_PATHS = (
53
+ ".claude/templates/issue-package",
54
+ "tools/lincoln-installer/dist",
55
+ "tools/lincoln-installer/node_modules",
56
+ "tools/lincoln-installer/coverage",
57
+ )
58
+
59
+
60
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
61
+ parser = argparse.ArgumentParser(
62
+ description="Build or validate a deterministic Lincoln plugin package."
63
+ )
64
+ parser.add_argument(
65
+ "--root",
66
+ type=Path,
67
+ default=ROOT,
68
+ help="Repository root (default: repository containing this script).",
69
+ )
70
+ subparsers = parser.add_subparsers(dest="command", required=True)
71
+
72
+ pkg = subparsers.add_parser("package", help="Build the distribution archive.")
73
+ pkg.add_argument(
74
+ "--output-dir",
75
+ type=Path,
76
+ default=Path("dist"),
77
+ help="Output directory for the archive and checksum.",
78
+ )
79
+ pkg.add_argument(
80
+ "--format",
81
+ choices=("tgz", "zip"),
82
+ default="tgz",
83
+ help="Archive format (default: tgz).",
84
+ )
85
+ pkg.add_argument(
86
+ "--force-harness",
87
+ action="store_true",
88
+ help="Regenerate harness artifacts even if they already exist.",
89
+ )
90
+
91
+ chk = subparsers.add_parser(
92
+ "check", help="Validate allowlist/denylist without building."
93
+ )
94
+ chk.add_argument(
95
+ "--check-dirty",
96
+ action="store_true",
97
+ help="Also reject dirty worktrees in check mode.",
98
+ )
99
+
100
+ return parser.parse_args(argv)
101
+
102
+
103
+ def load_version(root: Path) -> str:
104
+ source = root / ".version-bump.json"
105
+ if not source.exists():
106
+ sys.exit("missing version source: .version-bump.json")
107
+ data = json.loads(source.read_text(encoding="utf-8"))
108
+ version = data.get("version", "")
109
+ if not (isinstance(version, str) and len(version.split(".")) == 3):
110
+ sys.exit(f".version-bump.json has invalid version: {version!r}")
111
+ return version
112
+
113
+
114
+ def is_dirty(root: Path) -> bool:
115
+ """Return True if the working tree has uncommitted tracked changes."""
116
+ for diff_flag in ("--quiet", "--cached", "--quiet"):
117
+ result = subprocess.run(
118
+ ["git", "diff", diff_flag, "HEAD"],
119
+ cwd=root,
120
+ capture_output=True,
121
+ )
122
+ if result.returncode != 0:
123
+ return True
124
+ return False
125
+
126
+
127
+ def git_head_timestamp(root: Path) -> int:
128
+ """Return the Unix timestamp of HEAD for reproducible archives."""
129
+ result = subprocess.run(
130
+ ["git", "log", "-1", "--format=%ct"],
131
+ cwd=root,
132
+ capture_output=True,
133
+ text=True,
134
+ )
135
+ if result.returncode != 0 or not result.stdout.strip():
136
+ env_epoch = os.environ.get("SOURCE_DATE_EPOCH", "")
137
+ if env_epoch.isdigit():
138
+ return int(env_epoch)
139
+ return 0
140
+ return int(result.stdout.strip())
141
+
142
+
143
+ def regenerate_harness(root: Path, force: bool) -> None:
144
+ """Regenerate codex/opencode harness artifacts if they exist or force=True."""
145
+ adapter = root / "scripts" / "lincoln_harness_adapter.py"
146
+ any_artifact = any(
147
+ (root / ".claude" / "harnesses" / f"{harness}.yaml").exists()
148
+ for harness in ("codex", "opencode")
149
+ )
150
+ if not adapter.exists():
151
+ if any_artifact:
152
+ sys.exit("missing harness adapter: scripts/lincoln_harness_adapter.py")
153
+ return
154
+
155
+ for harness in ("codex", "opencode"):
156
+ artifact = root / ".claude" / "harnesses" / f"{harness}.yaml"
157
+ if artifact.exists() and not force:
158
+ continue
159
+ print(f"Regenerating harness artifact: {artifact.relative_to(root)}")
160
+ result = subprocess.run(
161
+ [sys.executable, str(adapter), "--harness", harness],
162
+ cwd=root,
163
+ capture_output=True,
164
+ text=True,
165
+ )
166
+ if result.returncode != 0:
167
+ print(result.stderr, file=sys.stderr)
168
+ sys.exit(f"harness generation failed for {harness}")
169
+
170
+
171
+ def collect_sources(root: Path) -> Iterable[Path]:
172
+ """Yield every file that belongs in the package, validating the allowlist."""
173
+ for name in ALLOWLIST_DIRS:
174
+ src_dir = root / name
175
+ if not src_dir.exists():
176
+ sys.exit(f"allowlist directory missing: {name}")
177
+ for path in src_dir.rglob("*"):
178
+ if path.is_file():
179
+ yield path
180
+
181
+ for name in ALLOWLIST_FILES:
182
+ src_file = root / name
183
+ if not src_file.exists():
184
+ sys.exit(f"allowlist file missing: {name}")
185
+ yield src_file
186
+
187
+
188
+ def is_denylisted(relative: str) -> bool:
189
+ parts = Path(relative).parts
190
+ return any(
191
+ part in DENYLIST_NAMES or part.startswith(DENYLIST_PREFIXES)
192
+ for part in parts
193
+ )
194
+
195
+
196
+ def is_skipped(relative: str) -> bool:
197
+ return any(relative.startswith(skip) for skip in SKIP_PATHS)
198
+
199
+
200
+ def clean_generated(root: Path) -> None:
201
+ """Remove generated artifacts that should never be packaged."""
202
+ for name in ALLOWLIST_DIRS:
203
+ base = root / name
204
+ if not base.exists():
205
+ continue
206
+ for pycache in base.rglob("__pycache__"):
207
+ if pycache.is_dir():
208
+ shutil.rmtree(pycache, ignore_errors=True)
209
+ for ds_store in base.rglob(".DS_Store"):
210
+ if ds_store.is_file():
211
+ ds_store.unlink(missing_ok=True)
212
+
213
+
214
+ def validate_manifest(root: Path) -> None:
215
+ clean_generated(root)
216
+ version = load_version(root)
217
+ for src in collect_sources(root):
218
+ rel = str(src.relative_to(root))
219
+ if is_skipped(rel):
220
+ continue
221
+ if is_denylisted(rel):
222
+ sys.exit(f"denylist violation in package: {rel}")
223
+ print(f"Package manifest OK for version {version}")
224
+
225
+
226
+ def stage_package(root: Path, staging: Path) -> None:
227
+ """Copy allowlisted sources into a staging directory for archiving."""
228
+ clean_generated(root)
229
+ for src in collect_sources(root):
230
+ rel = src.relative_to(root)
231
+ if is_skipped(str(rel)) or is_denylisted(str(rel)):
232
+ continue
233
+ dst = staging / rel
234
+ dst.parent.mkdir(parents=True, exist_ok=True)
235
+ shutil.copy2(src, dst)
236
+
237
+
238
+ def archive_mtime(root: Path) -> int:
239
+ env = os.environ.get("SOURCE_DATE_EPOCH", "")
240
+ if env.isdigit():
241
+ return int(env)
242
+ return git_head_timestamp(root)
243
+
244
+
245
+ def archive_time_tuple(epoch: int) -> tuple[int, int, int, int, int, int]:
246
+ dt = datetime.fromtimestamp(epoch, tz=timezone.utc)
247
+ return (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
248
+
249
+
250
+ def build_tgz(root: Path, staging: Path, output: Path, epoch: int) -> None:
251
+ with tarfile.open(output, "w:gz") as tar:
252
+
253
+ def _reset(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo:
254
+ tarinfo.mtime = epoch
255
+ tarinfo.uid = tarinfo.gid = 0
256
+ tarinfo.uname = tarinfo.gname = ""
257
+ return tarinfo
258
+
259
+ tar.add(staging, arcname=f"lincoln-{load_version(root)}", filter=_reset)
260
+
261
+
262
+ def build_zip(root: Path, staging: Path, output: Path, epoch: int) -> None:
263
+ time_tuple = archive_time_tuple(epoch)
264
+ with zipfile.ZipFile(output, "w", zipfile.ZIP_DEFLATED) as zf:
265
+ for file_path in staging.rglob("*"):
266
+ if not file_path.is_file():
267
+ continue
268
+ arcname = (
269
+ f"lincoln-{load_version(root)}/{file_path.relative_to(staging)}"
270
+ )
271
+ zf.write(file_path, arcname)
272
+ # Normalize timestamps after writing (zipfile does not expose this easily)
273
+ info = zf.getinfo(arcname)
274
+ info.date_time = time_tuple
275
+
276
+
277
+ def write_checksum(output: Path) -> None:
278
+ sha256 = hashlib.sha256(output.read_bytes()).hexdigest()
279
+ checksum_file = output.with_suffix(output.suffix + ".sha256")
280
+ checksum_file.write_text(f"{sha256} {output.name}\n", encoding="utf-8")
281
+
282
+
283
+ def cmd_check(args: argparse.Namespace) -> int:
284
+ if args.check_dirty and is_dirty(args.root):
285
+ print("error: working tree has uncommitted changes", file=sys.stderr)
286
+ return 1
287
+ validate_manifest(args.root)
288
+ return 0
289
+
290
+
291
+ def cmd_package(args: argparse.Namespace) -> int:
292
+ if is_dirty(args.root):
293
+ print(
294
+ "error: refusing to package a dirty working tree. "
295
+ "Commit or stash changes first.",
296
+ file=sys.stderr,
297
+ )
298
+ return 1
299
+
300
+ regenerate_harness(args.root, args.force_harness)
301
+ validate_manifest(args.root)
302
+
303
+ output_dir = args.root / args.output_dir
304
+ output_dir.mkdir(parents=True, exist_ok=True)
305
+ version = load_version(args.root)
306
+ ext = "tar.gz" if args.format == "tgz" else "zip"
307
+ output = output_dir / f"lincoln-{version}.{ext}"
308
+
309
+ epoch = archive_mtime(args.root)
310
+
311
+ staging = args.root / ".context" / "package-staging"
312
+ if staging.exists():
313
+ shutil.rmtree(staging)
314
+ staging.mkdir(parents=True)
315
+
316
+ try:
317
+ stage_package(args.root, staging)
318
+ if args.format == "tgz":
319
+ build_tgz(args.root, staging, output, epoch)
320
+ else:
321
+ build_zip(args.root, staging, output, epoch)
322
+ write_checksum(output)
323
+ print(f"Packaged {output.relative_to(args.root)}")
324
+ print(f"Checksum {output.with_suffix(output.suffix + '.sha256').relative_to(args.root)}")
325
+ return 0
326
+ finally:
327
+ shutil.rmtree(staging, ignore_errors=True)
328
+
329
+
330
+ def main(argv: list[str] | None = None) -> int:
331
+ args = parse_args(argv)
332
+ if args.command == "check":
333
+ return cmd_check(args)
334
+ if args.command == "package":
335
+ return cmd_package(args)
336
+ return 2
337
+
338
+
339
+ if __name__ == "__main__":
340
+ sys.exit(main())
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env python3
2
+ """Run the deterministic infrastructure test suite (#67).
3
+
4
+ This script is the entry point for the CI `infrastructure-tests` job. It runs
5
+ only tests that do not depend on LLM calls, network access, or stochastic
6
+ behavior, so they can be used as a fast, reliable gate.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import subprocess
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ ROOT = Path(__file__).resolve().parents[1]
17
+
18
+ INFRASTRUCTURE_TESTS = [
19
+ "tests/test_yaml_schemas.py",
20
+ "tests/test_bump_version.py",
21
+ "tests/test_harness_default_off.py",
22
+ "tests/test_agent_contract.py",
23
+ "tests/test_session_start_shape.py",
24
+ "tests/test_hook_session_start.py",
25
+ "tests/test_infrastructure_layers.py",
26
+ "tests/test_benchmark_opt_in.py",
27
+ "tests/test_new_skills.py",
28
+ "tests/test_package_lincoln_plugin.py",
29
+ ]
30
+
31
+
32
+ def parse_args() -> argparse.Namespace:
33
+ parser = argparse.ArgumentParser(
34
+ description="Run Lincoln deterministic infrastructure tests."
35
+ )
36
+ parser.add_argument(
37
+ "--ci",
38
+ action="store_true",
39
+ help="Exit with non-zero status if any test fails.",
40
+ )
41
+ parser.add_argument(
42
+ "--collect-only",
43
+ action="store_true",
44
+ help="List the tests that would be run without executing them.",
45
+ )
46
+ parser.add_argument(
47
+ "pytest_args",
48
+ nargs="*",
49
+ help="Additional arguments to pass to pytest.",
50
+ )
51
+ return parser.parse_args()
52
+
53
+
54
+ def main() -> int:
55
+ args = parse_args()
56
+
57
+ missing = [t for t in INFRASTRUCTURE_TESTS if not (ROOT / t).exists()]
58
+ if missing:
59
+ print("Missing infrastructure test files:")
60
+ for m in missing:
61
+ print(f" - {m}")
62
+ return 1
63
+
64
+ if args.collect_only:
65
+ print("Infrastructure test suite:")
66
+ for t in INFRASTRUCTURE_TESTS:
67
+ print(f" {t}")
68
+ return 0
69
+
70
+ cmd = [
71
+ sys.executable,
72
+ "-m",
73
+ "pytest",
74
+ *INFRASTRUCTURE_TESTS,
75
+ "-v",
76
+ *(args.pytest_args or []),
77
+ ]
78
+ print(f"Running: {' '.join(cmd)}")
79
+ result = subprocess.run(cmd, cwd=ROOT)
80
+ return result.returncode
81
+
82
+
83
+ if __name__ == "__main__":
84
+ sys.exit(main())