@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.
- package/dist/main.d.ts +3 -0
- package/dist/main.js +1231 -906
- package/dist/main.js.map +1 -1
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.js +18 -0
- package/dist/postinstall.js.map +1 -0
- package/framework/.claude/agents/_contract.md +79 -0
- package/framework/.claude/agents/architect.md +31 -0
- package/framework/.claude/agents/default.md +151 -0
- package/framework/.claude/agents/designer.md +33 -0
- package/framework/.claude/agents/engineer.md +42 -0
- package/framework/.claude/agents/external/NOTICES.md +12 -0
- package/framework/.claude/agents/external/everything-claude-code.manifest.yaml +23 -0
- package/framework/.claude/agents/external/oh-my-claudecode.manifest.yaml +26 -0
- package/framework/.claude/agents/external/wshobson-agents.manifest.yaml +23 -0
- package/framework/.claude/agents/frontend-engineer.md +32 -0
- package/framework/.claude/agents/knowledge-curator.md +28 -0
- package/framework/.claude/agents/pm.md +38 -0
- package/framework/.claude/agents/qa.md +28 -0
- package/framework/.claude/agents/release-coordinator.md +25 -0
- package/framework/.claude/agents/researcher.md +41 -0
- package/framework/.claude/harnesses/claude-code.yaml +15 -0
- package/framework/.claude/harnesses/codex.yaml +40 -0
- package/framework/.claude/harnesses/command-map.yaml +255 -0
- package/framework/.claude/harnesses/opencode.yaml +32 -0
- package/framework/.claude/harnesses/scenarios.yaml +45 -0
- package/framework/.claude/hooks/on-pr-event.sh +69 -0
- package/framework/.claude/hooks/on-session-start.sh +427 -0
- package/framework/.claude/hooks/on-stop.sh +104 -0
- package/framework/.claude/hooks/post-tool-use.sh +161 -0
- package/framework/.claude/hooks/pre-tool-use.sh +246 -0
- package/framework/.claude/schemas/agent-definition.schema.json +35 -0
- package/framework/.claude/schemas/benchmark-report.schema.json +148 -0
- package/framework/.claude/schemas/pm-to-ux-handoff.schema.yaml +128 -0
- package/framework/.claude/schemas/stage-definition.schema.json +233 -0
- package/framework/.claude/schemas/workflow-stage.schema.json +86 -0
- package/framework/.claude/schemas/workflow-template.schema.json +88 -0
- package/framework/.claude/settings.json +14 -0
- package/framework/.claude/skills/build-product-prototype/SKILL.md +35 -0
- package/framework/.claude/skills/build-product-prototype/prompts/main.md +78 -0
- package/framework/.claude/skills/clarify-requirements/SKILL.md +32 -0
- package/framework/.claude/skills/clarify-requirements/prompts/main.md +81 -0
- package/framework/.claude/skills/dependencies.yaml +139 -0
- package/framework/.claude/skills/draft-product-design/SKILL.md +40 -0
- package/framework/.claude/skills/draft-product-design/prompts/main.md +47 -0
- package/framework/.claude/skills/lc-analyze-frameworks/SKILL.md +43 -0
- package/framework/.claude/skills/lc-analyze-frameworks/prompts/main.md +95 -0
- package/framework/.claude/skills/lc-benchmark/SKILL.md +61 -0
- package/framework/.claude/skills/lc-build-codebase-knowledge/SKILL.md +38 -0
- package/framework/.claude/skills/lc-build-codebase-knowledge/prompts/build-codebase-knowledge.md +61 -0
- package/framework/.claude/skills/lc-collect-intelligence/SKILL.md +43 -0
- package/framework/.claude/skills/lc-collect-intelligence/prompts/main.md +72 -0
- package/framework/.claude/skills/lc-competitive-analysis/SKILL.md +43 -0
- package/framework/.claude/skills/lc-competitive-analysis/prompts/main.md +70 -0
- package/framework/.claude/skills/lc-explore-opensource/SKILL.md +36 -0
- package/framework/.claude/skills/lc-explore-opensource/prompts/explore-opensource.md +77 -0
- package/framework/.claude/skills/lc-first-principles/SKILL.md +43 -0
- package/framework/.claude/skills/lc-first-principles/prompts/main.md +73 -0
- package/framework/.claude/skills/lc-handoff/SKILL.md +34 -0
- package/framework/.claude/skills/lc-init-branch/SKILL.md +52 -0
- package/framework/.claude/skills/lc-market-research/SKILL.md +43 -0
- package/framework/.claude/skills/lc-market-research/prompts/main.md +79 -0
- package/framework/.claude/skills/lc-product-research/SKILL.md +43 -0
- package/framework/.claude/skills/lc-product-research/prompts/main.md +80 -0
- package/framework/.claude/skills/lc-research-report/SKILL.md +43 -0
- package/framework/.claude/skills/lc-research-report/prompts/main.md +90 -0
- package/framework/.claude/skills/lc-research-scope/SKILL.md +43 -0
- package/framework/.claude/skills/lc-research-scope/prompts/main.md +82 -0
- package/framework/.claude/skills/lc-setup/SKILL.md +68 -0
- package/framework/.claude/skills/lc-setup/prompts/main.md +88 -0
- package/framework/.claude/skills/lc-stage/SKILL.md +45 -0
- package/framework/.claude/skills/lc-stakeholder-research/SKILL.md +43 -0
- package/framework/.claude/skills/lc-stakeholder-research/prompts/main.md +65 -0
- package/framework/.claude/skills/lc-status/SKILL.md +25 -0
- package/framework/.claude/skills/lc-storytelling/SKILL.md +43 -0
- package/framework/.claude/skills/lc-storytelling/prompts/main.md +77 -0
- package/framework/.claude/skills/lc-wf/SKILL.md +54 -0
- package/framework/.claude/skills/lc-workflow/SKILL.md +48 -0
- package/framework/.claude/skills/lc-workflow/validators/validate.py +755 -0
- package/framework/.claude/skills/lc-workflow-router/SKILL.md +41 -0
- package/framework/.claude/skills/lc-workflow-router/prompts/intake-prompt.md +91 -0
- package/framework/.claude/skills/lc-workflow-router/prompts/router-prompt.md +44 -0
- package/framework/.claude/skills/plan-tdd-development/SKILL.md +31 -0
- package/framework/.claude/skills/plan-tdd-development/prompts/main.md +44 -0
- package/framework/.claude/skills/process-interview/SKILL.md +32 -0
- package/framework/.claude/skills/process-interview/prompts/main.md +47 -0
- package/framework/.claude/skills/propose-with-openspec/SKILL.md +37 -0
- package/framework/.claude/skills/propose-with-openspec/prompts/main.md +53 -0
- package/framework/.claude/skills/split-to-github/SKILL.md +32 -0
- package/framework/.claude/skills/split-to-github/prompts/main.md +42 -0
- package/framework/.claude/skills/sync-to-knowledge/SKILL.md +35 -0
- package/framework/.claude/skills/sync-to-knowledge/prompts/main.md +54 -0
- package/framework/.claude/skills/workflow-continue/SKILL.md +24 -0
- package/framework/.claude/skills/workflow-continue/prompts/main.md +25 -0
- package/framework/.claude/stages/build-codebase-knowledge.yaml +42 -0
- package/framework/.claude/stages/clarify.yaml +59 -0
- package/framework/.claude/stages/explore-opensource.yaml +40 -0
- package/framework/.claude/stages/implement.yaml +60 -0
- package/framework/.claude/stages/ingest.yaml +40 -0
- package/framework/.claude/stages/lc-analyze-frameworks.yaml +37 -0
- package/framework/.claude/stages/lc-collect-intelligence.yaml +37 -0
- package/framework/.claude/stages/lc-competitive-analysis.yaml +37 -0
- package/framework/.claude/stages/lc-first-principles.yaml +37 -0
- package/framework/.claude/stages/lc-market-research.yaml +37 -0
- package/framework/.claude/stages/lc-product-research.yaml +37 -0
- package/framework/.claude/stages/lc-research-report.yaml +38 -0
- package/framework/.claude/stages/lc-research-scope.yaml +38 -0
- package/framework/.claude/stages/lc-stakeholder-research.yaml +37 -0
- package/framework/.claude/stages/lc-storytelling.yaml +37 -0
- package/framework/.claude/stages/product-design-docs.yaml +66 -0
- package/framework/.claude/stages/product-prototype.yaml +53 -0
- package/framework/.claude/stages/propose.yaml +45 -0
- package/framework/.claude/stages/split.yaml +41 -0
- package/framework/.claude/stages/sync-knowledge.yaml +49 -0
- package/framework/.claude/stages/tdd-development-plan.yaml +43 -0
- package/framework/.claude/stages/workflow-router.yaml +45 -0
- package/framework/.claude/templates/solo-workflow-context.yaml +23 -0
- package/framework/.claude/workflows/README.md +93 -0
- package/framework/.claude/workflows/bug-fix.yaml +81 -0
- package/framework/.claude/workflows/design-spike.yaml +55 -0
- package/framework/.claude/workflows/existing-project-iteration.yaml +106 -0
- package/framework/.claude/workflows/interview-to-knowledge.yaml +189 -0
- package/framework/.claude/workflows/oss-first-design.yaml +100 -0
- package/framework/.claude/workflows/pm-research.yaml +115 -0
- package/framework/.claude-plugin/hooks.json +6 -0
- package/framework/.claude-plugin/marketplace.json +32 -0
- package/framework/.claude-plugin/plugin.json +57 -0
- package/framework/.version-bump.json +43 -0
- package/framework/CLAUDE.md +140 -0
- package/framework/CONTRIBUTING.md +219 -0
- package/framework/LICENSE +21 -0
- package/framework/README.en.md +139 -0
- package/framework/README.md +139 -0
- package/framework/RELEASE.md +334 -0
- package/framework/SKILL.md +24 -0
- package/framework/USAGE.md +356 -0
- package/framework/manifest.json +1214 -0
- package/framework/requirements.txt +4 -0
- package/framework/scripts/__init__.py +0 -0
- package/framework/scripts/build_codebase_knowledge.py +76 -0
- package/framework/scripts/bump_version.py +181 -0
- package/framework/scripts/check-dependency-drift.py +69 -0
- package/framework/scripts/check-harness-drift.sh +57 -0
- package/framework/scripts/check-main-merge-hygiene.py +128 -0
- package/framework/scripts/check-skill-dependencies.sh +124 -0
- package/framework/scripts/init-lincoln-branch.sh +300 -0
- package/framework/scripts/init-project.sh +184 -0
- package/framework/scripts/lc-benchmark-cli.py +66 -0
- package/framework/scripts/lincoln-audit.py +288 -0
- package/framework/scripts/lincoln-setup.py +651 -0
- package/framework/scripts/lincoln-status.py +448 -0
- package/framework/scripts/lincoln_benchmark.py +224 -0
- package/framework/scripts/lincoln_benchmark_eval.py +104 -0
- package/framework/scripts/lincoln_benchmark_metrics.py +818 -0
- package/framework/scripts/lincoln_benchmark_report.py +141 -0
- package/framework/scripts/lincoln_command_map.py +289 -0
- package/framework/scripts/lincoln_dependency_manager.py +335 -0
- package/framework/scripts/lincoln_documents.py +175 -0
- package/framework/scripts/lincoln_harness_adapter.py +319 -0
- package/framework/scripts/lincoln_index.py +255 -0
- package/framework/scripts/lincoln_paths.py +198 -0
- package/framework/scripts/lincoln_prd.py +227 -0
- package/framework/scripts/lincoln_role.py +46 -0
- package/framework/scripts/lincoln_scenario.py +59 -0
- package/framework/scripts/lincoln_session_start_metrics.py +71 -0
- package/framework/scripts/lincoln_skill_prompt.py +48 -0
- package/framework/scripts/lincoln_trace.py +335 -0
- package/framework/scripts/lincoln_workflow.py +199 -0
- package/framework/scripts/list-active-lincoln-branches.sh +87 -0
- package/framework/scripts/package-lincoln-plugin.py +340 -0
- package/framework/scripts/run-infrastructure-tests.py +84 -0
- package/framework/scripts/stage_loader.py +1071 -0
- package/framework/scripts/static-check.sh +356 -0
- package/framework/scripts/sync-external-agents.sh +210 -0
- package/framework/scripts/sync-framework-package.mjs +218 -0
- package/framework/scripts/task_tool_guard.py +213 -0
- package/framework/scripts/track-artifacts.py +140 -0
- package/framework/scripts/validate_stage.py +350 -0
- package/{README.md ā framework/tools/lincoln/README.md} +4 -4
- package/framework/tools/lincoln/package-lock.json +3349 -0
- package/framework/tools/lincoln/package.json +48 -0
- package/framework/tools/lincoln/src/cli.tsx +60 -0
- package/framework/tools/lincoln/src/components/AudioMeter.tsx +34 -0
- package/framework/tools/lincoln/src/components/CancelledScreen.tsx +11 -0
- package/framework/tools/lincoln/src/components/DevicesMenu.tsx +79 -0
- package/framework/tools/lincoln/src/components/HintBar.tsx +25 -0
- package/framework/tools/lincoln/src/components/LogView.tsx +36 -0
- package/framework/tools/lincoln/src/components/ModelMenu.tsx +122 -0
- package/framework/tools/lincoln/src/components/ReadyScreen.tsx +54 -0
- package/framework/tools/lincoln/src/components/RecordingApp.tsx +211 -0
- package/framework/tools/lincoln/src/components/RecordingScreen.tsx +41 -0
- package/framework/tools/lincoln/src/components/SelectMenu.tsx +53 -0
- package/framework/tools/lincoln/src/components/StatusPanel.tsx +52 -0
- package/framework/tools/lincoln/src/components/StopConfirmation.tsx +32 -0
- package/framework/tools/lincoln/src/config/args.ts +35 -0
- package/framework/tools/lincoln/src/config/loadConfig.ts +81 -0
- package/framework/tools/lincoln/src/config/resolveConfig.ts +85 -0
- package/framework/tools/lincoln/src/devices/listDevices.ts +11 -0
- package/framework/tools/lincoln/src/devices/parseDevices.ts +25 -0
- package/framework/tools/lincoln/src/hooks/useKeyHandler.ts +63 -0
- package/framework/tools/lincoln/src/main.tsx +4 -0
- package/framework/tools/lincoln/src/models/models.ts +34 -0
- package/framework/tools/lincoln/src/models/runWarmup.ts +46 -0
- package/framework/tools/lincoln/src/models/warmupProgress.ts +30 -0
- package/framework/tools/lincoln/src/recording/spawnRecorder.ts +127 -0
- package/framework/tools/lincoln/src/recording/useRecorder.ts +146 -0
- package/framework/tools/lincoln/src/utils/amplitudeToMeter.ts +4 -0
- package/framework/tools/lincoln/src/utils/formatDuration.ts +6 -0
- package/framework/tools/lincoln/src/utils/sessionId.ts +25 -0
- package/framework/tools/lincoln/tests/cli.test.tsx +52 -0
- package/framework/tools/lincoln/tests/components/AudioMeter.test.tsx +31 -0
- package/framework/tools/lincoln/tests/components/CancelledScreen.test.tsx +12 -0
- package/framework/tools/lincoln/tests/components/ReadyScreen.test.tsx +68 -0
- package/framework/tools/lincoln/tests/components/RecordingApp.menus.test.tsx +158 -0
- package/framework/tools/lincoln/tests/components/RecordingApp.test.tsx +248 -0
- package/framework/tools/lincoln/tests/components/RecordingScreen.test.tsx +37 -0
- package/framework/tools/lincoln/tests/components/SelectMenu.test.tsx +59 -0
- package/framework/tools/lincoln/tests/components/StopConfirmation.test.tsx +38 -0
- package/framework/tools/lincoln/tests/config/args.test.ts +49 -0
- package/framework/tools/lincoln/tests/config/loadConfig.test.ts +59 -0
- package/framework/tools/lincoln/tests/config/resolveConfig.test.ts +72 -0
- package/framework/tools/lincoln/tests/devices/parseDevices.test.ts +21 -0
- package/framework/tools/lincoln/tests/hooks/useKeyHandler.enabled.test.tsx +44 -0
- package/framework/tools/lincoln/tests/hooks/useKeyHandler.test.tsx +130 -0
- package/framework/tools/lincoln/tests/models/models.test.ts +27 -0
- package/framework/tools/lincoln/tests/models/warmupProgress.test.ts +25 -0
- package/framework/tools/lincoln/tests/recording/spawnRecorder.test.ts +85 -0
- package/framework/tools/lincoln/tests/recording/useRecorder.test.tsx +172 -0
- package/framework/tools/lincoln/tests/utils/amplitudeToMeter.test.ts +22 -0
- package/framework/tools/lincoln/tests/utils/formatDuration.test.ts +11 -0
- package/framework/tools/lincoln/tests/utils/sessionId.test.ts +30 -0
- package/framework/tools/lincoln/tsconfig.json +22 -0
- package/framework/tools/lincoln/tsconfig.tests.json +10 -0
- package/framework/tools/lincoln/tsup.config.ts +17 -0
- package/framework/tools/lincoln/vitest.config.ts +20 -0
- package/framework/tools/lincoln-installer/package-lock.json +3611 -0
- package/framework/tools/lincoln-installer/package.json +53 -0
- package/framework/tools/lincoln-installer/src/cli.tsx +63 -0
- package/framework/tools/lincoln-installer/src/components/HarnessSelectScreen.tsx +43 -0
- package/framework/tools/lincoln-installer/src/components/InstallerApp.tsx +98 -0
- package/framework/tools/lincoln-installer/src/components/OptionsScreen.tsx +56 -0
- package/framework/tools/lincoln-installer/src/components/ProgressScreen.tsx +25 -0
- package/framework/tools/lincoln-installer/src/components/ResultScreen.tsx +40 -0
- package/framework/tools/lincoln-installer/src/components/SelectMenu.tsx +73 -0
- package/framework/tools/lincoln-installer/src/components/SummaryScreen.tsx +49 -0
- package/framework/tools/lincoln-installer/src/components/UpdateApp.tsx +135 -0
- package/framework/tools/lincoln-installer/src/components/WelcomeScreen.tsx +22 -0
- package/framework/tools/lincoln-installer/src/config/args.ts +76 -0
- package/framework/tools/lincoln-installer/src/config/resolveConfig.ts +33 -0
- package/framework/tools/lincoln-installer/src/config/updateArgs.ts +67 -0
- package/framework/tools/lincoln-installer/src/hooks/useSetup.ts +149 -0
- package/framework/tools/lincoln-installer/src/main.tsx +11 -0
- package/framework/tools/lincoln-installer/src/types.ts +19 -0
- package/framework/tools/lincoln-installer/src/update-main.tsx +11 -0
- package/framework/tools/lincoln-installer/src/update.tsx +90 -0
- package/framework/tools/lincoln-installer/src/utils/detectHarness.ts +51 -0
- package/framework/tools/lincoln-installer/src/utils/runSetup.ts +62 -0
- package/framework/tools/lincoln-installer/src/utils/updateRelease.ts +454 -0
- package/framework/tools/lincoln-installer/tests/components/InstallerApp.test.tsx +88 -0
- package/framework/tools/lincoln-installer/tests/components/SelectMenu.test.tsx +26 -0
- package/framework/tools/lincoln-installer/tests/components/UpdateApp.test.tsx +170 -0
- package/framework/tools/lincoln-installer/tests/components/screens.test.tsx +310 -0
- package/framework/tools/lincoln-installer/tests/config/args.test.ts +66 -0
- package/framework/tools/lincoln-installer/tests/config/resolveConfig.test.ts +75 -0
- package/framework/tools/lincoln-installer/tests/config/updateArgs.test.ts +52 -0
- package/framework/tools/lincoln-installer/tests/hooks/useSetup.test.tsx +213 -0
- package/framework/tools/lincoln-installer/tests/update.test.tsx +108 -0
- package/framework/tools/lincoln-installer/tests/utils/detectHarness.test.ts +40 -0
- package/framework/tools/lincoln-installer/tests/utils/runSetup.test.ts +45 -0
- package/framework/tools/lincoln-installer/tests/utils/updateRelease.test.ts +559 -0
- package/framework/tools/lincoln-installer/tsconfig.json +22 -0
- package/framework/tools/lincoln-installer/tsconfig.tests.json +8 -0
- package/framework/tools/lincoln-installer/tsup.config.ts +17 -0
- package/framework/tools/lincoln-installer/vitest.config.ts +20 -0
- package/framework/tools/lincoln-record/Cargo.lock +1896 -0
- package/framework/tools/lincoln-record/Cargo.toml +24 -0
- package/framework/tools/lincoln-record/diarize/diarize.py +117 -0
- package/framework/tools/lincoln-record/diarize/merge.py +55 -0
- package/framework/tools/lincoln-record/src/audio/capture/microphone.rs +194 -0
- package/framework/tools/lincoln-record/src/audio/capture/mod.rs +1 -0
- package/framework/tools/lincoln-record/src/audio/devices.rs +20 -0
- package/framework/tools/lincoln-record/src/audio/mod.rs +5 -0
- package/framework/tools/lincoln-record/src/audio/resampler.rs +44 -0
- package/framework/tools/lincoln-record/src/audio/saver.rs +87 -0
- package/framework/tools/lincoln-record/src/audio/source.rs +104 -0
- package/framework/tools/lincoln-record/src/cli.rs +96 -0
- package/framework/tools/lincoln-record/src/config.rs +135 -0
- package/framework/tools/lincoln-record/src/lib.rs +6 -0
- package/framework/tools/lincoln-record/src/main.rs +242 -0
- package/framework/tools/lincoln-record/src/model/mod.rs +248 -0
- package/framework/tools/lincoln-record/src/output/metadata.rs +30 -0
- package/framework/tools/lincoln-record/src/output/mod.rs +2 -0
- package/framework/tools/lincoln-record/src/output/transcript.rs +42 -0
- package/framework/tools/lincoln-record/src/transcription/diarization.rs +64 -0
- package/framework/tools/lincoln-record/src/transcription/mod.rs +3 -0
- package/framework/tools/lincoln-record/src/transcription/provider.rs +43 -0
- package/framework/tools/lincoln-record/src/transcription/whisper.rs +176 -0
- package/framework/tools/lincoln-record/tests/cli_args.rs +103 -0
- package/framework/tools/lincoln-record/tests/config_test.rs +70 -0
- package/framework/tools/lincoln-record/tests/devices_test.rs +23 -0
- package/framework/tools/lincoln-record/tests/diarization_tests.rs +101 -0
- package/framework/tools/lincoln-record/tests/integration_tests.rs +44 -0
- package/framework/tools/lincoln-record/tests/model_test.rs +68 -0
- package/framework/tools/lincoln-record/tests/transcription_tests.rs +73 -0
- package/package.json +19 -13
|
@@ -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())
|