@erclx/aitk 0.8.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.
Files changed (359) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/claude/.claude-plugin/plugin.json +19 -0
  4. package/claude/skills/bash-script/SKILL.md +96 -0
  5. package/claude/skills/bash-script/references/patterns.md +349 -0
  6. package/claude/skills/ci-workflow/SKILL.md +52 -0
  7. package/claude/skills/ci-workflow/references/workflows.md +74 -0
  8. package/claude/skills/claude-address-review/SKILL.md +107 -0
  9. package/claude/skills/claude-autoship/SKILL.md +137 -0
  10. package/claude/skills/claude-design-extract/SKILL.md +69 -0
  11. package/claude/skills/claude-design-propose/SKILL.md +75 -0
  12. package/claude/skills/claude-diagram/SKILL.md +126 -0
  13. package/claude/skills/claude-docs/SKILL.md +204 -0
  14. package/claude/skills/claude-feature/REQUIREMENT.md +35 -0
  15. package/claude/skills/claude-feature/SKILL.md +148 -0
  16. package/claude/skills/claude-groundwork/SKILL.md +148 -0
  17. package/claude/skills/claude-groundwork/references/folder-format.md +107 -0
  18. package/claude/skills/claude-memory-capture/SKILL.md +80 -0
  19. package/claude/skills/claude-memory-review/REQUIREMENT.md +37 -0
  20. package/claude/skills/claude-memory-review/SKILL.md +206 -0
  21. package/claude/skills/claude-orchestrate/SKILL.md +125 -0
  22. package/claude/skills/claude-pr-review/SKILL.md +150 -0
  23. package/claude/skills/claude-review/SKILL.md +136 -0
  24. package/claude/skills/claude-roadmap/SKILL.md +61 -0
  25. package/claude/skills/claude-roadmap/references/roadmap.md +52 -0
  26. package/claude/skills/claude-screencast/SKILL.md +160 -0
  27. package/claude/skills/claude-seed-sync/SKILL.md +141 -0
  28. package/claude/skills/claude-slides-draft/SKILL.md +62 -0
  29. package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
  30. package/claude/skills/claude-standards-audit/SKILL.md +79 -0
  31. package/claude/skills/claude-standards-audit/references/branch.md +49 -0
  32. package/claude/skills/claude-standards-audit/references/pr.md +124 -0
  33. package/claude/skills/claude-tasks/SKILL.md +123 -0
  34. package/claude/skills/claude-ui-test/SKILL.md +75 -0
  35. package/claude/skills/claude-ux-audit/SKILL.md +78 -0
  36. package/claude/skills/claude-worktree/SKILL.md +79 -0
  37. package/claude/skills/cli-script/SKILL.md +47 -0
  38. package/claude/skills/cli-script/references/template.md +43 -0
  39. package/claude/skills/create-rule/SKILL.md +68 -0
  40. package/claude/skills/create-skill/REQUIREMENT.md +30 -0
  41. package/claude/skills/create-skill/SKILL.md +24 -0
  42. package/claude/skills/create-snippet/SKILL.md +28 -0
  43. package/claude/skills/create-snippet/references/snippets.md +57 -0
  44. package/claude/skills/create-standard/SKILL.md +31 -0
  45. package/claude/skills/create-standard/references/standard.md +52 -0
  46. package/claude/skills/docs-sync/SKILL.md +87 -0
  47. package/claude/skills/git-branch/REQUIREMENT.md +38 -0
  48. package/claude/skills/git-branch/SKILL.md +60 -0
  49. package/claude/skills/git-branch/references/branch.md +49 -0
  50. package/claude/skills/git-commit/REQUIREMENT.md +33 -0
  51. package/claude/skills/git-commit/SKILL.md +51 -0
  52. package/claude/skills/git-commit/references/commit.md +63 -0
  53. package/claude/skills/git-followup/REQUIREMENT.md +38 -0
  54. package/claude/skills/git-followup/SKILL.md +35 -0
  55. package/claude/skills/git-issue/REQUIREMENT.md +38 -0
  56. package/claude/skills/git-issue/SKILL.md +69 -0
  57. package/claude/skills/git-issue/references/issue.md +84 -0
  58. package/claude/skills/git-pr/REQUIREMENT.md +37 -0
  59. package/claude/skills/git-pr/SKILL.md +119 -0
  60. package/claude/skills/git-pr/references/branch.md +49 -0
  61. package/claude/skills/git-pr/references/pr.md +124 -0
  62. package/claude/skills/git-ship/REQUIREMENT.md +34 -0
  63. package/claude/skills/git-ship/SKILL.md +39 -0
  64. package/claude/skills/git-split/REQUIREMENT.md +38 -0
  65. package/claude/skills/git-split/SKILL.md +160 -0
  66. package/claude/skills/git-split/references/branch.md +49 -0
  67. package/claude/skills/git-split/references/pr.md +124 -0
  68. package/claude/skills/git-stage/REQUIREMENT.md +36 -0
  69. package/claude/skills/git-stage/SKILL.md +74 -0
  70. package/claude/skills/git-stage/references/commit.md +63 -0
  71. package/claude/skills/git-worktree/REQUIREMENT.md +37 -0
  72. package/claude/skills/git-worktree/SKILL.md +120 -0
  73. package/claude/skills/migration-claude-md/SKILL.md +74 -0
  74. package/claude/skills/migration-context/SKILL.md +93 -0
  75. package/claude/skills/migration-standards/SKILL.md +75 -0
  76. package/claude/skills/project-commands/SKILL.md +73 -0
  77. package/claude/skills/session-resume/SKILL.md +36 -0
  78. package/claude/skills/setup-gov/SKILL.md +71 -0
  79. package/claude/skills/setup-indexes/SKILL.md +148 -0
  80. package/claude/skills/setup-init/SKILL.md +114 -0
  81. package/claude/skills/setup-plugins/SKILL.md +81 -0
  82. package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
  83. package/claude/skills/setup-verify/SKILL.md +51 -0
  84. package/claude/skills/systematic-debugging/SKILL.md +70 -0
  85. package/claude/skills/toolkit-cli/SKILL.md +38 -0
  86. package/claude/skills/toolkit-feedback/SKILL.md +80 -0
  87. package/claude/skills/toolkit-operator/SKILL.md +45 -0
  88. package/claude/skills/toolkit-triage/SKILL.md +63 -0
  89. package/claude/skills/youtube-transcripts/SKILL.md +34 -0
  90. package/docs/agents.md +371 -0
  91. package/docs/ai-workflow.md +157 -0
  92. package/docs/index.md +20 -0
  93. package/docs/operating-model.md +106 -0
  94. package/docs/target-projects.md +183 -0
  95. package/docs/visual-design-workflow.md +136 -0
  96. package/docs/zshrc-aliases.md +65 -0
  97. package/governance/rules/claude/500-prose.md +12 -0
  98. package/governance/rules/claude/510-context.md +16 -0
  99. package/governance/rules/claude/520-wireframes.md +12 -0
  100. package/governance/rules/claude/530-requirements.md +11 -0
  101. package/governance/rules/claude/540-architecture.md +11 -0
  102. package/governance/rules/claude/550-design.md +11 -0
  103. package/governance/rules/claude/555-tasks.md +12 -0
  104. package/governance/rules/claude/560-diagrams.md +11 -0
  105. package/governance/rules/claude/570-skill.md +18 -0
  106. package/governance/rules/claude/580-readme.md +11 -0
  107. package/governance/rules/claude/590-rule-authoring.md +12 -0
  108. package/governance/rules/core/000-constitution.md +30 -0
  109. package/governance/rules/core/010-testing.md +35 -0
  110. package/governance/rules/core/020-concurrency.md +22 -0
  111. package/governance/rules/core/030-error-handling.md +31 -0
  112. package/governance/rules/core/040-performance.md +20 -0
  113. package/governance/rules/core/050-logging.md +20 -0
  114. package/governance/rules/core/060-naming.md +19 -0
  115. package/governance/rules/core/070-planning.md +13 -0
  116. package/governance/rules/core/080-config-comments.md +22 -0
  117. package/governance/rules/framework/200-react.md +51 -0
  118. package/governance/rules/framework/210-astro.md +41 -0
  119. package/governance/rules/framework/220-fastapi.md +43 -0
  120. package/governance/rules/framework/230-nextjs.md +48 -0
  121. package/governance/rules/framework/250-tailwind.md +32 -0
  122. package/governance/rules/framework/260-shadcn.md +34 -0
  123. package/governance/rules/lang/100-typescript.md +40 -0
  124. package/governance/rules/lang/110-python.md +42 -0
  125. package/governance/rules/lib/300-testing-ts.md +38 -0
  126. package/governance/rules/lib/310-zod.md +25 -0
  127. package/governance/rules/lib/320-tanstack-query.md +32 -0
  128. package/governance/rules/lib/330-testing-py.md +44 -0
  129. package/governance/rules/lib/340-pydantic.md +38 -0
  130. package/governance/rules/lib/350-security-web.md +31 -0
  131. package/governance/rules/ui/400-ui.md +34 -0
  132. package/governance/rules/ui/410-a11y.md +44 -0
  133. package/governance/rules/ui/420-forms.md +34 -0
  134. package/governance/rules/ui/430-ux-completeness.md +62 -0
  135. package/governance/stacks/astro.toml +2 -0
  136. package/governance/stacks/base.toml +2 -0
  137. package/governance/stacks/node.toml +2 -0
  138. package/governance/stacks/python-fastapi.toml +2 -0
  139. package/governance/stacks/python.toml +2 -0
  140. package/governance/stacks/react.toml +2 -0
  141. package/package.json +67 -0
  142. package/scripts/config.sh +11 -0
  143. package/scripts/core/bootstrap.sh +81 -0
  144. package/scripts/core/check-plugin-boundary.sh +45 -0
  145. package/scripts/core/check-skill-paths.sh +25 -0
  146. package/scripts/core/clean.sh +36 -0
  147. package/scripts/core/install-check.sh +93 -0
  148. package/scripts/core/regen-claude-copies.sh +26 -0
  149. package/scripts/core/regen-indexes.sh +10 -0
  150. package/scripts/core/regen-skill-references.sh +27 -0
  151. package/scripts/core/snapshot.sh +132 -0
  152. package/scripts/core/update.sh +35 -0
  153. package/scripts/core/verify.sh +201 -0
  154. package/scripts/docs/list.sh +129 -0
  155. package/scripts/gov/list.sh +234 -0
  156. package/scripts/lib/frontmatter.sh +30 -0
  157. package/scripts/lib/gov.sh +14 -0
  158. package/scripts/lib/sandbox-fixtures.sh +109 -0
  159. package/scripts/lib/sandbox-git.sh +73 -0
  160. package/scripts/lib/tooling.sh +24 -0
  161. package/scripts/lib/ui.sh +173 -0
  162. package/scripts/lib/worktree.sh +20 -0
  163. package/scripts/manage-sandbox.sh +453 -0
  164. package/scripts/snippets/create.sh +156 -0
  165. package/scripts/standards/list.sh +91 -0
  166. package/scripts/tooling/create.sh +109 -0
  167. package/scripts/tooling/ref.sh +141 -0
  168. package/scripts/tooling/verify.sh +179 -0
  169. package/snippets/claude/decision-memo.md +39 -0
  170. package/snippets/claude/feature-recap.md +19 -0
  171. package/snippets/claude/figma-steps.md +18 -0
  172. package/snippets/claude/orchestrator-resume.md +23 -0
  173. package/snippets/claude/orchestrator-sweep.md +10 -0
  174. package/snippets/compact-summary.md +5 -0
  175. package/snippets/create-snippet.md +7 -0
  176. package/snippets/decision-help.md +6 -0
  177. package/snippets/meta-prompt.md +14 -0
  178. package/snippets/research-prompt.md +7 -0
  179. package/snippets/session-notes.md +11 -0
  180. package/snippets/snippets.toml +6 -0
  181. package/snippets/step-by-step.md +10 -0
  182. package/snippets/web-research.md +21 -0
  183. package/src/claude/gitignore.ts +51 -0
  184. package/src/claude/seeds-list.ts +47 -0
  185. package/src/claude/seeds.ts +124 -0
  186. package/src/claude/settings.ts +151 -0
  187. package/src/cli-run.ts +43 -0
  188. package/src/cli.ts +111 -0
  189. package/src/commands/claude.ts +349 -0
  190. package/src/commands/design.ts +39 -0
  191. package/src/commands/docs.ts +59 -0
  192. package/src/commands/feedback-format.ts +23 -0
  193. package/src/commands/feedback.ts +103 -0
  194. package/src/commands/gov.ts +268 -0
  195. package/src/commands/indexes.ts +182 -0
  196. package/src/commands/init.ts +117 -0
  197. package/src/commands/pass-through.ts +39 -0
  198. package/src/commands/sandbox.ts +315 -0
  199. package/src/commands/slides.ts +106 -0
  200. package/src/commands/snippets.ts +236 -0
  201. package/src/commands/standards.ts +89 -0
  202. package/src/commands/sync.ts +211 -0
  203. package/src/commands/tasks.ts +185 -0
  204. package/src/commands/tooling.ts +432 -0
  205. package/src/commands/transcripts.ts +48 -0
  206. package/src/commands/wiki.ts +101 -0
  207. package/src/copy.ts +30 -0
  208. package/src/design/parse.ts +79 -0
  209. package/src/design/render.ts +170 -0
  210. package/src/docs/read.ts +59 -0
  211. package/src/exec.ts +17 -0
  212. package/src/frontmatter.ts +13 -0
  213. package/src/github-format.ts +13 -0
  214. package/src/github.ts +20 -0
  215. package/src/gov/adapter.ts +73 -0
  216. package/src/gov/install.ts +103 -0
  217. package/src/gov/payload.ts +39 -0
  218. package/src/gov/stacks.ts +124 -0
  219. package/src/indexes/frontmatter.ts +46 -0
  220. package/src/indexes/regen.ts +84 -0
  221. package/src/indexes/render.ts +181 -0
  222. package/src/indexes/walk.ts +111 -0
  223. package/src/init/flags.ts +66 -0
  224. package/src/init/plan.ts +128 -0
  225. package/src/init/run.ts +46 -0
  226. package/src/init/steps.ts +91 -0
  227. package/src/sandbox/coverage.ts +115 -0
  228. package/src/sandbox/expect.ts +412 -0
  229. package/src/slides/layouts.ts +391 -0
  230. package/src/slides/open.ts +18 -0
  231. package/src/slides/parse.ts +84 -0
  232. package/src/slides/render.ts +88 -0
  233. package/src/slides/styles.ts +44 -0
  234. package/src/snippets/adapter.ts +34 -0
  235. package/src/snippets/categories.ts +59 -0
  236. package/src/snippets/install.ts +125 -0
  237. package/src/snippets/list.ts +32 -0
  238. package/src/snippets/presets.ts +50 -0
  239. package/src/standards/adapter.ts +51 -0
  240. package/src/standards/index-refresh.ts +44 -0
  241. package/src/standards/install.ts +52 -0
  242. package/src/sync/check.ts +269 -0
  243. package/src/sync/engine.ts +416 -0
  244. package/src/sync/git.ts +204 -0
  245. package/src/sync/stamp.ts +202 -0
  246. package/src/sync/target.ts +79 -0
  247. package/src/sync/workflow.ts +201 -0
  248. package/src/target.ts +43 -0
  249. package/src/tasks/archive.ts +304 -0
  250. package/src/tooling/gitignore.ts +122 -0
  251. package/src/tooling/inject.ts +214 -0
  252. package/src/tooling/list.ts +39 -0
  253. package/src/tooling/manifest.ts +178 -0
  254. package/src/tooling/package.ts +166 -0
  255. package/src/tooling/scan.ts +186 -0
  256. package/src/transcripts/fetch.ts +156 -0
  257. package/src/transcripts/metadata.ts +54 -0
  258. package/src/transcripts/vtt.ts +114 -0
  259. package/src/ui.ts +187 -0
  260. package/src/wiki/init.ts +85 -0
  261. package/standards/architecture.md +41 -0
  262. package/standards/bundled/branch.md +49 -0
  263. package/standards/bundled/commit.md +63 -0
  264. package/standards/bundled/issue.md +84 -0
  265. package/standards/bundled/pr.md +124 -0
  266. package/standards/bundled/roadmap.md +52 -0
  267. package/standards/bundled/snippets.md +57 -0
  268. package/standards/bundled/standard.md +52 -0
  269. package/standards/context.md +132 -0
  270. package/standards/design.md +31 -0
  271. package/standards/diagrams.md +55 -0
  272. package/standards/index.md +21 -0
  273. package/standards/prose.md +122 -0
  274. package/standards/readme.md +163 -0
  275. package/standards/requirements.md +61 -0
  276. package/standards/rule.md +79 -0
  277. package/standards/skill.md +257 -0
  278. package/standards/tasks.md +140 -0
  279. package/standards/versioning.md +47 -0
  280. package/standards/wireframes.md +67 -0
  281. package/tooling/astro/configs/astro.config.mjs +17 -0
  282. package/tooling/astro/configs/eslint.config.js +79 -0
  283. package/tooling/astro/configs/playwright.config.ts +25 -0
  284. package/tooling/astro/configs/tsconfig.json +12 -0
  285. package/tooling/astro/configs/vitest.config.ts +22 -0
  286. package/tooling/astro/manifest.toml +32 -0
  287. package/tooling/astro/reference.md +60 -0
  288. package/tooling/base/configs/.editorconfig +5 -0
  289. package/tooling/base/configs/.github/pull_request_template.md +18 -0
  290. package/tooling/base/configs/.github/workflows/verify.yml +35 -0
  291. package/tooling/base/configs/.husky/commit-msg +1 -0
  292. package/tooling/base/configs/.husky/post-merge +61 -0
  293. package/tooling/base/configs/.husky/post-rewrite +21 -0
  294. package/tooling/base/configs/.husky/pre-commit +1 -0
  295. package/tooling/base/configs/.husky/pre-push +1 -0
  296. package/tooling/base/configs/.prettierrc +12 -0
  297. package/tooling/base/configs/.shellcheckrc +1 -0
  298. package/tooling/base/configs/.vscode/extensions.json +9 -0
  299. package/tooling/base/configs/.vscode/settings.json +3 -0
  300. package/tooling/base/configs/commitlint.config.js +11 -0
  301. package/tooling/base/configs/scripts/clean.sh +45 -0
  302. package/tooling/base/configs/scripts/update.sh +49 -0
  303. package/tooling/base/configs/scripts/verify.sh +64 -0
  304. package/tooling/base/manifest.toml +32 -0
  305. package/tooling/base/reference.md +114 -0
  306. package/tooling/base/seeds/.claude/context/ci.md +27 -0
  307. package/tooling/base/seeds/.claude/context/development.md +32 -0
  308. package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
  309. package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
  310. package/tooling/base/seeds/.lintstagedrc +8 -0
  311. package/tooling/base/seeds/.prettierignore +0 -0
  312. package/tooling/base/seeds/cspell.json +20 -0
  313. package/tooling/claude/manifest.toml +11 -0
  314. package/tooling/claude/reference.md +62 -0
  315. package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
  316. package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
  317. package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
  318. package/tooling/claude/seeds/.claude/context/index.md +8 -0
  319. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +43 -0
  320. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +45 -0
  321. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +61 -0
  322. package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +60 -0
  323. package/tooling/claude/seeds/.claude/settings.json +39 -0
  324. package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
  325. package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
  326. package/tooling/claude/seeds/CLAUDE.md +87 -0
  327. package/tooling/claude/user/settings.template.json +10 -0
  328. package/tooling/claude/user/statusline-command.sh +53 -0
  329. package/tooling/python/configs/.coveragerc +14 -0
  330. package/tooling/python/configs/.python-version +1 -0
  331. package/tooling/python/configs/mypy.ini +6 -0
  332. package/tooling/python/configs/pytest.ini +4 -0
  333. package/tooling/python/configs/ruff.toml +15 -0
  334. package/tooling/python/configs/scripts/verify.sh +77 -0
  335. package/tooling/python/manifest.toml +16 -0
  336. package/tooling/python/reference.md +66 -0
  337. package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
  338. package/tooling/python/seeds/tests/test_smoke.py +2 -0
  339. package/tooling/vite-react/configs/playwright.config.ts +25 -0
  340. package/tooling/vite-react/configs/tsconfig.json +35 -0
  341. package/tooling/vite-react/configs/vite.config.ts +14 -0
  342. package/tooling/vite-react/configs/vitest.config.ts +26 -0
  343. package/tooling/vite-react/manifest.toml +21 -0
  344. package/tooling/vite-react/reference.md +55 -0
  345. package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
  346. package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
  347. package/tooling/web/configs/.github/workflows/verify.yml +134 -0
  348. package/tooling/web/configs/.vscode/extensions.json +13 -0
  349. package/tooling/web/configs/.vscode/settings.json +10 -0
  350. package/tooling/web/configs/e2e/home.spec.ts +6 -0
  351. package/tooling/web/configs/e2e/screenshot.ts +41 -0
  352. package/tooling/web/configs/eslint.config.js +82 -0
  353. package/tooling/web/configs/scripts/screenshot.sh +28 -0
  354. package/tooling/web/configs/scripts/verify.sh +80 -0
  355. package/tooling/web/configs/src/test/setup.ts +8 -0
  356. package/tooling/web/manifest.toml +57 -0
  357. package/tooling/web/reference.md +95 -0
  358. package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
  359. package/tsconfig.json +14 -0
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Fixture files carry this suffix so the repository's own checks ignore them.
4
+ # A stored `index.md.fixture` is not an `index.md`, so the index walker, prettier,
5
+ # shfmt, and shellcheck all skip it and the bytes reach the sandbox unmodified.
6
+ FIXTURE_SUFFIX=".fixture"
7
+
8
+ # The tree mirrors the scenario path, so `category` and `scenario` together match
9
+ # `scripts/sandbox/<category>/<scenario>.sh`. Both segments are load-bearing:
10
+ # four scenario basenames repeat across categories (`claude`, `docs`, `review`,
11
+ # `sync`), and `docs` is also a category of its own.
12
+ fixture_stage_dir() {
13
+ local category="$1"
14
+ local scenario="$2"
15
+ local arm="$3"
16
+ local stage="$4"
17
+ echo "$PROJECT_ROOT/scripts/sandbox/fixtures/$category/$scenario/$arm/$stage"
18
+ }
19
+
20
+ list_fixture_files() {
21
+ local source_dir="$1"
22
+ find "$source_dir" -type f -name "*$FIXTURE_SUFFIX" -print0 | sort -z
23
+ }
24
+
25
+ count_fixture_files() {
26
+ local source_dir="$1"
27
+ if [ ! -d "$source_dir" ]; then
28
+ echo 0
29
+ return 0
30
+ fi
31
+ find "$source_dir" -type f -name "*$FIXTURE_SUFFIX" | wc -l
32
+ }
33
+
34
+ # The copy loops match on the suffix, so a file without one would be skipped in
35
+ # silence and the scenario would provision a tree it was never meant to have.
36
+ assert_fixtures_suffixed() {
37
+ local source_dir="$1"
38
+ [ -d "$source_dir" ] || return 0
39
+
40
+ local stray
41
+ stray="$(find "$source_dir" -type f -not -name "*$FIXTURE_SUFFIX" | sort | tr '\n' ' ')"
42
+ [ -z "$stray" ] || log_error "Fixture missing the $FIXTURE_SUFFIX suffix: $stray"
43
+ }
44
+
45
+ fixture_target_path() {
46
+ local source_dir="$1"
47
+ local source_file="$2"
48
+ local relative="${source_file#"$source_dir"/}"
49
+ echo "${relative%"$FIXTURE_SUFFIX"}"
50
+ }
51
+
52
+ create_from_fixtures() {
53
+ local source_dir="$1"
54
+ [ -d "$source_dir" ] || return 0
55
+
56
+ local source_file target
57
+ while IFS= read -r -d '' source_file; do
58
+ target="$(fixture_target_path "$source_dir" "$source_file")"
59
+ mkdir -p "$(dirname "$target")"
60
+ cp "$source_file" "$target"
61
+ done < <(list_fixture_files "$source_dir")
62
+ }
63
+
64
+ # An append fixture extends a file the anchor or the injected seeds already
65
+ # provide. A missing target means that upstream shape changed, so fail rather
66
+ # than create the file and silently alter what the scenario provisions.
67
+ append_from_fixtures() {
68
+ local source_dir="$1"
69
+ [ -d "$source_dir" ] || return 0
70
+
71
+ local source_file target
72
+ while IFS= read -r -d '' source_file; do
73
+ target="$(fixture_target_path "$source_dir" "$source_file")"
74
+ if [ ! -f "$target" ]; then
75
+ log_error "Append fixture has no target: $target"
76
+ fi
77
+ cat "$source_file" >>"$target"
78
+ done < <(list_fixture_files "$source_dir")
79
+ }
80
+
81
+ # Stages one step of a scenario arm into the sandbox working directory.
82
+ # Scenarios call this once per step so their own git operations stay between
83
+ # the steps, where they are visible.
84
+ stage_fixtures() {
85
+ local category="$1"
86
+ local scenario="$2"
87
+ local arm="$3"
88
+ local stage="$4"
89
+
90
+ local stage_dir
91
+ stage_dir="$(fixture_stage_dir "$category" "$scenario" "$arm" "$stage")"
92
+
93
+ if [ ! -d "$stage_dir" ]; then
94
+ log_error "Fixture stage not found: $category/$scenario/$arm/$stage"
95
+ fi
96
+
97
+ assert_fixtures_suffixed "$stage_dir/create"
98
+ assert_fixtures_suffixed "$stage_dir/append"
99
+
100
+ local staged
101
+ staged=$(($(count_fixture_files "$stage_dir/create") + \
102
+ $(count_fixture_files "$stage_dir/append")))
103
+ if [ "$staged" -eq 0 ]; then
104
+ log_error "Fixture stage provisions nothing: $category/$scenario/$arm/$stage"
105
+ fi
106
+
107
+ create_from_fixtures "$stage_dir/create"
108
+ append_from_fixtures "$stage_dir/append"
109
+ }
@@ -0,0 +1,73 @@
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
+ sandbox_anchor_url() {
19
+ local repo_name="${1:-${ANCHOR_REPO:-}}"
20
+
21
+ if [ -z "$repo_name" ] || [ -z "${GITHUB_ORG:-}" ]; then
22
+ log_error "sandbox_anchor_url needs GITHUB_ORG and a repository name. Call require_sandbox_anchor_config first."
23
+ fi
24
+
25
+ printf 'https://github.com/%s/%s.git\n' "$GITHUB_ORG" "$repo_name"
26
+ }
27
+
28
+ # credential.helper is multi-valued and git concatenates it across system, global,
29
+ # and local, trying each in order until one returns a credential. A plain set
30
+ # leaves an operator's existing helper ahead of this one, so a stale token wins
31
+ # and gh never runs. The empty value resets the inherited list first.
32
+ configure_sandbox_git_credentials() {
33
+ git config credential.helper ""
34
+ git config --add credential.helper "$SANDBOX_GIT_CREDENTIAL_HELPER"
35
+ }
36
+
37
+ resolve_sandbox_git_identity() {
38
+ SANDBOX_GIT_NAME="${SANDBOX_GIT_NAME:-$(git config --global user.name 2>/dev/null || true)}"
39
+ SANDBOX_GIT_EMAIL="${SANDBOX_GIT_EMAIL:-$(git config --global user.email 2>/dev/null || true)}"
40
+
41
+ : "${SANDBOX_GIT_NAME:=aitk-sandbox}"
42
+ : "${SANDBOX_GIT_EMAIL:=sandbox@example.com}"
43
+
44
+ export SANDBOX_GIT_NAME SANDBOX_GIT_EMAIL
45
+ }
46
+
47
+ configure_sandbox_git_identity() {
48
+ resolve_sandbox_git_identity
49
+ git config user.name "$SANDBOX_GIT_NAME"
50
+ git config user.email "$SANDBOX_GIT_EMAIL"
51
+ }
52
+
53
+ # Every scenario that needs a remote points at the same throwaway repository, so
54
+ # the name lives here rather than in each one.
55
+ SANDBOX_ANCHOR_REPO="toolkit-sandbox"
56
+
57
+ # A scenario calls this from its own use_anchor hook rather than this file
58
+ # defining the hook. manage-sandbox.sh keys off `type -t use_anchor`, so
59
+ # declaring it here would hand an anchor to the scenarios that source this file
60
+ # for the identity helpers alone.
61
+ use_sandbox_anchor() {
62
+ export ANCHOR_REPO="${1:-$SANDBOX_ANCHOR_REPO}"
63
+ }
64
+
65
+ # A remote is useless without an author, so the scenarios that reach one always
66
+ # configure both. configure_sandbox_git_identity stays callable on its own for
67
+ # the scenarios that never push. The remove keeps this idempotent against a
68
+ # sandbox tree that already carries an origin.
69
+ configure_sandbox_anchor_remote() {
70
+ configure_sandbox_git_identity
71
+ git remote remove origin 2>/dev/null || true
72
+ git remote add origin "$(sandbox_anchor_url "$@")"
73
+ }
@@ -0,0 +1,24 @@
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
+ }
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if [ "${BASH_VERSINFO[0]:-0}" -lt 4 ]; then
4
+ echo "aitk 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
+ GREEN='\033[0;32m'
10
+ RED='\033[0;31m'
11
+ YELLOW='\033[0;33m'
12
+ WHITE='\033[1;37m'
13
+ GREY='\033[0;90m'
14
+ NC='\033[0m'
15
+
16
+ log_info() { echo -e "${GREY}│${NC} ${GREEN}✓${NC} $1" >&2; }
17
+ log_warn() { echo -e "${GREY}│${NC} ${YELLOW}!${NC} $1" >&2; }
18
+ log_error() {
19
+ echo -e "${GREY}│${NC} ${RED}✗${NC} $1" >&2
20
+ exit 1
21
+ }
22
+ log_step() { echo -e "${GREY}│${NC}\n${GREY}├${NC} ${WHITE}$1${NC}" >&2; }
23
+ log_add() { echo -e "${GREY}│${NC} ${GREEN}+${NC} $1" >&2; }
24
+ log_rem() { echo -e "${GREY}│${NC} ${RED}-${NC} $1" >&2; }
25
+
26
+ pipe_output() { while IFS= read -r line; do echo -e "${GREY}│${NC} $line" >&2; done; }
27
+
28
+ open_timeline() {
29
+ echo -e "${GREY}┌${NC}" >&2
30
+ if [ -n "${1:-}" ]; then
31
+ echo -e "${GREY}│${NC} ${WHITE}$1${NC}" >&2
32
+ fi
33
+ }
34
+
35
+ close_timeline() {
36
+ echo -e "${GREY}└${NC}" >&2
37
+ }
38
+
39
+ guard_root() {
40
+ local target="$1"
41
+ local target_abs
42
+ target_abs=$(cd "$target" && pwd)
43
+ if [ "$target_abs" = "$PROJECT_ROOT" ]; then
44
+ log_error "Cannot run against toolkit root. Files here are the source of truth."
45
+ fi
46
+ }
47
+
48
+ require_project_root() {
49
+ if [[ "$PWD" == *".sandbox"* ]]; then
50
+ echo -e "${GREY}┌${NC}" >&2
51
+ log_error "Execution restricted: Command cannot be run from inside the sandbox environment."
52
+ fi
53
+ if [[ "$PWD" != "$PROJECT_ROOT"* ]]; then
54
+ echo -e "${GREY}┌${NC}" >&2
55
+ log_error "Context Error: You must run this command from inside the repository."
56
+ fi
57
+ }
58
+
59
+ ask() {
60
+ local prompt_text=$1
61
+ local var_name=$2
62
+ local default_val=$3
63
+ local input=""
64
+ local char
65
+ local display_default=""
66
+ if [ -n "$default_val" ]; then
67
+ display_default=" (${default_val})"
68
+ fi
69
+ if [[ "${AITK_NON_INTERACTIVE:-}" == "1" ]]; then
70
+ echo -e "${GREY}│${NC}" >&2
71
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${default_val}${NC}" >&2
72
+ export "$var_name"="$default_val"
73
+ return
74
+ fi
75
+ echo -e "${GREY}│${NC}" >&2
76
+ echo -ne "${GREEN}◆${NC} ${prompt_text}${display_default} " >&2
77
+ while IFS= read -r -s -n1 char; do
78
+ if [[ $char == $'\x1b' ]]; then
79
+ read -rsn2 -t 0.001 _ || true
80
+ echo -ne "\r\033[K" >&2
81
+ echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
82
+ exit 1
83
+ elif [[ $char == $'\x7f' || $char == $'\x08' ]]; then
84
+ if [ -n "$input" ]; then
85
+ input="${input%?}"
86
+ echo -ne "\b \b" >&2
87
+ fi
88
+ elif [[ -z "$char" ]]; then
89
+ break
90
+ else
91
+ input+="$char"
92
+ echo -n "$char" >&2
93
+ fi
94
+ done
95
+ [ -z "$input" ] && input="$default_val"
96
+ echo -ne "\r\033[K" >&2
97
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${input}${NC}" >&2
98
+ export "$var_name"="$input"
99
+ }
100
+
101
+ select_or_route_scenario() {
102
+ local prompt_text=$1
103
+ shift
104
+ local options=("$@")
105
+
106
+ if [ -n "${SANDBOX_SCENARIO:-}" ]; then
107
+ echo -e "${GREY}│${NC}" >&2
108
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${SANDBOX_SCENARIO}${NC}" >&2
109
+ export SELECTED_OPTION="$SANDBOX_SCENARIO"
110
+ return
111
+ fi
112
+
113
+ select_option "$prompt_text" "${options[@]}"
114
+ }
115
+
116
+ select_option() {
117
+ local prompt_text=$1
118
+ shift
119
+ local options=("$@")
120
+ local cur=0
121
+ local count=${#options[@]}
122
+
123
+ if [[ "${AITK_NON_INTERACTIVE:-}" == "1" ]]; then
124
+ echo -e "${GREY}│${NC}" >&2
125
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${options[0]}${NC}" >&2
126
+ export SELECTED_OPTION="${options[0]}"
127
+ return
128
+ fi
129
+
130
+ if [ ! -t 0 ]; then
131
+ log_error "${prompt_text} requires a TTY. Pass an argument or set AITK_NON_INTERACTIVE=1."
132
+ fi
133
+
134
+ echo -e "${GREY}│${NC}" >&2
135
+ echo -ne "${GREEN}◆${NC} ${prompt_text}\n" >&2
136
+
137
+ while true; do
138
+ for i in "${!options[@]}"; do
139
+ if [ "$i" -eq "$cur" ]; then
140
+ echo -e "${GREY}│${NC} ${GREEN}❯ ${options[$i]}${NC}" >&2
141
+ else
142
+ echo -e "${GREY}│${NC} ${GREY}${options[$i]}${NC}" >&2
143
+ fi
144
+ done
145
+
146
+ read -rsn1 key
147
+ case "$key" in
148
+ $'\x1b')
149
+ if read -rsn2 -t 0.001 key_seq; then
150
+ if [[ "$key_seq" == "[A" ]]; then cur=$(((cur - 1 + count) % count)); fi
151
+ if [[ "$key_seq" == "[B" ]]; then cur=$(((cur + 1) % count)); fi
152
+ else
153
+ echo -ne "\033[$((count + 1))A\033[J" >&2
154
+ echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
155
+ exit 1
156
+ fi
157
+ ;;
158
+ "k") cur=$(((cur - 1 + count) % count)) ;;
159
+ "j") cur=$(((cur + 1) % count)) ;;
160
+ "q")
161
+ echo -ne "\033[$((count + 1))A\033[J" >&2
162
+ echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
163
+ exit 1
164
+ ;;
165
+ "") break ;;
166
+ esac
167
+ echo -ne "\033[${count}A" >&2
168
+ done
169
+
170
+ echo -ne "\033[$((count + 1))A\033[J" >&2
171
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${options[$cur]}${NC}" >&2
172
+ export SELECTED_OPTION="${options[$cur]}"
173
+ }
@@ -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
+ }