@erclx/canon 4.0.0
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/LICENSE +21 -0
- package/README.md +129 -0
- package/claude/.claude-plugin/plugin.json +19 -0
- package/claude/skills/bash-cli-script/REQUIREMENT.md +42 -0
- package/claude/skills/bash-cli-script/SKILL.md +48 -0
- package/claude/skills/bash-cli-script/references/template.md +43 -0
- package/claude/skills/bash-script/REQUIREMENT.md +36 -0
- package/claude/skills/bash-script/SKILL.md +100 -0
- package/claude/skills/bash-script/references/patterns.md +349 -0
- package/claude/skills/canon-cli/REQUIREMENT.md +41 -0
- package/claude/skills/canon-cli/SKILL.md +103 -0
- package/claude/skills/canon-feedback-file/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-file/SKILL.md +80 -0
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-triage/SKILL.md +63 -0
- package/claude/skills/canon-operator/REQUIREMENT.md +61 -0
- package/claude/skills/canon-operator/SKILL.md +108 -0
- package/claude/skills/canon-rollout/REQUIREMENT.md +59 -0
- package/claude/skills/canon-rollout/SKILL.md +147 -0
- package/claude/skills/canon-screencast/REQUIREMENT.md +39 -0
- package/claude/skills/canon-screencast/SKILL.md +167 -0
- package/claude/skills/canon-slides-draft/REQUIREMENT.md +39 -0
- package/claude/skills/canon-slides-draft/SKILL.md +62 -0
- package/claude/skills/ci-workflow/REQUIREMENT.md +40 -0
- package/claude/skills/ci-workflow/SKILL.md +65 -0
- package/claude/skills/ci-workflow/references/workflows.md +98 -0
- package/claude/skills/claude-address-review/REQUIREMENT.md +57 -0
- package/claude/skills/claude-address-review/SKILL.md +212 -0
- package/claude/skills/claude-address-review/references/rebase-conflicts.md +39 -0
- package/claude/skills/claude-autoship/REQUIREMENT.md +50 -0
- package/claude/skills/claude-autoship/SKILL.md +207 -0
- package/claude/skills/claude-design-extract/REQUIREMENT.md +42 -0
- package/claude/skills/claude-design-extract/SKILL.md +102 -0
- package/claude/skills/claude-diagram/REQUIREMENT.md +45 -0
- package/claude/skills/claude-diagram/SKILL.md +177 -0
- package/claude/skills/claude-docs/REQUIREMENT.md +60 -0
- package/claude/skills/claude-docs/SKILL.md +287 -0
- package/claude/skills/claude-docs/references/anchor-sweep.md +58 -0
- package/claude/skills/claude-docs/references/wireframe-sweep.md +45 -0
- package/claude/skills/claude-feature/REQUIREMENT.md +36 -0
- package/claude/skills/claude-feature/SKILL.md +115 -0
- package/claude/skills/claude-groundwork/REQUIREMENT.md +48 -0
- package/claude/skills/claude-groundwork/SKILL.md +142 -0
- package/claude/skills/claude-intake/REQUIREMENT.md +49 -0
- package/claude/skills/claude-intake/SKILL.md +114 -0
- package/claude/skills/claude-intake-answer/REQUIREMENT.md +48 -0
- package/claude/skills/claude-intake-answer/SKILL.md +90 -0
- package/claude/skills/claude-markdown-propose/REQUIREMENT.md +48 -0
- package/claude/skills/claude-markdown-propose/SKILL.md +118 -0
- package/claude/skills/claude-markdown-propose/references/format.md +107 -0
- package/claude/skills/claude-memory-capture/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-capture/SKILL.md +101 -0
- package/claude/skills/claude-memory-review/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-review/SKILL.md +210 -0
- package/claude/skills/claude-memory-review/references/receipt-format.md +48 -0
- package/claude/skills/claude-orchestrate/REQUIREMENT.md +121 -0
- package/claude/skills/claude-orchestrate/SKILL.md +241 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +132 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +32 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +72 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +87 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +30 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-sweep.md +21 -0
- package/claude/skills/claude-orchestrate/scripts/poll.sh +373 -0
- package/claude/skills/claude-orchestrate/scripts/watch.sh +181 -0
- package/claude/skills/claude-pr-review/REQUIREMENT.md +47 -0
- package/claude/skills/claude-pr-review/SKILL.md +295 -0
- package/claude/skills/claude-review/REQUIREMENT.md +39 -0
- package/claude/skills/claude-review/SKILL.md +142 -0
- package/claude/skills/claude-seed-sync/REQUIREMENT.md +45 -0
- package/claude/skills/claude-seed-sync/SKILL.md +156 -0
- package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
- package/claude/skills/claude-standards-audit/SKILL.md +99 -0
- package/claude/skills/claude-tasks/REQUIREMENT.md +43 -0
- package/claude/skills/claude-tasks/SKILL.md +161 -0
- package/claude/skills/claude-teach/REQUIREMENT.md +56 -0
- package/claude/skills/claude-teach/SKILL.md +196 -0
- package/claude/skills/claude-teach/references/lesson-craft.md +59 -0
- package/claude/skills/claude-teach/references/pedagogy.md +67 -0
- package/claude/skills/claude-teach/references/promotion.md +54 -0
- package/claude/skills/claude-ui-test/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ui-test/SKILL.md +77 -0
- package/claude/skills/claude-ux-audit/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ux-audit/SKILL.md +79 -0
- package/claude/skills/claude-ux-measure/REQUIREMENT.md +48 -0
- package/claude/skills/claude-ux-measure/SKILL.md +122 -0
- package/claude/skills/claude-worker/REQUIREMENT.md +54 -0
- package/claude/skills/claude-worker/SKILL.md +96 -0
- package/claude/skills/claude-worktree/REQUIREMENT.md +58 -0
- package/claude/skills/claude-worktree/SKILL.md +136 -0
- package/claude/skills/create-rule/REQUIREMENT.md +45 -0
- package/claude/skills/create-rule/SKILL.md +68 -0
- package/claude/skills/create-skill/REQUIREMENT.md +38 -0
- package/claude/skills/create-skill/SKILL.md +32 -0
- package/claude/skills/create-snippet/REQUIREMENT.md +39 -0
- package/claude/skills/create-snippet/SKILL.md +30 -0
- package/claude/skills/create-standard/REQUIREMENT.md +35 -0
- package/claude/skills/create-standard/SKILL.md +29 -0
- package/claude/skills/decision-escalate/REQUIREMENT.md +45 -0
- package/claude/skills/decision-escalate/SKILL.md +79 -0
- package/claude/skills/docs-sync/REQUIREMENT.md +41 -0
- package/claude/skills/docs-sync/SKILL.md +95 -0
- package/claude/skills/git-branch/REQUIREMENT.md +38 -0
- package/claude/skills/git-branch/SKILL.md +60 -0
- package/claude/skills/git-commit/REQUIREMENT.md +36 -0
- package/claude/skills/git-commit/SKILL.md +49 -0
- package/claude/skills/git-followup/REQUIREMENT.md +43 -0
- package/claude/skills/git-followup/SKILL.md +48 -0
- package/claude/skills/git-issue/REQUIREMENT.md +38 -0
- package/claude/skills/git-issue/SKILL.md +65 -0
- package/claude/skills/git-pr/REQUIREMENT.md +50 -0
- package/claude/skills/git-pr/SKILL.md +164 -0
- package/claude/skills/git-pr/references/labels.md +95 -0
- package/claude/skills/git-ship/REQUIREMENT.md +42 -0
- package/claude/skills/git-ship/SKILL.md +55 -0
- package/claude/skills/git-split/REQUIREMENT.md +39 -0
- package/claude/skills/git-split/SKILL.md +162 -0
- package/claude/skills/git-stage/REQUIREMENT.md +39 -0
- package/claude/skills/git-stage/SKILL.md +73 -0
- package/claude/skills/git-worktree/REQUIREMENT.md +38 -0
- package/claude/skills/git-worktree/SKILL.md +130 -0
- package/claude/skills/migration-claude-md/REQUIREMENT.md +40 -0
- package/claude/skills/migration-claude-md/SKILL.md +76 -0
- package/claude/skills/migration-context/REQUIREMENT.md +36 -0
- package/claude/skills/migration-context/SKILL.md +95 -0
- package/claude/skills/migration-standards-drop/REQUIREMENT.md +55 -0
- package/claude/skills/migration-standards-drop/SKILL.md +113 -0
- package/claude/skills/migration-superseded/REQUIREMENT.md +44 -0
- package/claude/skills/migration-superseded/SKILL.md +115 -0
- package/claude/skills/project-commands/REQUIREMENT.md +42 -0
- package/claude/skills/project-commands/SKILL.md +85 -0
- package/claude/skills/restate-plainly/REQUIREMENT.md +41 -0
- package/claude/skills/restate-plainly/SKILL.md +39 -0
- package/claude/skills/session-map/REQUIREMENT.md +57 -0
- package/claude/skills/session-map/SKILL.md +70 -0
- package/claude/skills/session-resume/REQUIREMENT.md +49 -0
- package/claude/skills/session-resume/SKILL.md +51 -0
- package/claude/skills/setup-gov/REQUIREMENT.md +37 -0
- package/claude/skills/setup-gov/SKILL.md +77 -0
- package/claude/skills/setup-indexes/REQUIREMENT.md +45 -0
- package/claude/skills/setup-indexes/SKILL.md +153 -0
- package/claude/skills/setup-init/REQUIREMENT.md +45 -0
- package/claude/skills/setup-init/SKILL.md +127 -0
- package/claude/skills/setup-plugins/REQUIREMENT.md +42 -0
- package/claude/skills/setup-plugins/SKILL.md +81 -0
- package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
- package/claude/skills/setup-verify/REQUIREMENT.md +39 -0
- package/claude/skills/setup-verify/SKILL.md +51 -0
- package/claude/skills/systematic-debugging/REQUIREMENT.md +41 -0
- package/claude/skills/systematic-debugging/SKILL.md +70 -0
- package/claude/skills/write-human/REQUIREMENT.md +46 -0
- package/claude/skills/write-human/SKILL.md +68 -0
- package/claude/skills/write-human/references/density.md +38 -0
- package/claude/skills/write-human/references/machine-tells.md +107 -0
- package/claude/skills/write-human/references/source-material.md +37 -0
- package/claude/skills/youtube-transcripts/REQUIREMENT.md +38 -0
- package/claude/skills/youtube-transcripts/SKILL.md +34 -0
- package/docs/agents/audits.md +98 -0
- package/docs/agents/capture.md +37 -0
- package/docs/agents/census.md +23 -0
- package/docs/agents/commands.md +146 -0
- package/docs/agents/comments.md +34 -0
- package/docs/agents/context-audit-checks.md +120 -0
- package/docs/agents/context-audit.md +83 -0
- package/docs/agents/counts.md +76 -0
- package/docs/agents/demo.md +86 -0
- package/docs/agents/docs.md +17 -0
- package/docs/agents/gate.md +84 -0
- package/docs/agents/index.md +47 -0
- package/docs/agents/indexes.md +35 -0
- package/docs/agents/install-and-sync.md +385 -0
- package/docs/agents/intake.md +81 -0
- package/docs/agents/key-changes.md +103 -0
- package/docs/agents/label-coverage.md +73 -0
- package/docs/agents/markdown-audit.md +197 -0
- package/docs/agents/output-shape.md +70 -0
- package/docs/agents/overview.md +26 -0
- package/docs/agents/records.md +170 -0
- package/docs/agents/restated.md +81 -0
- package/docs/agents/review-classification.md +77 -0
- package/docs/agents/routing.md +61 -0
- package/docs/agents/rule-citations.md +98 -0
- package/docs/agents/sandbox.md +71 -0
- package/docs/agents/scripting.md +149 -0
- package/docs/agents/sessions.md +120 -0
- package/docs/agents/skills-audit.md +94 -0
- package/docs/agents/skills-reach.md +64 -0
- package/docs/agents/standards-audit.md +38 -0
- package/docs/agents/state-scoped-risk.md +105 -0
- package/docs/agents/superseded.md +85 -0
- package/docs/agents/targets.md +83 -0
- package/docs/agents/tasks.md +200 -0
- package/docs/agents/teach.md +158 -0
- package/docs/agents/test-order.md +56 -0
- package/docs/agents/worktrees.md +62 -0
- package/docs/ai-workflow.md +317 -0
- package/docs/index.md +23 -0
- package/docs/operating-model.md +223 -0
- package/docs/target-projects.md +258 -0
- package/docs/visual-design-workflow.md +151 -0
- package/docs/zshrc-aliases.md +65 -0
- package/governance/rules/ci/700-ci-workflow.md +44 -0
- package/governance/rules/claude/500-prose.md +15 -0
- package/governance/rules/claude/501-markdown.md +14 -0
- package/governance/rules/claude/510-context.md +28 -0
- package/governance/rules/claude/511-indexes.md +14 -0
- package/governance/rules/claude/520-wireframes.md +12 -0
- package/governance/rules/claude/530-requirements.md +11 -0
- package/governance/rules/claude/540-architecture.md +11 -0
- package/governance/rules/claude/550-design.md +11 -0
- package/governance/rules/claude/555-tasks.md +12 -0
- package/governance/rules/claude/556-groundwork.md +11 -0
- package/governance/rules/claude/557-intake.md +11 -0
- package/governance/rules/claude/558-plan.md +22 -0
- package/governance/rules/claude/559-memory.md +11 -0
- package/governance/rules/claude/560-diagrams.md +18 -0
- package/governance/rules/claude/561-teach.md +13 -0
- package/governance/rules/claude/562-session.md +15 -0
- package/governance/rules/claude/570-skill.md +24 -0
- package/governance/rules/claude/575-hooks.md +17 -0
- package/governance/rules/claude/576-settings.md +14 -0
- package/governance/rules/claude/580-readme.md +11 -0
- package/governance/rules/claude/590-rule-authoring.md +12 -0
- package/governance/rules/claude/591-standard-authoring.md +12 -0
- package/governance/rules/claude/592-claude-md.md +19 -0
- package/governance/rules/core/000-constitution.md +30 -0
- package/governance/rules/core/005-behavior.md +27 -0
- package/governance/rules/core/010-testing.md +35 -0
- package/governance/rules/core/015-output.md +20 -0
- package/governance/rules/core/020-concurrency.md +22 -0
- package/governance/rules/core/025-indexes.md +9 -0
- package/governance/rules/core/030-error-handling.md +31 -0
- package/governance/rules/core/035-tasks.md +13 -0
- package/governance/rules/core/040-performance.md +20 -0
- package/governance/rules/core/045-memory.md +12 -0
- package/governance/rules/core/050-logging.md +20 -0
- package/governance/rules/core/055-scratch.md +9 -0
- package/governance/rules/core/060-naming.md +19 -0
- package/governance/rules/core/065-spelling.md +19 -0
- package/governance/rules/core/070-planning.md +18 -0
- package/governance/rules/core/075-dependencies.md +25 -0
- package/governance/rules/core/080-config-comments.md +22 -0
- package/governance/rules/core/085-worktrees.md +17 -0
- package/governance/rules/core/087-git.md +11 -0
- package/governance/rules/core/090-code-comments.md +39 -0
- package/governance/rules/framework/200-react.md +51 -0
- package/governance/rules/framework/210-astro.md +41 -0
- package/governance/rules/framework/220-fastapi.md +43 -0
- package/governance/rules/framework/230-nextjs.md +48 -0
- package/governance/rules/framework/250-tailwind.md +32 -0
- package/governance/rules/framework/260-shadcn.md +34 -0
- package/governance/rules/lang/100-typescript.md +40 -0
- package/governance/rules/lang/110-python.md +42 -0
- package/governance/rules/lang/120-bash.md +19 -0
- package/governance/rules/lib/300-testing-ts.md +39 -0
- package/governance/rules/lib/305-e2e-reliability.md +34 -0
- package/governance/rules/lib/306-test-scope.md +25 -0
- package/governance/rules/lib/310-zod.md +25 -0
- package/governance/rules/lib/320-tanstack-query.md +32 -0
- package/governance/rules/lib/330-testing-py.md +44 -0
- package/governance/rules/lib/340-pydantic.md +38 -0
- package/governance/rules/lib/350-security-web.md +32 -0
- package/governance/rules/lib/360-security-server.md +39 -0
- package/governance/rules/lib/370-database.md +35 -0
- package/governance/rules/snippets/505-at-references.md +9 -0
- package/governance/rules/ui/400-ui.md +36 -0
- package/governance/rules/ui/410-a11y.md +48 -0
- package/governance/rules/ui/420-forms.md +36 -0
- package/governance/rules/ui/430-ux-completeness.md +65 -0
- package/governance/rules/ui/440-surface-capture.md +34 -0
- package/governance/rules/ui/450-link-behavior.md +19 -0
- package/governance/stacks/astro.toml +2 -0
- package/governance/stacks/base.toml +8 -0
- package/governance/stacks/node-server.toml +2 -0
- package/governance/stacks/node.toml +2 -0
- package/governance/stacks/python-fastapi.toml +2 -0
- package/governance/stacks/python.toml +2 -0
- package/governance/stacks/react.toml +2 -0
- package/package.json +69 -0
- package/scripts/config.sh +11 -0
- package/scripts/core/bootstrap.sh +81 -0
- package/scripts/core/check-color-source.sh +41 -0
- package/scripts/core/check-ignore-parity.sh +162 -0
- package/scripts/core/check-plugin-boundary.sh +45 -0
- package/scripts/core/check-seed-independence.sh +59 -0
- package/scripts/core/check-skill-paths.sh +24 -0
- package/scripts/core/clean.sh +36 -0
- package/scripts/core/install-check.sh +101 -0
- package/scripts/core/list-seed-roots.sh +18 -0
- package/scripts/core/regen-claude-copies.sh +10 -0
- package/scripts/core/regen-hero.sh +217 -0
- package/scripts/core/regen-indexes.sh +10 -0
- package/scripts/core/regen-tooling-paths.sh +61 -0
- package/scripts/core/repair-bare-flag.sh +19 -0
- package/scripts/core/snapshot.sh +134 -0
- package/scripts/core/update.sh +35 -0
- package/scripts/docs/list.sh +165 -0
- package/scripts/lib/frontmatter.sh +30 -0
- package/scripts/lib/gov.sh +14 -0
- package/scripts/lib/sandbox-fixtures.sh +191 -0
- package/scripts/lib/sandbox-git.sh +125 -0
- package/scripts/lib/sandbox-path.sh +206 -0
- package/scripts/lib/tooling.sh +35 -0
- package/scripts/lib/ui.sh +266 -0
- package/scripts/lib/worktree.sh +20 -0
- package/scripts/manage-sandbox.sh +466 -0
- package/scripts/snippets/create.sh +156 -0
- package/scripts/standards/list.sh +115 -0
- package/scripts/tooling/create.sh +109 -0
- package/scripts/tooling/verify.sh +179 -0
- package/snippets/align.md +12 -0
- package/snippets/claude/decision-memo.md +39 -0
- package/snippets/claude/feature-recap.md +19 -0
- package/snippets/claude/figma-steps.md +24 -0
- package/snippets/compact-summary.md +5 -0
- package/snippets/decision-help.md +6 -0
- package/snippets/meta-prompt.md +14 -0
- package/snippets/research-prompt.md +7 -0
- package/snippets/session-notes.md +11 -0
- package/snippets/snippets.toml +5 -0
- package/snippets/step-by-step.md +10 -0
- package/snippets/web-research.md +21 -0
- package/src/audits/baseline.ts +201 -0
- package/src/audits/catalog.ts +876 -0
- package/src/audits/run.ts +204 -0
- package/src/autoship/classify.ts +75 -0
- package/src/autoship/paths.ts +51 -0
- package/src/binary.ts +16 -0
- package/src/browser/engine.ts +40 -0
- package/src/census/count.ts +113 -0
- package/src/claude/cases/all.ts +24 -0
- package/src/claude/cases/authoring.ts +53 -0
- package/src/claude/cases/claude-workflow.ts +158 -0
- package/src/claude/cases/git.ts +44 -0
- package/src/claude/cases/misc.ts +27 -0
- package/src/claude/cases/setup.ts +94 -0
- package/src/claude/gitignore.ts +51 -0
- package/src/claude/routing.ts +283 -0
- package/src/claude/seeds-list.ts +47 -0
- package/src/claude/seeds.ts +150 -0
- package/src/claude/settings.ts +151 -0
- package/src/claude/skills-audit.ts +228 -0
- package/src/claude/skills-drift.ts +156 -0
- package/src/claude/skills-list.ts +99 -0
- package/src/claude/skills-rank.ts +320 -0
- package/src/claude/skills-reach.ts +227 -0
- package/src/cli-run.ts +43 -0
- package/src/cli.ts +200 -0
- package/src/commands/audits.ts +350 -0
- package/src/commands/autoship.ts +129 -0
- package/src/commands/capture.ts +133 -0
- package/src/commands/census.ts +105 -0
- package/src/commands/claude.ts +1286 -0
- package/src/commands/comments.ts +240 -0
- package/src/commands/context.ts +857 -0
- package/src/commands/demo.ts +389 -0
- package/src/commands/deps.ts +173 -0
- package/src/commands/design.ts +36 -0
- package/src/commands/docs.ts +60 -0
- package/src/commands/feedback-format.ts +23 -0
- package/src/commands/feedback.ts +112 -0
- package/src/commands/gate.ts +189 -0
- package/src/commands/gov.ts +1265 -0
- package/src/commands/indexes.ts +184 -0
- package/src/commands/init.ts +113 -0
- package/src/commands/intake.ts +406 -0
- package/src/commands/inventory.ts +256 -0
- package/src/commands/labels.ts +361 -0
- package/src/commands/markdown.ts +544 -0
- package/src/commands/migrate.ts +175 -0
- package/src/commands/pass-through.ts +39 -0
- package/src/commands/pr.ts +411 -0
- package/src/commands/records.ts +728 -0
- package/src/commands/sandbox.ts +468 -0
- package/src/commands/secrets.ts +132 -0
- package/src/commands/serve.ts +159 -0
- package/src/commands/sessions.ts +408 -0
- package/src/commands/slides.ts +126 -0
- package/src/commands/snippets.ts +84 -0
- package/src/commands/standards.ts +247 -0
- package/src/commands/sync.ts +428 -0
- package/src/commands/targets.ts +319 -0
- package/src/commands/tasks.ts +743 -0
- package/src/commands/teach.ts +786 -0
- package/src/commands/tooling.ts +573 -0
- package/src/commands/transcripts.ts +44 -0
- package/src/commands/upgrade.ts +231 -0
- package/src/commands/wiki.ts +100 -0
- package/src/commands/worktrees.ts +191 -0
- package/src/comments/scan.ts +338 -0
- package/src/comments/trend.ts +207 -0
- package/src/comments/vocabulary.ts +85 -0
- package/src/context/architecture.ts +364 -0
- package/src/context/audit.ts +790 -0
- package/src/context/citations.ts +196 -0
- package/src/context/folders.ts +186 -0
- package/src/context/gate.ts +57 -0
- package/src/context/index-drift.ts +64 -0
- package/src/context/narration.ts +99 -0
- package/src/copy.ts +30 -0
- package/src/counts/catalogs.ts +96 -0
- package/src/counts/numbers.ts +79 -0
- package/src/counts/scan.ts +314 -0
- package/src/demo/beats.ts +135 -0
- package/src/demo/compile.ts +326 -0
- package/src/demo/container.ts +63 -0
- package/src/demo/cursors.ts +55 -0
- package/src/demo/drive.ts +357 -0
- package/src/demo/pointer.ts +178 -0
- package/src/demo/theme.ts +112 -0
- package/src/deps/audit.ts +153 -0
- package/src/design/parse.ts +116 -0
- package/src/design/render.ts +249 -0
- package/src/docs/read.ts +77 -0
- package/src/exec.ts +16 -0
- package/src/exempt-marker.ts +43 -0
- package/src/frontmatter.ts +13 -0
- package/src/gate/measures.ts +682 -0
- package/src/gate/sequencer.ts +386 -0
- package/src/gate/stages.ts +412 -0
- package/src/git-env.ts +36 -0
- package/src/git-files.ts +105 -0
- package/src/git-ignore.ts +46 -0
- package/src/github-format.ts +13 -0
- package/src/github.ts +24 -0
- package/src/gov/adapter.ts +103 -0
- package/src/gov/citations.ts +514 -0
- package/src/gov/consumed.ts +129 -0
- package/src/gov/install.ts +132 -0
- package/src/gov/list.ts +106 -0
- package/src/gov/payload.ts +39 -0
- package/src/gov/restated.ts +814 -0
- package/src/gov/stacks.ts +205 -0
- package/src/gov/superseded.ts +415 -0
- package/src/gov/test-order.ts +407 -0
- package/src/indexes/frontmatter.ts +46 -0
- package/src/indexes/regen.ts +84 -0
- package/src/indexes/render.ts +201 -0
- package/src/indexes/walk.ts +83 -0
- package/src/init/flags.ts +60 -0
- package/src/init/plan.ts +114 -0
- package/src/init/run.ts +46 -0
- package/src/init/steps.ts +77 -0
- package/src/intake/folder.ts +320 -0
- package/src/intake/items.ts +174 -0
- package/src/inventory/config.ts +117 -0
- package/src/inventory/group.ts +76 -0
- package/src/inventory/subjects.ts +114 -0
- package/src/inventory/walk.ts +129 -0
- package/src/labels/audit.ts +82 -0
- package/src/labels/coverage.ts +79 -0
- package/src/labels/map.ts +101 -0
- package/src/labels/phase.ts +95 -0
- package/src/markdown/bans.ts +94 -0
- package/src/markdown/files.ts +102 -0
- package/src/markdown/gate.ts +28 -0
- package/src/markdown/scan.ts +295 -0
- package/src/markdown/structure.ts +730 -0
- package/src/migrate/apply.ts +115 -0
- package/src/migrate/plan.ts +103 -0
- package/src/migrate/rename.ts +183 -0
- package/src/pr/bijection.ts +145 -0
- package/src/pr/paths.ts +335 -0
- package/src/process/harness.ts +167 -0
- package/src/project-root.ts +19 -0
- package/src/records/backup.ts +455 -0
- package/src/records/migrate.ts +78 -0
- package/src/records/size.ts +260 -0
- package/src/records/validate.ts +1162 -0
- package/src/sandbox/census.ts +228 -0
- package/src/sandbox/coverage.ts +115 -0
- package/src/sandbox/expect.ts +629 -0
- package/src/sandbox/tree.ts +47 -0
- package/src/secrets/marker.ts +30 -0
- package/src/secrets/patterns.ts +142 -0
- package/src/secrets/scan.ts +123 -0
- package/src/secrets/shipped.ts +111 -0
- package/src/seed-marker.ts +74 -0
- package/src/serve/static.ts +322 -0
- package/src/sessions/claim.ts +85 -0
- package/src/sessions/live.ts +79 -0
- package/src/sessions/registry.ts +137 -0
- package/src/sessions/resolve.ts +333 -0
- package/src/slides/layouts.ts +391 -0
- package/src/slides/open.ts +18 -0
- package/src/slides/parse.ts +84 -0
- package/src/slides/render.ts +88 -0
- package/src/slides/styles.ts +44 -0
- package/src/snippets/categories.ts +66 -0
- package/src/snippets/list.ts +32 -0
- package/src/snippets/presets.ts +50 -0
- package/src/standards/audit.ts +132 -0
- package/src/standards/read.ts +100 -0
- package/src/sync/check.ts +692 -0
- package/src/sync/engine.ts +576 -0
- package/src/sync/git.ts +225 -0
- package/src/sync/history.ts +123 -0
- package/src/sync/layout.ts +140 -0
- package/src/sync/reverse.ts +268 -0
- package/src/sync/seeds-report.ts +126 -0
- package/src/sync/stamp.ts +358 -0
- package/src/sync/target.ts +70 -0
- package/src/sync/workflow.ts +200 -0
- package/src/target.ts +43 -0
- package/src/targets/pulls.ts +250 -0
- package/src/targets/registry.ts +203 -0
- package/src/targets/resolve.ts +145 -0
- package/src/targets/sweep.ts +246 -0
- package/src/tasks/archive.ts +506 -0
- package/src/tasks/record.ts +311 -0
- package/src/tasks/trunk.ts +89 -0
- package/src/tasks/validate.ts +1001 -0
- package/src/teach/lesson.ts +180 -0
- package/src/teach/workspace.ts +842 -0
- package/src/tooling/gitignore.ts +122 -0
- package/src/tooling/inject.ts +193 -0
- package/src/tooling/list.ts +39 -0
- package/src/tooling/manifest.ts +176 -0
- package/src/tooling/package.ts +166 -0
- package/src/tooling/read.ts +65 -0
- package/src/tooling/scan.ts +147 -0
- package/src/tooling/stamp.ts +44 -0
- package/src/transcripts/fetch.ts +156 -0
- package/src/transcripts/metadata.ts +54 -0
- package/src/transcripts/vtt.ts +114 -0
- package/src/ui.ts +266 -0
- package/src/version/compare.ts +53 -0
- package/src/version/installed.ts +40 -0
- package/src/version/manager.ts +67 -0
- package/src/version/skew.ts +192 -0
- package/src/wiki/init.ts +85 -0
- package/src/worktree.ts +143 -0
- package/src/worktrees/reclaim.ts +306 -0
- package/standards/architecture.md +72 -0
- package/standards/branch.md +59 -0
- package/standards/commit.md +72 -0
- package/standards/context.md +151 -0
- package/standards/design.md +93 -0
- package/standards/diagrams.md +152 -0
- package/standards/glossary.md +75 -0
- package/standards/groundwork.md +211 -0
- package/standards/index.md +36 -0
- package/standards/intake.md +192 -0
- package/standards/issue.md +94 -0
- package/standards/markdown.md +137 -0
- package/standards/memory.md +144 -0
- package/standards/plan.md +172 -0
- package/standards/pr.md +139 -0
- package/standards/publish.md +51 -0
- package/standards/readme.md +208 -0
- package/standards/requirements.md +70 -0
- package/standards/rule.md +118 -0
- package/standards/session.md +109 -0
- package/standards/skill.md +300 -0
- package/standards/slug.md +39 -0
- package/standards/snippets.md +76 -0
- package/standards/standard.md +170 -0
- package/standards/tasks.md +254 -0
- package/standards/teach.md +153 -0
- package/standards/versioning.md +71 -0
- package/standards/wireframes.md +113 -0
- package/tooling/astro/configs/astro.config.mjs +31 -0
- package/tooling/astro/configs/eslint.config.js +79 -0
- package/tooling/astro/configs/playwright.config.ts +26 -0
- package/tooling/astro/configs/tsconfig.json +12 -0
- package/tooling/astro/configs/vitest.config.ts +22 -0
- package/tooling/astro/manifest.toml +34 -0
- package/tooling/astro/reference.md +60 -0
- package/tooling/base/configs/.editorconfig +5 -0
- package/tooling/base/configs/.github/pull_request_template.md +18 -0
- package/tooling/base/configs/.github/workflows/verify.yml +35 -0
- package/tooling/base/configs/.husky/commit-msg +1 -0
- package/tooling/base/configs/.husky/post-merge +61 -0
- package/tooling/base/configs/.husky/post-rewrite +21 -0
- package/tooling/base/configs/.husky/pre-commit +1 -0
- package/tooling/base/configs/.husky/pre-push +1 -0
- package/tooling/base/configs/.prettierrc +12 -0
- package/tooling/base/configs/.shellcheckrc +1 -0
- package/tooling/base/configs/.vscode/extensions.json +9 -0
- package/tooling/base/configs/.vscode/settings.json +3 -0
- package/tooling/base/configs/commitlint.config.js +11 -0
- package/tooling/base/configs/scripts/verify.sh +64 -0
- package/tooling/base/manifest.toml +30 -0
- package/tooling/base/reference.md +98 -0
- package/tooling/base/seeds/.claude/context/ci.md +33 -0
- package/tooling/base/seeds/.claude/context/development.md +37 -0
- package/tooling/base/seeds/.claude/context/index.md +11 -0
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/base/seeds/.lintstagedrc +8 -0
- package/tooling/base/seeds/.prettierignore +0 -0
- package/tooling/base/seeds/cspell.json +20 -0
- package/tooling/claude/manifest.toml +14 -0
- package/tooling/claude/reference.md +79 -0
- package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
- package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
- package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
- package/tooling/claude/seeds/.claude/diagrams/index.md +8 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +50 -0
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +68 -0
- package/tooling/claude/seeds/.claude/hooks/path-form.sh +57 -0
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +52 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +86 -0
- package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +71 -0
- package/tooling/claude/seeds/.claude/memory/index.md +8 -0
- package/tooling/claude/seeds/.claude/settings.json +47 -0
- package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
- package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
- package/tooling/claude/seeds/CLAUDE.md +29 -0
- package/tooling/claude/user/settings.template.json +10 -0
- package/tooling/claude/user/statusline-command.sh +53 -0
- package/tooling/python/configs/.coveragerc +14 -0
- package/tooling/python/configs/.python-version +1 -0
- package/tooling/python/configs/mypy.ini +6 -0
- package/tooling/python/configs/pytest.ini +4 -0
- package/tooling/python/configs/ruff.toml +15 -0
- package/tooling/python/configs/scripts/verify.sh +77 -0
- package/tooling/python/manifest.toml +16 -0
- package/tooling/python/reference.md +66 -0
- package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/python/seeds/tests/test_smoke.py +2 -0
- package/tooling/vite-react/configs/playwright.config.ts +26 -0
- package/tooling/vite-react/configs/tsconfig.json +35 -0
- package/tooling/vite-react/configs/vite.config.ts +24 -0
- package/tooling/vite-react/configs/vitest.config.ts +26 -0
- package/tooling/vite-react/manifest.toml +23 -0
- package/tooling/vite-react/reference.md +55 -0
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
- package/tooling/web/configs/.github/workflows/verify.yml +134 -0
- package/tooling/web/configs/.vscode/extensions.json +13 -0
- package/tooling/web/configs/.vscode/settings.json +10 -0
- package/tooling/web/configs/e2e/home.spec.ts +6 -0
- package/tooling/web/configs/e2e/screenshot.ts +53 -0
- package/tooling/web/configs/eslint.config.js +82 -0
- package/tooling/web/configs/scripts/screenshot.sh +28 -0
- package/tooling/web/configs/scripts/verify.sh +80 -0
- package/tooling/web/configs/scripts/worktree-port.sh +74 -0
- package/tooling/web/configs/src/test/setup.ts +8 -0
- package/tooling/web/manifest.toml +58 -0
- package/tooling/web/reference.md +115 -0
- package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# The sandbox reaches GitHub over HTTPS with the gh token so a headless run needs
|
|
4
|
+
# no SSH key and no agent. `gh auth login` authenticates the CLI but leaves git
|
|
5
|
+
# itself without a credential, so the harness supplies the helper rather than
|
|
6
|
+
# assuming the machine carries one.
|
|
7
|
+
SANDBOX_GIT_CREDENTIAL_HELPER='!gh auth git-credential'
|
|
8
|
+
|
|
9
|
+
# Call from the main shell before any scenario runs. sandbox_anchor_url is used
|
|
10
|
+
# inside command substitutions, where log_error would exit only the subshell and
|
|
11
|
+
# leave the caller building an empty remote, so the run has to stop here instead.
|
|
12
|
+
require_sandbox_anchor_config() {
|
|
13
|
+
if [ -z "${GITHUB_ORG:-}" ]; then
|
|
14
|
+
log_error "GITHUB_ORG is empty. Export GITHUB_ORG=<org>, or run from a clone whose remote.origin.url points at GitHub."
|
|
15
|
+
fi
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
resolve_sandbox_anchor_repo() {
|
|
19
|
+
printf '%s\n' "${1:-${ANCHOR_REPO:-}}"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
sandbox_anchor_url() {
|
|
23
|
+
local repo_name
|
|
24
|
+
repo_name="$(resolve_sandbox_anchor_repo "$@")"
|
|
25
|
+
|
|
26
|
+
if [ -z "$repo_name" ] || [ -z "${GITHUB_ORG:-}" ]; then
|
|
27
|
+
log_error "sandbox_anchor_url needs GITHUB_ORG and a repository name. Call require_sandbox_anchor_config first."
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
printf 'https://github.com/%s/%s.git\n' "$GITHUB_ORG" "$repo_name"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# credential.helper is multi-valued and git concatenates it across system, global,
|
|
34
|
+
# and local, trying each in order until one returns a credential. A plain set
|
|
35
|
+
# leaves an operator's existing helper ahead of this one, so a stale token wins
|
|
36
|
+
# and gh never runs. The empty value resets the inherited list first.
|
|
37
|
+
configure_sandbox_git_credentials() {
|
|
38
|
+
git config credential.helper ""
|
|
39
|
+
git config --add credential.helper "$SANDBOX_GIT_CREDENTIAL_HELPER"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
resolve_sandbox_git_identity() {
|
|
43
|
+
SANDBOX_GIT_NAME="${SANDBOX_GIT_NAME:-$(git config --global user.name 2>/dev/null || true)}"
|
|
44
|
+
SANDBOX_GIT_EMAIL="${SANDBOX_GIT_EMAIL:-$(git config --global user.email 2>/dev/null || true)}"
|
|
45
|
+
|
|
46
|
+
: "${SANDBOX_GIT_NAME:=aitk-sandbox}"
|
|
47
|
+
: "${SANDBOX_GIT_EMAIL:=sandbox@example.com}"
|
|
48
|
+
|
|
49
|
+
export SANDBOX_GIT_NAME SANDBOX_GIT_EMAIL
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
configure_sandbox_git_identity() {
|
|
53
|
+
resolve_sandbox_git_identity
|
|
54
|
+
git config user.name "$SANDBOX_GIT_NAME"
|
|
55
|
+
git config user.email "$SANDBOX_GIT_EMAIL"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Every scenario that needs a remote points at the same throwaway repository, so
|
|
59
|
+
# the name lives here rather than in each one.
|
|
60
|
+
SANDBOX_ANCHOR_REPO="aitk-sandbox"
|
|
61
|
+
|
|
62
|
+
# A scenario calls this from its own use_anchor hook rather than this file
|
|
63
|
+
# defining the hook. manage-sandbox.sh keys off `type -t use_anchor`, so
|
|
64
|
+
# declaring it here would hand an anchor to the scenarios that source this file
|
|
65
|
+
# for the identity helpers alone.
|
|
66
|
+
use_sandbox_anchor() {
|
|
67
|
+
export ANCHOR_REPO="${1:-$SANDBOX_ANCHOR_REPO}"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# gh answers an absent repository and an unreachable host with the same exit
|
|
71
|
+
# status, so the 404 is the only thing separating them. Anything else is a
|
|
72
|
+
# network or credential fault, where creating a repository would be the wrong
|
|
73
|
+
# answer and would fail for the same reason the read did.
|
|
74
|
+
ensure_sandbox_anchor_repo() {
|
|
75
|
+
local repo_name gh_error
|
|
76
|
+
|
|
77
|
+
repo_name="$(resolve_sandbox_anchor_repo "$@")"
|
|
78
|
+
|
|
79
|
+
if [ -z "$repo_name" ] || [ -z "${GITHUB_ORG:-}" ]; then
|
|
80
|
+
log_error "ensure_sandbox_anchor_repo needs GITHUB_ORG and a repository name. Call require_sandbox_anchor_config first."
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
if gh_error="$(gh api "repos/${GITHUB_ORG}/${repo_name}" --silent 2>&1)"; then
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
case "$gh_error" in
|
|
88
|
+
*"HTTP 404"*) ;;
|
|
89
|
+
*) log_error "Cannot reach ${GITHUB_ORG}/${repo_name}: ${gh_error}" ;;
|
|
90
|
+
esac
|
|
91
|
+
|
|
92
|
+
# An absent anchor is nearly always a wrong GITHUB_ORG or a rename nobody
|
|
93
|
+
# performed, and provisioning stages a fixture rather than cloning while every
|
|
94
|
+
# scenario force-pushes to main, so a repository created here would carry all
|
|
95
|
+
# nine to a pass against something that is not the anchor. Refusing is the safe
|
|
96
|
+
# default and creating is the opt-in, the shape `canon tooling sync --write`
|
|
97
|
+
# already sets. `canon records push` refuses outright for the reason
|
|
98
|
+
# `.claude/context/development/scratch.md` records, so the two still differ.
|
|
99
|
+
# The sibling SANDBOX_ flags are presence tests, so any non-empty value turns
|
|
100
|
+
# them on. This one allowlists instead, because a presence test would have
|
|
101
|
+
# SANDBOX_ANCHOR_CREATE=false provisioning a repository. Both spellings are
|
|
102
|
+
# accepted so the `true` those siblings are set to does not land on a refusal.
|
|
103
|
+
case "${SANDBOX_ANCHOR_CREATE:-}" in
|
|
104
|
+
1 | true) ;;
|
|
105
|
+
*) log_error "${GITHUB_ORG}/${repo_name} does not exist. Check GITHUB_ORG and whether a rename is pending, then create it with 'gh repo create ${GITHUB_ORG}/${repo_name} --private' or re-run with SANDBOX_ANCHOR_CREATE=true." ;;
|
|
106
|
+
esac
|
|
107
|
+
|
|
108
|
+
log_warn "${GITHUB_ORG}/${repo_name} does not exist and SANDBOX_ANCHOR_CREATE is set. Creating it as private."
|
|
109
|
+
if ! gh_error="$(gh repo create "${GITHUB_ORG}/${repo_name}" --private 2>&1)"; then
|
|
110
|
+
log_error "Could not create ${GITHUB_ORG}/${repo_name}: ${gh_error}"
|
|
111
|
+
fi
|
|
112
|
+
log_info "Created ${GITHUB_ORG}/${repo_name} as a private repository."
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# A remote is useless without an author, so the scenarios that reach one always
|
|
116
|
+
# configure both. configure_sandbox_git_identity stays callable on its own for
|
|
117
|
+
# the scenarios that never push. The probe runs first so an absent remote is
|
|
118
|
+
# reported before the scenario stages anything. The remove keeps this idempotent
|
|
119
|
+
# against a sandbox tree that already carries an origin.
|
|
120
|
+
configure_sandbox_anchor_remote() {
|
|
121
|
+
ensure_sandbox_anchor_repo "$@"
|
|
122
|
+
configure_sandbox_git_identity
|
|
123
|
+
git remote remove origin 2>/dev/null || true
|
|
124
|
+
git remote add origin "$(sandbox_anchor_url "$@")"
|
|
125
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# The sandbox tree lives outside the toolkit worktree. `scripts/sandbox/run.sh`
|
|
4
|
+
# sets cwd to it for `claude -p`, and every `CLAUDE.md` between that cwd and the
|
|
5
|
+
# filesystem root loads into the session. Under the repository the toolkit's own
|
|
6
|
+
# instructions join that chain beside the seeded copy the scenario installed,
|
|
7
|
+
# both carry the rule sending shared session scratch to the main worktree root,
|
|
8
|
+
# and nothing decides which root wins. A session picking the toolkit writes its
|
|
9
|
+
# output where no manifest reads it, so the run reports success while the verdict
|
|
10
|
+
# reports no writes at all. `scripts/eval/run.sh` keeps its fixture outside the
|
|
11
|
+
# repository for the same reason.
|
|
12
|
+
#
|
|
13
|
+
# Mints a short random per-run identifier the first time it is asked for, then
|
|
14
|
+
# holds it in CANON_SANDBOX_RUN_ID for the rest of this process. A direct call
|
|
15
|
+
# (not `$(...)`) exports it into the caller's own shell, which is what lets
|
|
16
|
+
# `run.sh` mint once and have manage-sandbox.sh and the check it shells out to
|
|
17
|
+
# both inherit the same id as ordinary children. A call already carrying the
|
|
18
|
+
# variable, inherited from such a parent, reuses it rather than minting a new one.
|
|
19
|
+
#
|
|
20
|
+
# Twin of `mintSandboxRunId` in `src/commands/sandbox.ts`.
|
|
21
|
+
mint_sandbox_run_id() {
|
|
22
|
+
if [ -z "${CANON_SANDBOX_RUN_ID:-}" ]; then
|
|
23
|
+
CANON_SANDBOX_RUN_ID="$(date +%s)-$$-$RANDOM"
|
|
24
|
+
fi
|
|
25
|
+
export CANON_SANDBOX_RUN_ID
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# The base every per-run tree nests under, with no run id appended. Split out
|
|
29
|
+
# of `resolve_sandbox_dir` so a caller that needs to recognize any run's tree,
|
|
30
|
+
# such as `require_project_root` in `scripts/lib/ui.sh`, tests against this
|
|
31
|
+
# prefix instead of a single resolved path that changes on every call.
|
|
32
|
+
sandbox_dir_prefix() {
|
|
33
|
+
printf '%s/canon/sandbox\n' "${XDG_STATE_HOME:-$HOME/.local/state}"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Twin of `sandboxTree` in `src/commands/sandbox.ts`. The exec boundary rules out
|
|
37
|
+
# a shared constant, so a change to the default lands on both sides.
|
|
38
|
+
#
|
|
39
|
+
# A bare fall-through with no per-run component is one path per machine, so
|
|
40
|
+
# two sessions resolving the default at once would provision over each other
|
|
41
|
+
# with neither told. `mint_sandbox_run_id` is what makes two such sessions
|
|
42
|
+
# land on two different trees rather than one.
|
|
43
|
+
resolve_sandbox_dir() {
|
|
44
|
+
if [ -n "${CANON_SANDBOX_DIR:-}" ]; then
|
|
45
|
+
printf '%s\n' "$CANON_SANDBOX_DIR"
|
|
46
|
+
return 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
mint_sandbox_run_id
|
|
50
|
+
printf '%s-%s\n' "$(sandbox_dir_prefix)" "$CANON_SANDBOX_RUN_ID"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Collapses repeated separators, folds `.` and `..` segments, and strips every
|
|
54
|
+
# trailing separator, leaving a bare root as `/`. Every comparison below is a
|
|
55
|
+
# string test, so `//`, `$HOME//`, and `$HOME/../../usr` each read as a path no
|
|
56
|
+
# rule names until this runs, and an unresolved `..` defeats the allowlist and
|
|
57
|
+
# both directions of the repository test at once.
|
|
58
|
+
#
|
|
59
|
+
# The fold is lexical because the guard runs before provisioning creates the
|
|
60
|
+
# tree, which rules out `cd` with `pwd -P` and any resolution needing the path
|
|
61
|
+
# to exist. Nothing here follows a symlink, so a `..` below one resolves against
|
|
62
|
+
# the link's own path rather than its target. A `..` climbing past the root
|
|
63
|
+
# clamps to `/`, matching the kernel, which leaves the allowlist to refuse it
|
|
64
|
+
# under the rule that already covers every root path.
|
|
65
|
+
normalize_sandbox_path() {
|
|
66
|
+
local path="$1"
|
|
67
|
+
|
|
68
|
+
[ -n "$path" ] || return 0
|
|
69
|
+
|
|
70
|
+
while [ "$path" != "${path//\/\//\/}" ]; do
|
|
71
|
+
path="${path//\/\//\/}"
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
local root=""
|
|
75
|
+
if [ "${path#/}" != "$path" ]; then
|
|
76
|
+
root="/"
|
|
77
|
+
path="${path#/}"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# `resolved` carries each kept segment behind its own separator, so a pop is
|
|
81
|
+
# one suffix removal and popping an empty stack is the no-op that clamps at
|
|
82
|
+
# the root. `climbed` holds the leading `..` a relative path has no segment to
|
|
83
|
+
# pop against, which dropping would change the directory it names.
|
|
84
|
+
local resolved="" climbed="" segment
|
|
85
|
+
local remaining=4096
|
|
86
|
+
|
|
87
|
+
while [ -n "$path" ] && [ "$remaining" -gt 0 ]; do
|
|
88
|
+
remaining=$((remaining - 1))
|
|
89
|
+
|
|
90
|
+
segment="${path%%/*}"
|
|
91
|
+
if [ "$segment" = "$path" ]; then
|
|
92
|
+
path=""
|
|
93
|
+
else
|
|
94
|
+
path="${path#*/}"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
case "$segment" in
|
|
98
|
+
"" | .) ;;
|
|
99
|
+
..)
|
|
100
|
+
if [ -n "$resolved" ]; then
|
|
101
|
+
resolved="${resolved%/*}"
|
|
102
|
+
elif [ -z "$root" ]; then
|
|
103
|
+
climbed="$climbed../"
|
|
104
|
+
fi
|
|
105
|
+
;;
|
|
106
|
+
*) resolved="$resolved/$segment" ;;
|
|
107
|
+
esac
|
|
108
|
+
done
|
|
109
|
+
|
|
110
|
+
if [ -n "$root" ]; then
|
|
111
|
+
path="${resolved:-/}"
|
|
112
|
+
else
|
|
113
|
+
path="${climbed}${resolved#/}"
|
|
114
|
+
path="${path:-.}"
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
while [ "${#path}" -gt 1 ] && [ "${path%/}" != "$path" ]; do
|
|
118
|
+
path="${path%/}"
|
|
119
|
+
done
|
|
120
|
+
|
|
121
|
+
printf '%s' "$path"
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# Whether `candidate` is `target` or a directory containing it. Removing the
|
|
125
|
+
# former removes the latter, which is what makes an ancestor as dangerous as an
|
|
126
|
+
# exact match.
|
|
127
|
+
is_at_or_above() {
|
|
128
|
+
local candidate="$1"
|
|
129
|
+
local target="$2"
|
|
130
|
+
|
|
131
|
+
[ "$candidate" = "$target" ] || [ "${target#"$candidate"/}" != "$target" ]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Prints the reason a location is unusable and returns non-zero, so the caller
|
|
135
|
+
# reports one message naming the path rather than a bare refusal.
|
|
136
|
+
#
|
|
137
|
+
# Provisioning runs `rm -rf` on this path at three sites before staging, so the
|
|
138
|
+
# test is an allowlist rather than a list of paths to refuse. A blocklist has to
|
|
139
|
+
# name every system directory to be right once and stays wrong as soon as one is
|
|
140
|
+
# missed, while requiring a strict descendant of the home directory or of the
|
|
141
|
+
# temp root admits the default and every reasonable override and refuses `/`,
|
|
142
|
+
# `/usr`, `/etc`, and `$HOME` itself without naming any of them.
|
|
143
|
+
#
|
|
144
|
+
# The repository test is separate and runs both ways. A path under the worktree
|
|
145
|
+
# restores the ancestor chain the relocation removed, and a path above it is one
|
|
146
|
+
# `rm -rf` away from deleting the repository. It resolves the main worktree root
|
|
147
|
+
# rather than trusting `$PROJECT_ROOT`, since a linked worktree is itself inside
|
|
148
|
+
# that root.
|
|
149
|
+
assert_sandbox_dir_safe() {
|
|
150
|
+
local raw="$1"
|
|
151
|
+
local root="${2:-${PROJECT_ROOT:-$PWD}}"
|
|
152
|
+
|
|
153
|
+
if [ -z "$raw" ] || [ "${raw#/}" = "$raw" ]; then
|
|
154
|
+
printf 'CANON_SANDBOX_DIR must be an absolute path, got: %s\n' "${raw:-<empty>}"
|
|
155
|
+
return 1
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# `normalize_sandbox_path` stops at 4096 segments and drops the remainder,
|
|
159
|
+
# which would hand the tests below an ancestor of the path provisioning
|
|
160
|
+
# removes. Refusing past `PATH_MAX` keeps that bound out of reach, since a
|
|
161
|
+
# segment costs at least two bytes and no syscall accepts the string anyway.
|
|
162
|
+
if [ "${#raw}" -gt 4096 ]; then
|
|
163
|
+
printf 'Refusing the sandbox path. It is %s characters, past the longest path any filesystem here accepts.\n' "${#raw}"
|
|
164
|
+
return 1
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
local dir home temp
|
|
168
|
+
dir="$(normalize_sandbox_path "$raw")"
|
|
169
|
+
home="$(normalize_sandbox_path "${HOME:-/root}")"
|
|
170
|
+
temp="$(normalize_sandbox_path "${TMPDIR:-/tmp}")"
|
|
171
|
+
|
|
172
|
+
# Every message below names `$raw`, which is what the operator set. The tests
|
|
173
|
+
# compare `$dir`, so a path carrying `..` is refused for a location its own
|
|
174
|
+
# spelling does not show.
|
|
175
|
+
local resolution=""
|
|
176
|
+
[ "$dir" = "$raw" ] || resolution=" It resolves to $dir."
|
|
177
|
+
|
|
178
|
+
if ! is_at_or_above "$home" "$dir" && ! is_at_or_above "$temp" "$dir"; then
|
|
179
|
+
printf 'Refusing %s as the sandbox. Provisioning removes the tree first, so the path has to sit under %s or %s.%s\n' "$raw" "$home" "$temp" "$resolution"
|
|
180
|
+
return 1
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
if [ "$dir" = "$home" ] || [ "$dir" = "$temp" ]; then
|
|
184
|
+
printf 'Refusing %s as the sandbox. Provisioning removes the tree first, so the path has to sit under %s rather than be it.\n' "$raw" "$dir"
|
|
185
|
+
return 1
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
local main_root
|
|
189
|
+
main_root="$(git -C "$root" worktree list --porcelain 2>/dev/null |
|
|
190
|
+
grep -m 1 '^worktree ' | cut -d' ' -f2-)"
|
|
191
|
+
main_root="$(normalize_sandbox_path "${main_root:-$root}")"
|
|
192
|
+
|
|
193
|
+
if is_at_or_above "$dir" "$main_root"; then
|
|
194
|
+
printf 'Refusing %s as the sandbox. Provisioning removes the tree first, and that path contains %s.%s\n' "$raw" "$main_root" "$resolution"
|
|
195
|
+
return 1
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
case "$dir" in
|
|
199
|
+
"$main_root"/*)
|
|
200
|
+
printf 'Sandbox at %s sits inside %s, which puts the toolkit CLAUDE.md back on the session ancestor chain.%s Point CANON_SANDBOX_DIR outside the repository.\n' "$raw" "$main_root" "$resolution"
|
|
201
|
+
return 1
|
|
202
|
+
;;
|
|
203
|
+
esac
|
|
204
|
+
|
|
205
|
+
return 0
|
|
206
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
TOOLING_STACK_EXCLUDE=("claude")
|
|
4
|
+
|
|
5
|
+
is_tooling_stack_excluded() {
|
|
6
|
+
local name="$1"
|
|
7
|
+
local excluded
|
|
8
|
+
for excluded in "${TOOLING_STACK_EXCLUDE[@]}"; do
|
|
9
|
+
if [ "$name" = "$excluded" ]; then
|
|
10
|
+
return 0
|
|
11
|
+
fi
|
|
12
|
+
done
|
|
13
|
+
return 1
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
list_tooling_stacks() {
|
|
17
|
+
local tooling_dir="${1:-$PROJECT_ROOT/tooling}"
|
|
18
|
+
local name
|
|
19
|
+
while IFS= read -r entry; do
|
|
20
|
+
name=$(basename "$entry")
|
|
21
|
+
is_tooling_stack_excluded "$name" && continue
|
|
22
|
+
echo "$name"
|
|
23
|
+
done < <(find "$tooling_dir" -mindepth 1 -maxdepth 1 -type d | sort)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Seed roots that carry a `.claude/`, emitted relative to `PROJECT_ROOT`. Every
|
|
27
|
+
# stage measuring seed content discovers through this rather than naming a stack,
|
|
28
|
+
# so a stack seeding `.claude/` later arrives covered with no edit to any caller.
|
|
29
|
+
collect_seed_roots() {
|
|
30
|
+
local dir
|
|
31
|
+
for dir in "$PROJECT_ROOT"/tooling/*/seeds; do
|
|
32
|
+
[ -d "$dir/.claude" ] || continue
|
|
33
|
+
printf '%s\n' "${dir#"$PROJECT_ROOT"/}"
|
|
34
|
+
done
|
|
35
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
if [ "${BASH_VERSINFO[0]:-0}" -lt 4 ]; then
|
|
4
|
+
echo "canon requires bash 4 or newer. Current: ${BASH_VERSION:-unknown}." >&2
|
|
5
|
+
echo "Install via Homebrew: brew install bash" >&2
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
# Resolved from this file's own location rather than `$PROJECT_ROOT`, because
|
|
10
|
+
# `require_project_root` is what several scripts call before anything has
|
|
11
|
+
# established a root.
|
|
12
|
+
# shellcheck source=/dev/null
|
|
13
|
+
source "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/sandbox-path.sh"
|
|
14
|
+
|
|
15
|
+
# `NO_COLOR` follows the published convention, where any non-empty value turns
|
|
16
|
+
# color off whatever the value says.
|
|
17
|
+
supports_color() {
|
|
18
|
+
[ -z "${NO_COLOR:-}" ] && [ -t "$1" ]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Assigns the six palette names for one file descriptor. The blank palette keeps
|
|
22
|
+
# every frame character and drops only the escapes, so a captured run still
|
|
23
|
+
# reads as one block.
|
|
24
|
+
#
|
|
25
|
+
# Bash returns a string and nothing richer, so the palette arrives through the
|
|
26
|
+
# caller's own scope. A writer declaring all six `local` before calling this
|
|
27
|
+
# keeps the assignment to itself, which is what leaves the source-time answer
|
|
28
|
+
# below standing for anything that sources this file.
|
|
29
|
+
set_palette() {
|
|
30
|
+
if supports_color "$1"; then
|
|
31
|
+
GREEN='\033[0;32m'
|
|
32
|
+
RED='\033[0;31m'
|
|
33
|
+
YELLOW='\033[0;33m'
|
|
34
|
+
WHITE='\033[1;37m'
|
|
35
|
+
GREY='\033[0;90m'
|
|
36
|
+
NC='\033[0m'
|
|
37
|
+
else
|
|
38
|
+
GREEN=''
|
|
39
|
+
RED=''
|
|
40
|
+
YELLOW=''
|
|
41
|
+
WHITE=''
|
|
42
|
+
GREY=''
|
|
43
|
+
NC=''
|
|
44
|
+
fi
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Every writer below frames to stderr and asks about that stream at write time,
|
|
48
|
+
# so no answer is frozen before a caller's redirect is in place. This one answers
|
|
49
|
+
# for stdout instead, because it is read by a sourcing script writing its own
|
|
50
|
+
# frame with a bare `echo`, and that is the stream a bare `echo` reaches.
|
|
51
|
+
set_palette 1
|
|
52
|
+
|
|
53
|
+
log_info() {
|
|
54
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
55
|
+
set_palette 2
|
|
56
|
+
echo -e "${GREY}│${NC} ${GREEN}✓${NC} $1" >&2
|
|
57
|
+
}
|
|
58
|
+
log_warn() {
|
|
59
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
60
|
+
set_palette 2
|
|
61
|
+
echo -e "${GREY}│${NC} ${YELLOW}!${NC} $1" >&2
|
|
62
|
+
}
|
|
63
|
+
log_error() {
|
|
64
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
65
|
+
set_palette 2
|
|
66
|
+
echo -e "${GREY}│${NC} ${RED}✗${NC} $1" >&2
|
|
67
|
+
exit 1
|
|
68
|
+
}
|
|
69
|
+
log_step() {
|
|
70
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
71
|
+
set_palette 2
|
|
72
|
+
echo -e "${GREY}│${NC}\n${GREY}├${NC} ${WHITE}$1${NC}" >&2
|
|
73
|
+
}
|
|
74
|
+
log_add() {
|
|
75
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
76
|
+
set_palette 2
|
|
77
|
+
echo -e "${GREY}│${NC} ${GREEN}+${NC} $1" >&2
|
|
78
|
+
}
|
|
79
|
+
log_rem() {
|
|
80
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
81
|
+
set_palette 2
|
|
82
|
+
echo -e "${GREY}│${NC} ${RED}-${NC} $1" >&2
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
pipe_output() {
|
|
86
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
87
|
+
set_palette 2
|
|
88
|
+
while IFS= read -r line; do echo -e "${GREY}│${NC} $line" >&2; done
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
open_timeline() {
|
|
92
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
93
|
+
set_palette 2
|
|
94
|
+
echo -e "${GREY}┌${NC}" >&2
|
|
95
|
+
if [ -n "${1:-}" ]; then
|
|
96
|
+
echo -e "${GREY}│${NC} ${WHITE}$1${NC}" >&2
|
|
97
|
+
fi
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
close_timeline() {
|
|
101
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
102
|
+
set_palette 2
|
|
103
|
+
echo -e "${GREY}└${NC}" >&2
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
guard_root() {
|
|
107
|
+
local target="$1"
|
|
108
|
+
local target_abs
|
|
109
|
+
target_abs=$(cd "$target" && pwd)
|
|
110
|
+
if [ "$target_abs" = "$PROJECT_ROOT" ]; then
|
|
111
|
+
log_error "Cannot run against toolkit root. Files here are the source of truth."
|
|
112
|
+
fi
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
require_project_root() {
|
|
116
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
117
|
+
set_palette 2
|
|
118
|
+
local sandbox in_sandbox=0
|
|
119
|
+
if [ -n "${CANON_SANDBOX_DIR:-}" ]; then
|
|
120
|
+
sandbox="$CANON_SANDBOX_DIR"
|
|
121
|
+
[[ "$PWD" == "$sandbox" || "$PWD" == "$sandbox"/* ]] && in_sandbox=1
|
|
122
|
+
else
|
|
123
|
+
sandbox="$(sandbox_dir_prefix)"
|
|
124
|
+
[[ "$PWD" == "$sandbox" || "$PWD" == "$sandbox"/* || "$PWD" == "$sandbox"-* ]] && in_sandbox=1
|
|
125
|
+
fi
|
|
126
|
+
if [ "$in_sandbox" -eq 1 ]; then
|
|
127
|
+
echo -e "${GREY}┌${NC}" >&2
|
|
128
|
+
log_error "Execution restricted: Command cannot be run from inside the sandbox environment."
|
|
129
|
+
fi
|
|
130
|
+
if [[ "$PWD" != "$PROJECT_ROOT"* ]]; then
|
|
131
|
+
echo -e "${GREY}┌${NC}" >&2
|
|
132
|
+
log_error "Context Error: You must run this command from inside the repository."
|
|
133
|
+
fi
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# The retired spelling stays honored, and permanently. This variable is the
|
|
137
|
+
# documented way to drive any command headlessly, so every skill body, CI job,
|
|
138
|
+
# and operator script already written sets the old name, and those callers live
|
|
139
|
+
# in repositories and plugin caches this release cannot reach. Dropping it
|
|
140
|
+
# leaves them waiting on a TTY nobody is watching.
|
|
141
|
+
is_non_interactive() {
|
|
142
|
+
# canon-keep-retired
|
|
143
|
+
[[ "${CANON_NON_INTERACTIVE:-}" == "1" || "${AITK_NON_INTERACTIVE:-}" == "1" ]]
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
ask() {
|
|
147
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
148
|
+
set_palette 2
|
|
149
|
+
local prompt_text=$1
|
|
150
|
+
local var_name=$2
|
|
151
|
+
local default_val=$3
|
|
152
|
+
local input=""
|
|
153
|
+
local char
|
|
154
|
+
local display_default=""
|
|
155
|
+
if [ -n "$default_val" ]; then
|
|
156
|
+
display_default=" (${default_val})"
|
|
157
|
+
fi
|
|
158
|
+
if is_non_interactive; then
|
|
159
|
+
echo -e "${GREY}│${NC}" >&2
|
|
160
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${default_val}${NC}" >&2
|
|
161
|
+
export "$var_name"="$default_val"
|
|
162
|
+
return
|
|
163
|
+
fi
|
|
164
|
+
echo -e "${GREY}│${NC}" >&2
|
|
165
|
+
echo -ne "${GREEN}◆${NC} ${prompt_text}${display_default} " >&2
|
|
166
|
+
while IFS= read -r -s -n1 char; do
|
|
167
|
+
if [[ $char == $'\x1b' ]]; then
|
|
168
|
+
read -rsn2 -t 0.001 _ || true
|
|
169
|
+
echo -ne "\r\033[K" >&2
|
|
170
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
|
|
171
|
+
exit 1
|
|
172
|
+
elif [[ $char == $'\x7f' || $char == $'\x08' ]]; then
|
|
173
|
+
if [ -n "$input" ]; then
|
|
174
|
+
input="${input%?}"
|
|
175
|
+
echo -ne "\b \b" >&2
|
|
176
|
+
fi
|
|
177
|
+
elif [[ -z "$char" ]]; then
|
|
178
|
+
break
|
|
179
|
+
else
|
|
180
|
+
input+="$char"
|
|
181
|
+
echo -n "$char" >&2
|
|
182
|
+
fi
|
|
183
|
+
done
|
|
184
|
+
[ -z "$input" ] && input="$default_val"
|
|
185
|
+
echo -ne "\r\033[K" >&2
|
|
186
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${input}${NC}" >&2
|
|
187
|
+
export "$var_name"="$input"
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
select_or_route_scenario() {
|
|
191
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
192
|
+
set_palette 2
|
|
193
|
+
local prompt_text=$1
|
|
194
|
+
shift
|
|
195
|
+
local options=("$@")
|
|
196
|
+
|
|
197
|
+
if [ -n "${SANDBOX_SCENARIO:-}" ]; then
|
|
198
|
+
echo -e "${GREY}│${NC}" >&2
|
|
199
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${SANDBOX_SCENARIO}${NC}" >&2
|
|
200
|
+
export SELECTED_OPTION="$SANDBOX_SCENARIO"
|
|
201
|
+
return
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
select_option "$prompt_text" "${options[@]}"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
select_option() {
|
|
208
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
209
|
+
set_palette 2
|
|
210
|
+
local prompt_text=$1
|
|
211
|
+
shift
|
|
212
|
+
local options=("$@")
|
|
213
|
+
local cur=0
|
|
214
|
+
local count=${#options[@]}
|
|
215
|
+
|
|
216
|
+
if is_non_interactive; then
|
|
217
|
+
echo -e "${GREY}│${NC}" >&2
|
|
218
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${options[0]}${NC}" >&2
|
|
219
|
+
export SELECTED_OPTION="${options[0]}"
|
|
220
|
+
return
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
if [ ! -t 0 ]; then
|
|
224
|
+
log_error "${prompt_text} requires a TTY. Pass an argument or set CANON_NON_INTERACTIVE=1."
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
echo -e "${GREY}│${NC}" >&2
|
|
228
|
+
echo -ne "${GREEN}◆${NC} ${prompt_text}\n" >&2
|
|
229
|
+
|
|
230
|
+
while true; do
|
|
231
|
+
for i in "${!options[@]}"; do
|
|
232
|
+
if [ "$i" -eq "$cur" ]; then
|
|
233
|
+
echo -e "${GREY}│${NC} ${GREEN}❯ ${options[$i]}${NC}" >&2
|
|
234
|
+
else
|
|
235
|
+
echo -e "${GREY}│${NC} ${GREY}${options[$i]}${NC}" >&2
|
|
236
|
+
fi
|
|
237
|
+
done
|
|
238
|
+
|
|
239
|
+
read -rsn1 key
|
|
240
|
+
case "$key" in
|
|
241
|
+
$'\x1b')
|
|
242
|
+
if read -rsn2 -t 0.001 key_seq; then
|
|
243
|
+
if [[ "$key_seq" == "[A" ]]; then cur=$(((cur - 1 + count) % count)); fi
|
|
244
|
+
if [[ "$key_seq" == "[B" ]]; then cur=$(((cur + 1) % count)); fi
|
|
245
|
+
else
|
|
246
|
+
echo -ne "\033[$((count + 1))A\033[J" >&2
|
|
247
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
|
|
248
|
+
exit 1
|
|
249
|
+
fi
|
|
250
|
+
;;
|
|
251
|
+
"k") cur=$(((cur - 1 + count) % count)) ;;
|
|
252
|
+
"j") cur=$(((cur + 1) % count)) ;;
|
|
253
|
+
"q")
|
|
254
|
+
echo -ne "\033[$((count + 1))A\033[J" >&2
|
|
255
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
|
|
256
|
+
exit 1
|
|
257
|
+
;;
|
|
258
|
+
"") break ;;
|
|
259
|
+
esac
|
|
260
|
+
echo -ne "\033[${count}A" >&2
|
|
261
|
+
done
|
|
262
|
+
|
|
263
|
+
echo -ne "\033[$((count + 1))A\033[J" >&2
|
|
264
|
+
echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${options[$cur]}${NC}" >&2
|
|
265
|
+
export SELECTED_OPTION="${options[$cur]}"
|
|
266
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Claude Code's worktree entry writes core.bare into the parent repository's
|
|
4
|
+
# shared config and its exit never restores it, stranding every later command in
|
|
5
|
+
# the main worktree. Sourced by verify.sh, which runs the repair before any stage
|
|
6
|
+
# because the flag breaks the git reads that scope the run.
|
|
7
|
+
|
|
8
|
+
repair_bare_flag() {
|
|
9
|
+
local root="${1:-$PROJECT_ROOT}"
|
|
10
|
+
local common_dir
|
|
11
|
+
[ "$(git -C "$root" config --get core.bare 2>/dev/null || echo false)" = true ] || return 0
|
|
12
|
+
|
|
13
|
+
common_dir=$(git -C "$root" rev-parse --path-format=absolute --git-common-dir 2>/dev/null) || return 0
|
|
14
|
+
# A genuinely bare repository keeps its objects at the root and has no .git
|
|
15
|
+
# directory, so it fails this test and keeps its flag.
|
|
16
|
+
[ "$(basename "$common_dir")" = ".git" ] || return 0
|
|
17
|
+
|
|
18
|
+
git -C "$root" config core.bare false
|
|
19
|
+
log_warn "Repaired core.bare, which worktree entry left set. Recovery is 'git config core.bare false'."
|
|
20
|
+
}
|