@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,268 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { mkdir, writeFile } from 'node:fs/promises'
3
+ import { basename, dirname, join, resolve } from 'node:path'
4
+ import type { Command } from 'commander'
5
+ import { registerPassThroughVerbs } from '@/commands/pass-through'
6
+ import { PROJECT_ROOT } from '@/exec'
7
+ import { createGovAdapter } from '@/gov/adapter'
8
+ import { hasStandards, installRules, lookupRules } from '@/gov/install'
9
+ import { buildRulesPayload, listRuleFiles } from '@/gov/payload'
10
+ import {
11
+ govStackExists,
12
+ listGovStacks,
13
+ mergeExtraRules,
14
+ resolveRules,
15
+ } from '@/gov/stacks'
16
+ import { recordStamp, runDomainSync } from '@/sync/engine'
17
+ import { resolveTarget } from '@/target'
18
+ import {
19
+ intro,
20
+ isNonInteractive,
21
+ logAdd,
22
+ logError,
23
+ logInfo,
24
+ logStep,
25
+ logWarn,
26
+ outro,
27
+ select,
28
+ } from '@/ui'
29
+
30
+ const GREEN = '\x1b[0;32m'
31
+ const NC = '\x1b[0m'
32
+
33
+ const PAYLOAD_REL = join('.claude', '.tmp', 'gov', 'rules.md')
34
+ const RULES_REL = join('.claude', 'rules')
35
+
36
+ const PASS_THROUGH_VERBS = ['list'] as const
37
+
38
+ interface InstallOptions {
39
+ readonly add?: string
40
+ }
41
+
42
+ export function register(program: Command): void {
43
+ const gov = program
44
+ .command('gov')
45
+ .description('Governance commands (install, sync, build, list)')
46
+ .helpOption('-h, --help', 'Show this help message')
47
+
48
+ gov
49
+ .command('install')
50
+ .description('Install a governance stack into .claude/rules/')
51
+ .argument('[stack]', 'Stack name (e.g. base, node, react)')
52
+ .argument('[target]', 'Target directory', '.')
53
+ .helpOption('-h, --help', 'Show this help message')
54
+ .option('--add <rules>', 'Comma-separated rules to layer on the stack')
55
+ .addHelpText(
56
+ 'after',
57
+ [
58
+ '',
59
+ 'Examples:',
60
+ ' aitk gov install react',
61
+ ' aitk gov install node ../my-app',
62
+ ' aitk gov install astro --add 200-react,260-shadcn ../my-app',
63
+ '',
64
+ ].join('\n'),
65
+ )
66
+ .action(
67
+ async (
68
+ stack: string | undefined,
69
+ target: string,
70
+ opts: InstallOptions,
71
+ ) => {
72
+ process.exitCode = await runInstall(stack, target, opts)
73
+ },
74
+ )
75
+
76
+ gov
77
+ .command('sync')
78
+ .description('Update rules already installed under .claude/rules/')
79
+ .argument('[target]', 'Target directory', '.')
80
+ .helpOption('-h, --help', 'Show this help message')
81
+ .action(async (target: string) => {
82
+ process.exitCode = await runDomainSync(
83
+ createGovAdapter(PROJECT_ROOT),
84
+ target,
85
+ { protectedRoot: PROJECT_ROOT },
86
+ )
87
+ })
88
+
89
+ gov
90
+ .command('build')
91
+ .description('Concatenate installed rules into .claude/.tmp/gov/rules.md')
92
+ .argument('[target]', 'Target directory', '.')
93
+ .helpOption('-h, --help', 'Show this help message')
94
+ .action(async (target: string) => {
95
+ process.exitCode = await runBuild(target)
96
+ })
97
+
98
+ registerPassThroughVerbs(gov, 'gov', PASS_THROUGH_VERBS)
99
+ }
100
+
101
+ /**
102
+ * Renders the target-relative path the prompt quotes, keeping the argument the
103
+ * caller typed rather than the absolute path it resolves to.
104
+ */
105
+ function displayPath(target: string, rel: string): string {
106
+ const trimmed = target.replace(/\/$/, '').replace(/^\.\//, '')
107
+ return trimmed === '' || trimmed === '.' ? rel : `${trimmed}/${rel}`
108
+ }
109
+
110
+ /**
111
+ * Refuses rather than picking. `select_option` returned `options[0]` under
112
+ * `AITK_NON_INTERACTIVE=1`, so a headless `aitk gov install` with no stack
113
+ * installed whichever stack sorted first, measured as 26 astro rules into an
114
+ * empty directory. Every documented agent path already passes the argument.
115
+ */
116
+ async function chooseStack(root: string): Promise<string | number> {
117
+ const stacks = listGovStacks(root)
118
+
119
+ if (stacks.length === 0) {
120
+ logError('No stacks found in governance/stacks/')
121
+ outro()
122
+ return 1
123
+ }
124
+
125
+ if (isNonInteractive()) {
126
+ logError(
127
+ `Stack argument is required in non-interactive mode. One of: ${stacks.join(', ')}.`,
128
+ )
129
+ outro()
130
+ return 1
131
+ }
132
+
133
+ return select({
134
+ message: 'Select stack to install:',
135
+ options: stacks.map((stack) => ({ value: stack, label: stack })),
136
+ })
137
+ }
138
+
139
+ async function runInstall(
140
+ stack: string | undefined,
141
+ target: string,
142
+ opts: InstallOptions,
143
+ ): Promise<number> {
144
+ intro('aitk gov install')
145
+
146
+ const resolved = resolveTarget(target, PROJECT_ROOT)
147
+ if (typeof resolved === 'number') return resolved
148
+
149
+ let selected = stack
150
+ if (selected === undefined) {
151
+ const choice = await chooseStack(PROJECT_ROOT)
152
+ if (typeof choice === 'number') return choice
153
+ selected = choice
154
+ }
155
+
156
+ if (!govStackExists(PROJECT_ROOT, selected)) {
157
+ logError(`Stack not found: ${selected}`)
158
+ outro()
159
+ return 1
160
+ }
161
+
162
+ const resolution = resolveRules(PROJECT_ROOT, selected)
163
+ if (!resolution.ok) {
164
+ logError(`Stack not found: ${resolution.missingStack}`)
165
+ outro()
166
+ return 1
167
+ }
168
+
169
+ const add = opts.add ?? ''
170
+ const rules =
171
+ add === '' ? resolution.rules : mergeExtraRules(resolution.rules, add)
172
+
173
+ if (rules.length === 0) {
174
+ logWarn(`No rules defined for stack: ${selected}`)
175
+ outro()
176
+ return 0
177
+ }
178
+
179
+ logStep(
180
+ add === ''
181
+ ? `Resolving stack: ${selected}`
182
+ : `Resolving stack: ${selected} + extras`,
183
+ )
184
+
185
+ const { found, missing } = lookupRules(PROJECT_ROOT, rules)
186
+ for (const rule of missing) logWarn(`${rule} (source not found, skipping)`)
187
+ for (const source of found) logInfo(source.rule)
188
+
189
+ const shouldInstall = await select({
190
+ message: `Install ${found.length} rules to ${displayPath(target, RULES_REL)}?`,
191
+ options: [
192
+ { value: true, label: 'Yes' },
193
+ { value: false, label: 'No' },
194
+ ],
195
+ nonInteractiveDefault: true,
196
+ })
197
+
198
+ if (!shouldInstall) {
199
+ logWarn('Cancelled')
200
+ outro()
201
+ return 0
202
+ }
203
+
204
+ logStep('Installing rules')
205
+ for (const rel of await installRules(found, resolved)) logAdd(rel)
206
+ await recordStamp(createGovAdapter(PROJECT_ROOT), resolved, new Date())
207
+
208
+ if (!hasStandards(resolved)) {
209
+ logWarn(
210
+ `Rules reference .claude/standards/. Run 'aitk standards install ${target}' or 'aitk init' so the references resolve.`,
211
+ )
212
+ }
213
+
214
+ outro()
215
+ process.stderr.write(`${GREEN}✓ Rules installed${NC}\n`)
216
+ return 0
217
+ }
218
+
219
+ /**
220
+ * Emits the rules payload the `gov-*` skills read. The output lands in the
221
+ * target's scratch directory rather than stdout because the file is the
222
+ * contract, and the skills point at the path.
223
+ */
224
+ async function runBuild(target: string): Promise<number> {
225
+ intro('aitk gov build')
226
+
227
+ const resolved = resolve(target)
228
+ const rulesDir = join(resolved, RULES_REL)
229
+
230
+ if (!existsSync(rulesDir)) {
231
+ logError(`No rules found at ${rulesDir}. Run \`aitk gov install\` first.`)
232
+ outro()
233
+ return 1
234
+ }
235
+
236
+ const files = listRuleFiles(rulesDir)
237
+ logStep(`Reading ${RULES_REL} (${files.length} found)`)
238
+ for (const file of files) {
239
+ logInfo(basename(file))
240
+ }
241
+
242
+ const shouldBuild = await select({
243
+ message: `Build ${files.length} rules to ${PAYLOAD_REL}?`,
244
+ options: [
245
+ { value: true, label: 'Yes' },
246
+ { value: false, label: 'No' },
247
+ ],
248
+ nonInteractiveDefault: true,
249
+ })
250
+
251
+ if (!shouldBuild) {
252
+ logWarn('Cancelled')
253
+ outro()
254
+ return 0
255
+ }
256
+
257
+ logStep('Building rules payload')
258
+ const output = join(resolved, PAYLOAD_REL)
259
+ await mkdir(dirname(output), { recursive: true })
260
+ await writeFile(output, buildRulesPayload(files))
261
+ logAdd(PAYLOAD_REL)
262
+
263
+ outro()
264
+ process.stderr.write(
265
+ `${GREEN}✓ Rules built (${files.length} rules → ${PAYLOAD_REL})${NC}\n`,
266
+ )
267
+ return 0
268
+ }
@@ -0,0 +1,182 @@
1
+ import { stat } from 'node:fs/promises'
2
+ import { dirname, resolve } from 'node:path'
3
+ import { $ } from 'bun'
4
+ import type { Command } from 'commander'
5
+ import { exitCodeFor, type RegenResult, regenOne } from '@/indexes/regen'
6
+ import { findIndexedAncestor, isIgnored, listIndexes } from '@/indexes/walk'
7
+ import { intro, logAdd, logInfo, logStep, logWarn, outro } from '@/ui'
8
+
9
+ interface RegenCommandOptions {
10
+ readonly dryRun?: boolean
11
+ readonly json?: boolean
12
+ readonly root?: string
13
+ readonly stage?: boolean
14
+ }
15
+
16
+ export function register(program: Command): void {
17
+ const indexes = program
18
+ .command('indexes')
19
+ .description('Regenerate index.md files from sibling frontmatter')
20
+ .helpOption('-h, --help', 'Show this help message')
21
+
22
+ indexes
23
+ .command('regen')
24
+ .description('Regenerate index.md files from sibling frontmatter')
25
+ .argument(
26
+ '[paths...]',
27
+ 'Paths to resolve up to their nearest indexed folder',
28
+ )
29
+ .helpOption('-h, --help', 'Show this help message')
30
+ .option('--dry-run', 'Report changes without writing')
31
+ .option('--json', 'Emit a machine-readable record per index on stdout')
32
+ .option('--root <path>', 'Walk-up boundary for positional paths')
33
+ .option('--no-stage', 'Skip the auto git add on modified indexes')
34
+ .addHelpText(
35
+ 'after',
36
+ [
37
+ '',
38
+ 'Exit codes:',
39
+ ' 0 no drift, nothing to do',
40
+ ' 1 frontmatter error or missing index.md',
41
+ ' 2 --dry-run found folders that would change',
42
+ '',
43
+ 'Examples:',
44
+ ' aitk indexes regen',
45
+ ' aitk indexes regen --dry-run',
46
+ ' aitk indexes regen --json docs/',
47
+ '',
48
+ ].join('\n'),
49
+ )
50
+ .action(async (paths: string[], opts: RegenCommandOptions) => {
51
+ process.exitCode = await runRegen(paths, opts)
52
+ })
53
+ }
54
+
55
+ async function runRegen(
56
+ paths: string[],
57
+ opts: RegenCommandOptions,
58
+ ): Promise<number> {
59
+ const root = resolve(opts.root ?? process.cwd())
60
+ const dryRun = opts.dryRun ?? false
61
+ const emitJson = opts.json ?? false
62
+
63
+ if (!(await isDirectory(root))) {
64
+ if (emitJson) {
65
+ process.stdout.write(
66
+ `${JSON.stringify({ error: `root not a directory: ${root}` })}\n`,
67
+ )
68
+ return 1
69
+ }
70
+ process.stderr.write(`Root is not a directory: ${root}\n`)
71
+ return 1
72
+ }
73
+
74
+ const dirs =
75
+ paths.length > 0
76
+ ? collectFromPaths(paths, root)
77
+ : (await listIndexes(root)).map(dirname)
78
+
79
+ const shouldStage =
80
+ paths.length > 0 && opts.stage !== false && !dryRun && !emitJson
81
+
82
+ const results: RegenResult[] = []
83
+
84
+ if (!emitJson) {
85
+ intro('aitk indexes')
86
+ logStep(dryRun ? 'Indexes (dry-run)' : 'Indexes')
87
+ }
88
+
89
+ for (const dir of dirs) {
90
+ const result = await regenOne(dir, { dryRun })
91
+ results.push(result)
92
+
93
+ for (const message of result.errors ?? []) {
94
+ process.stderr.write(`ERROR: ${message}\n`)
95
+ }
96
+
97
+ if (!emitJson) await reportResult(result, root, shouldStage)
98
+ }
99
+
100
+ if (emitJson) {
101
+ process.stdout.write(
102
+ `${JSON.stringify({
103
+ root,
104
+ dryRun,
105
+ results: results.map(({ path, action, reason }) =>
106
+ reason ? { path, action, reason } : { path, action },
107
+ ),
108
+ })}\n`,
109
+ )
110
+ } else {
111
+ outro()
112
+ }
113
+
114
+ return exitCodeFor(results, { dryRun })
115
+ }
116
+
117
+ function collectFromPaths(paths: string[], root: string): string[] {
118
+ const dirs: string[] = []
119
+
120
+ for (const path of paths) {
121
+ const dir = findIndexedAncestor(resolve(root, path), root)
122
+ if (!dir) {
123
+ process.stderr.write(
124
+ `WARN: ${path} has no index.md ancestor under ${root}\n`,
125
+ )
126
+ continue
127
+ }
128
+ if (!dirs.includes(dir)) dirs.push(dir)
129
+ }
130
+
131
+ return dirs
132
+ }
133
+
134
+ async function reportResult(
135
+ result: RegenResult,
136
+ root: string,
137
+ shouldStage: boolean,
138
+ ): Promise<void> {
139
+ const rel = result.path.startsWith(`${root}/`)
140
+ ? result.path.slice(root.length + 1)
141
+ : result.path
142
+
143
+ switch (result.action) {
144
+ case 'written':
145
+ logAdd(rel)
146
+ if (shouldStage) await stage(result.path, rel, root)
147
+ break
148
+ case 'would-write':
149
+ logWarn(`${rel} would change`)
150
+ break
151
+ case 'unchanged':
152
+ logInfo(`${rel} unchanged`)
153
+ break
154
+ case 'skipped':
155
+ logInfo(`${rel} skipped (auto:false)`)
156
+ break
157
+ case 'error':
158
+ logWarn(`${rel} error`)
159
+ break
160
+ }
161
+ }
162
+
163
+ async function stage(path: string, rel: string, root: string): Promise<void> {
164
+ if (await isIgnored(root, path)) return
165
+
166
+ const staged = await $`git -C ${root} add -- ${path}`
167
+ .quiet()
168
+ .nothrow()
169
+ .then((result) => result.exitCode === 0)
170
+
171
+ if (staged) {
172
+ logInfo(`staged ${rel}`)
173
+ } else {
174
+ logWarn(`failed to stage ${rel}`)
175
+ }
176
+ }
177
+
178
+ async function isDirectory(path: string): Promise<boolean> {
179
+ return stat(path)
180
+ .then((info) => info.isDirectory())
181
+ .catch(() => false)
182
+ }
@@ -0,0 +1,117 @@
1
+ import type { Command } from 'commander'
2
+ import { cliPath, cliRun } from '@/cli-run'
3
+ import { PROJECT_ROOT } from '@/exec'
4
+ import { applyInitOptions, flagsProvided } from '@/init/flags'
5
+ import { type InitFlags, parseSkip, planInit } from '@/init/plan'
6
+ import { runDomains } from '@/init/run'
7
+ import { buildSteps } from '@/init/steps'
8
+ import { resolveTarget } from '@/target'
9
+ import { intro, logInfo, logStep, logWarn, outro, select } from '@/ui'
10
+
11
+ const GREEN = '\x1b[0;32m'
12
+ const YELLOW = '\x1b[0;33m'
13
+ const NC = '\x1b[0m'
14
+
15
+ interface InitOptions {
16
+ /** Always present: the option falls back to `DEFAULT_STACK`. */
17
+ readonly stack: string
18
+ readonly add?: string
19
+ readonly snippets: string
20
+ readonly skip?: string
21
+ }
22
+
23
+ export function register(program: Command): void {
24
+ const command = program
25
+ .command('init')
26
+ .description('Bootstrap a project with base tooling and toolkit domains')
27
+ .argument('[target]', 'Target directory', '.')
28
+
29
+ applyInitOptions(command)
30
+ .helpOption('-h, --help', 'Show this help message')
31
+ .addHelpText(
32
+ 'after',
33
+ [
34
+ '',
35
+ 'Passing any option skips the confirmation prompt.',
36
+ '',
37
+ 'Examples:',
38
+ ' aitk init',
39
+ ' aitk init ../my-app',
40
+ ' aitk init --stack astro --add 260-shadcn ../my-app',
41
+ ' aitk init --skip governance ../my-app',
42
+ '',
43
+ ].join('\n'),
44
+ )
45
+ .action(async (target: string, options: InitOptions, cmd: Command) => {
46
+ process.exitCode = await runInit(target, options, flagsProvided(cmd))
47
+ })
48
+ }
49
+
50
+ async function runInit(
51
+ target: string,
52
+ options: InitOptions,
53
+ skipPrompt: boolean,
54
+ ): Promise<number> {
55
+ intro('aitk init')
56
+
57
+ const resolved = resolveTarget(target, PROJECT_ROOT)
58
+ if (typeof resolved === 'number') return resolved
59
+
60
+ const skip = parseSkip(options.skip)
61
+ for (const value of skip.unknown) {
62
+ logWarn(`Unknown --skip value: ${value} (ignoring)`)
63
+ }
64
+
65
+ const flags: InitFlags = {
66
+ stack: options.stack,
67
+ add: options.add,
68
+ snippets: options.snippets,
69
+ skip,
70
+ }
71
+
72
+ const plan = planInit(flags)
73
+
74
+ logStep('Core domains')
75
+ for (const line of plan.preview) {
76
+ if (line.level === 'info') logInfo(line.text)
77
+ else logWarn(line.text)
78
+ }
79
+
80
+ if (!skipPrompt) {
81
+ const shouldInstall = await select({
82
+ message: `Install ${plan.total} domains to ${target}?`,
83
+ options: [
84
+ { value: true, label: 'Yes' },
85
+ { value: false, label: 'Cancel' },
86
+ ],
87
+ nonInteractiveDefault: true,
88
+ })
89
+
90
+ if (!shouldInstall) {
91
+ logWarn('Cancelled')
92
+ outro()
93
+ return 0
94
+ }
95
+ }
96
+
97
+ const path = cliPath(PROJECT_ROOT)
98
+ const child = (args: readonly string[]): (() => Promise<boolean>) =>
99
+ cliRun(path, args, { nonInteractive: true, stdin: 'ignore' })
100
+
101
+ const failed = await runDomains(buildSteps(target, resolved, flags, child))
102
+
103
+ outro()
104
+ process.stderr.write('\n')
105
+
106
+ if (failed.length === 0) {
107
+ process.stderr.write(
108
+ `${GREEN}✓ Project initialized (${plan.total} domains)${NC}\n`,
109
+ )
110
+ return 0
111
+ }
112
+
113
+ process.stderr.write(
114
+ `${YELLOW}! Project initialized with ${failed.length} failure(s): ${failed.join(', ')}${NC}\n`,
115
+ )
116
+ return 1
117
+ }
@@ -0,0 +1,39 @@
1
+ import type { Command } from 'commander'
2
+ import { execScript } from '@/exec'
3
+ import { intro } from '@/ui'
4
+
5
+ /**
6
+ * Registers the verbs a domain has not migrated yet, each forwarding to
7
+ * `scripts/<domain>/<verb>.sh`. Naming them instead of catching everything on
8
+ * the parent gives each verb its own `--help` and lets a migrated sibling sit
9
+ * alongside them.
10
+ */
11
+ export function registerPassThroughVerbs(
12
+ parent: Command,
13
+ domain: string,
14
+ verbs: readonly string[],
15
+ ): void {
16
+ for (const verb of verbs) {
17
+ parent
18
+ .command(verb)
19
+ .description(`Run the ${domain} ${verb} command`)
20
+ .allowUnknownOption()
21
+ .allowExcessArguments(true)
22
+ .passThroughOptions()
23
+ .helpOption(false)
24
+ .action(async (_opts: unknown, cmd: Command) => {
25
+ if (!isHelpRequest(cmd.args)) intro(`aitk ${domain}`)
26
+ await execScript(`${domain}/${verb}.sh`, cmd.args)
27
+ })
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Commander resolves `--help` before an action runs, so a pass-through verb
33
+ * that keeps the built-in help option prints a one-line stub instead of the
34
+ * script's usage. Disabling it lets the flag reach the script, which owns the
35
+ * real flag surface, and this guard keeps the frame from opening around it.
36
+ */
37
+ function isHelpRequest(args: readonly string[]): boolean {
38
+ return args.includes('-h') || args.includes('--help')
39
+ }