@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,89 @@
1
+ import { join } from 'node:path'
2
+ import type { Command } from 'commander'
3
+ import { registerPassThroughVerbs } from '@/commands/pass-through'
4
+ import { PROJECT_ROOT } from '@/exec'
5
+ import { createStandardsAdapter, standardsSourceDir } from '@/standards/adapter'
6
+ import {
7
+ refreshIndex,
8
+ STANDARDS_REL,
9
+ standardsInstallDir,
10
+ } from '@/standards/index-refresh'
11
+ import { applyInstall, planInstall } from '@/standards/install'
12
+ import { recordStamp, runDomainSync } from '@/sync/engine'
13
+ import { resolveTarget } from '@/target'
14
+ import { intro, logAdd, logInfo, logStep, logWarn, outro, select } from '@/ui'
15
+
16
+ const GREEN = '\x1b[0;32m'
17
+ const GREY = '\x1b[0;90m'
18
+ const NC = '\x1b[0m'
19
+
20
+ export function register(program: Command): void {
21
+ const standards = program
22
+ .command('standards')
23
+ .description('Standards commands (install, sync, list)')
24
+ .helpOption('-h, --help', 'Show this help message')
25
+
26
+ standards
27
+ .command('sync')
28
+ .description('Update standards already installed under .claude/standards/')
29
+ .argument('[target]', 'Target directory', '.')
30
+ .helpOption('-h, --help', 'Show this help message')
31
+ .action(async (target: string) => {
32
+ process.exitCode = await runDomainSync(
33
+ createStandardsAdapter(PROJECT_ROOT),
34
+ target,
35
+ { protectedRoot: PROJECT_ROOT },
36
+ )
37
+ })
38
+
39
+ standards
40
+ .command('install')
41
+ .description('Copy all standards into a project (overwrites)')
42
+ .argument('[target]', 'Target directory', '.')
43
+ .helpOption('-h, --help', 'Show this help message')
44
+ .action(async (target: string) => {
45
+ process.exitCode = await runInstall(target)
46
+ })
47
+
48
+ registerPassThroughVerbs(standards, 'standards', ['list'])
49
+ }
50
+
51
+ async function runInstall(target: string): Promise<number> {
52
+ intro('aitk standards')
53
+
54
+ const resolved = resolveTarget(target, PROJECT_ROOT)
55
+ if (typeof resolved === 'number') return resolved
56
+
57
+ const sourceDir = standardsSourceDir(PROJECT_ROOT)
58
+ const destDir = standardsInstallDir(resolved)
59
+
60
+ logStep('Scanning standards')
61
+ const files = planInstall(sourceDir)
62
+ for (const file of files) logInfo(join(STANDARDS_REL, file.name))
63
+
64
+ const shouldInstall = await select({
65
+ message: `Install ${files.length} standards to ${destDir}?`,
66
+ options: [
67
+ { value: true, label: 'Yes' },
68
+ { value: false, label: 'No' },
69
+ ],
70
+ nonInteractiveDefault: true,
71
+ })
72
+
73
+ if (!shouldInstall) {
74
+ logWarn('Cancelled')
75
+ outro()
76
+ return 0
77
+ }
78
+
79
+ logStep('Installing standards')
80
+ for (const label of await applyInstall(files, destDir)) logAdd(label)
81
+ await refreshIndex(sourceDir, resolved)
82
+ await recordStamp(createStandardsAdapter(PROJECT_ROOT), resolved, new Date())
83
+
84
+ outro()
85
+ process.stderr.write(
86
+ `\n${GREEN}✓ Standards installed${NC} ${GREY}(${files.length} files)${NC}\n`,
87
+ )
88
+ return 0
89
+ }
@@ -0,0 +1,211 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import type { Command } from 'commander'
4
+ import { cliPath, cliRun } from '@/cli-run'
5
+ import { PROJECT_ROOT } from '@/exec'
6
+ import { buildCheckReport, type CheckReport, hasDrift } from '@/sync/check'
7
+ import { createGitRunner, createPullRequestOpener, hasGh } from '@/sync/git'
8
+ import { STAMP_DOMAINS } from '@/sync/stamp'
9
+ import {
10
+ detectDomains,
11
+ installedDomains,
12
+ isTreeClean,
13
+ shouldSync,
14
+ SYNC_DOMAINS,
15
+ type SyncDomain,
16
+ } from '@/sync/target'
17
+ import { runGitWorkflow } from '@/sync/workflow'
18
+ import { resolveTarget } from '@/target'
19
+ import {
20
+ intro,
21
+ isNonInteractive,
22
+ logError,
23
+ logInfo,
24
+ logStep,
25
+ logWarn,
26
+ outro,
27
+ } from '@/ui'
28
+
29
+ const GREY = '\x1b[0;90m'
30
+ const YELLOW = '\x1b[0;33m'
31
+ const NC = '\x1b[0m'
32
+
33
+ const SYNC_ARGS: Record<SyncDomain, readonly string[]> = {
34
+ standards: ['standards', 'sync'],
35
+ snippets: ['snippets', 'sync'],
36
+ governance: ['gov', 'sync'],
37
+ claude: ['claude', 'sync'],
38
+ }
39
+
40
+ interface SyncOptions {
41
+ readonly check?: boolean
42
+ readonly json?: boolean
43
+ readonly exitCode?: boolean
44
+ }
45
+
46
+ export function register(program: Command): void {
47
+ program
48
+ .command('sync')
49
+ .description('Sync all installed domains in a project')
50
+ .argument('[target]', 'Target directory', '.')
51
+ .option('--check', 'Report drift without writing anything')
52
+ .option('--json', 'Emit the drift report as JSON on stdout')
53
+ .option('--exit-code', 'Exit 1 when drift is found, for CI')
54
+ .helpOption('-h, --help', 'Show this help message')
55
+ .addHelpText(
56
+ 'after',
57
+ [
58
+ '',
59
+ 'Examples:',
60
+ ' aitk sync',
61
+ ' aitk sync ../my-app',
62
+ ' aitk sync --check',
63
+ ' aitk sync --check --json',
64
+ ' aitk sync --check --exit-code',
65
+ '',
66
+ ].join('\n'),
67
+ )
68
+ .action(async (target: string, options: SyncOptions) => {
69
+ process.exitCode =
70
+ options.check === true
71
+ ? await runCheck(target, options)
72
+ : await runSync(target)
73
+ })
74
+ }
75
+
76
+ /**
77
+ * Reads the same plan a sync would apply and writes nothing. Drift between
78
+ * syncs is normal, so the default exit stays 0 and CI opts into failing.
79
+ */
80
+ async function runCheck(target: string, options: SyncOptions): Promise<number> {
81
+ const resolved = resolveTarget(target, PROJECT_ROOT)
82
+ if (typeof resolved === 'number') return resolved
83
+
84
+ const report = await buildCheckReport(PROJECT_ROOT, resolved)
85
+
86
+ if (options.json === true) {
87
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`)
88
+ } else {
89
+ renderCheck(report)
90
+ }
91
+
92
+ return options.exitCode === true && hasDrift(report) ? 1 : 0
93
+ }
94
+
95
+ function renderCheck(report: CheckReport): void {
96
+ intro('aitk sync --check')
97
+
98
+ for (const domain of report.domains) {
99
+ logStep(domain.domain)
100
+
101
+ if (domain.commit === undefined) {
102
+ logWarn('Not stamped. Drift below is reported unattributed.')
103
+ } else {
104
+ logInfo(`Synced from ${domain.commit} on ${domain.syncedAt}`)
105
+ }
106
+
107
+ for (const entry of domain.entries) {
108
+ if (entry.state === 'matching' || entry.state === 'orphaned') continue
109
+ logWarn(`${entry.rel} (${entry.state})`)
110
+ }
111
+
112
+ const { stale, customized, drifted, stranded, orphaned } = domain.counts
113
+ if (stale + customized + drifted + stranded === 0) {
114
+ logInfo(orphaned === 0 ? 'up to date' : `up to date (${orphaned} local)`)
115
+ }
116
+
117
+ for (const commit of domain.upstream) {
118
+ logInfo(`${commit.sha} ${commit.subject}`)
119
+ }
120
+ }
121
+
122
+ if (report.newSkills.length > 0) {
123
+ logStep('New skills, no sync needed')
124
+ for (const name of report.newSkills) logInfo(name)
125
+ }
126
+
127
+ outro()
128
+ const uncovered = STAMP_DOMAINS.filter(
129
+ (domain) => !report.covers.includes(domain),
130
+ )
131
+ const unstamped =
132
+ uncovered.length === 0 ? '' : `Unstamped: ${uncovered.join(', ')}. `
133
+ process.stderr.write(
134
+ `${GREY}${unstamped}Tooling is never stamped, run \`aitk tooling\` to reconcile configs.${NC}\n`,
135
+ )
136
+ }
137
+
138
+ async function runSync(target: string): Promise<number> {
139
+ intro('aitk sync')
140
+
141
+ const resolved = resolveTarget(target, PROJECT_ROOT)
142
+ if (typeof resolved === 'number') return resolved
143
+
144
+ const git = createGitRunner(resolved)
145
+
146
+ logStep('Checking working tree')
147
+ if (!isTreeClean(await git.status([]))) {
148
+ logError(
149
+ 'Working tree has uncommitted changes. Commit or stash before syncing.',
150
+ )
151
+ outro()
152
+ return 1
153
+ }
154
+ logInfo('Working tree clean')
155
+
156
+ logStep('Detecting domains')
157
+ const states = detectDomains(resolved)
158
+ for (const state of states) {
159
+ if (state.installed) logInfo(state.domain)
160
+ else logWarn(`${state.domain} (not installed, skipping)`)
161
+ }
162
+
163
+ if (installedDomains(states).length === 0) {
164
+ outro()
165
+ process.stderr.write(
166
+ `\n${YELLOW}! No domains installed in target. Run domain install commands first.${NC}\n`,
167
+ )
168
+ return 0
169
+ }
170
+
171
+ outro()
172
+ process.stderr.write('\n')
173
+
174
+ await runDomainSyncs(resolved)
175
+
176
+ const code = await runGitWorkflow(resolved, {
177
+ git,
178
+ pullRequests: (await hasGh())
179
+ ? createPullRequestOpener(resolved)
180
+ : undefined,
181
+ now: new Date(),
182
+ nonInteractive: isNonInteractive(),
183
+ })
184
+
185
+ if (existsSync(join(resolved, '.claude'))) {
186
+ process.stderr.write(
187
+ `${GREY}Tip: run \`/claude-seed-sync\` to audit seed and standards drift per section, preserving local customizations.${NC}\n`,
188
+ )
189
+ }
190
+
191
+ return code
192
+ }
193
+
194
+ /**
195
+ * Each domain sync runs as its own process. They open their own frames and
196
+ * prompt for their own changes, so stdin stays inherited. Claude is the one
197
+ * exception: it runs headless because the combined pull request preview is the
198
+ * single confirmation gate for the whole sync, and `aitk claude sync` writes
199
+ * only `.gitignore`.
200
+ */
201
+ async function runDomainSyncs(target: string): Promise<void> {
202
+ const path = cliPath(PROJECT_ROOT)
203
+
204
+ for (const domain of SYNC_DOMAINS) {
205
+ if (!shouldSync(target, domain)) continue
206
+
207
+ await cliRun(path, [...SYNC_ARGS[domain], target], {
208
+ nonInteractive: domain === 'claude',
209
+ })()
210
+ }
211
+ }
@@ -0,0 +1,185 @@
1
+ import { relative } from 'node:path'
2
+ import { $ } from 'bun'
3
+ import type { Command } from 'commander'
4
+ import { type ArchiveOutcome, archiveTask } from '@/tasks/archive'
5
+ import {
6
+ intro,
7
+ logAdd,
8
+ logError,
9
+ logInfo,
10
+ logRemove,
11
+ logStep,
12
+ outro,
13
+ pipeOutput,
14
+ } from '@/ui'
15
+
16
+ interface ArchiveCommandOptions {
17
+ readonly json?: boolean
18
+ readonly pullRequest?: string
19
+ readonly root?: string
20
+ }
21
+
22
+ /**
23
+ * The board is shared scratch at the main worktree root, and `git worktree
24
+ * list` puts that root first. A pull inside a linked worktree fires the same
25
+ * hook, so trusting the working directory would write a second board nothing
26
+ * else reads.
27
+ */
28
+ async function mainWorktreeRoot(): Promise<string> {
29
+ const result = await $`git worktree list --porcelain`.quiet().nothrow()
30
+ if (result.exitCode !== 0) return process.cwd()
31
+
32
+ const line = result.stdout
33
+ .toString()
34
+ .split('\n')
35
+ .find((entry) => entry.startsWith('worktree '))
36
+
37
+ return line ? line.slice('worktree '.length).trim() : process.cwd()
38
+ }
39
+
40
+ export function register(program: Command): void {
41
+ const tasks = program
42
+ .command('tasks')
43
+ .description('Manage the task board in .claude/tasks/')
44
+ .helpOption('-h, --help', 'Show this help message')
45
+
46
+ tasks
47
+ .command('archive')
48
+ .description('Move a shipped task out of the board and clear its ordering')
49
+ .argument('[task]', 'Task filename stem, as in v28.1-trigger-escalation')
50
+ .helpOption('-h, --help', 'Show this help message')
51
+ .option(
52
+ '--pull-request <number>',
53
+ 'Select the task naming this pull request',
54
+ )
55
+ .option('--json', 'Emit a machine-readable record on stdout')
56
+ .option('--root <path>', 'Board root, defaulting to the main worktree')
57
+ .addHelpText(
58
+ 'after',
59
+ [
60
+ '',
61
+ 'Exit codes:',
62
+ ' 0 the task was archived',
63
+ ' 1 refused, with the reason on stderr or in the JSON record',
64
+ '',
65
+ 'Examples:',
66
+ ' aitk tasks archive v28.1-trigger-escalation',
67
+ ' aitk tasks archive --pull-request 673 --json',
68
+ '',
69
+ ].join('\n'),
70
+ )
71
+ .action(async (task: string | undefined, opts: ArchiveCommandOptions) => {
72
+ process.exitCode = await runArchive(task, opts)
73
+ })
74
+ }
75
+
76
+ async function runArchive(
77
+ task: string | undefined,
78
+ opts: ArchiveCommandOptions,
79
+ ): Promise<number> {
80
+ const emitJson = opts.json ?? false
81
+
82
+ if (task && opts.pullRequest) {
83
+ return report(
84
+ {
85
+ ok: false,
86
+ reason: 'ambiguous',
87
+ message: 'Name a task or a pull request, not both.',
88
+ detail: [],
89
+ },
90
+ emitJson,
91
+ process.cwd(),
92
+ )
93
+ }
94
+
95
+ if (!task && !opts.pullRequest) {
96
+ return report(
97
+ {
98
+ ok: false,
99
+ reason: 'no-match',
100
+ message:
101
+ 'No task named. Pass a filename stem or --pull-request <number>.',
102
+ detail: [],
103
+ },
104
+ emitJson,
105
+ process.cwd(),
106
+ )
107
+ }
108
+
109
+ const root = opts.root ?? (await mainWorktreeRoot())
110
+
111
+ if (opts.pullRequest && !/^\d+$/.test(opts.pullRequest)) {
112
+ return report(
113
+ {
114
+ ok: false,
115
+ reason: 'no-match',
116
+ message: `Not a pull request number: ${opts.pullRequest}`,
117
+ detail: [],
118
+ },
119
+ emitJson,
120
+ root,
121
+ )
122
+ }
123
+
124
+ const outcome = await archiveTask(
125
+ root,
126
+ task
127
+ ? { kind: 'stem', stem: task }
128
+ : { kind: 'pull-request', number: Number(opts.pullRequest) },
129
+ )
130
+
131
+ return report(outcome, emitJson, root)
132
+ }
133
+
134
+ function report(
135
+ outcome: ArchiveOutcome,
136
+ emitJson: boolean,
137
+ root: string,
138
+ ): number {
139
+ if (emitJson) {
140
+ process.stdout.write(`${JSON.stringify(recordFor(outcome, root))}\n`)
141
+ return outcome.ok ? 0 : 1
142
+ }
143
+
144
+ intro('aitk tasks archive')
145
+
146
+ if (!outcome.ok) {
147
+ logStep('Refused')
148
+ logError(outcome.message)
149
+ if (outcome.detail.length > 0) pipeOutput(outcome.detail.join('\n'))
150
+ outro()
151
+ return 1
152
+ }
153
+
154
+ logStep('Archived')
155
+ logRemove(relative(root, outcome.from))
156
+ logAdd(relative(root, outcome.to))
157
+ if (outcome.priorityRowRemoved) logInfo('cleared the ordering row')
158
+ if (outcome.indexRegenerated) logInfo('regenerated index.md')
159
+ outro()
160
+
161
+ return 0
162
+ }
163
+
164
+ function recordFor(
165
+ outcome: ArchiveOutcome,
166
+ root: string,
167
+ ): Record<string, unknown> {
168
+ if (!outcome.ok) {
169
+ return {
170
+ ok: false,
171
+ reason: outcome.reason,
172
+ message: outcome.message,
173
+ detail: outcome.detail,
174
+ }
175
+ }
176
+
177
+ return {
178
+ ok: true,
179
+ task: outcome.stem,
180
+ from: relative(root, outcome.from),
181
+ to: relative(root, outcome.to),
182
+ priorityRowRemoved: outcome.priorityRowRemoved,
183
+ indexRegenerated: outcome.indexRegenerated,
184
+ }
185
+ }