@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,54 @@
1
+ export interface VideoMetadata {
2
+ readonly videoId: string
3
+ readonly title: string
4
+ readonly channel: string
5
+ readonly durationSeconds: number
6
+ readonly published: string
7
+ readonly url: string
8
+ }
9
+
10
+ const SLUG_PATTERN = /[^a-z0-9]+/g
11
+
12
+ export function slugify(text: string, maxLength = 50): string {
13
+ const cleaned = text
14
+ .toLowerCase()
15
+ .replace(SLUG_PATTERN, '-')
16
+ .replace(/(^-|-$)/g, '')
17
+ if (!cleaned) return 'untitled'
18
+ return cleaned.slice(0, maxLength).replace(/-$/, '') || 'untitled'
19
+ }
20
+
21
+ export function formatUploadDate(yyyymmdd: string | undefined): string {
22
+ if (!yyyymmdd || yyyymmdd.length !== 8 || !/^\d{8}$/.test(yyyymmdd)) return ''
23
+ return `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6)}`
24
+ }
25
+
26
+ function yamlEscape(value: string): string {
27
+ return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`
28
+ }
29
+
30
+ interface FrontmatterOptions {
31
+ readonly hasTranscript: boolean
32
+ readonly fetchedAt: string
33
+ }
34
+
35
+ export function renderFrontmatter(
36
+ video: VideoMetadata,
37
+ { hasTranscript, fetchedAt }: FrontmatterOptions,
38
+ ): string {
39
+ const lines = [
40
+ '---',
41
+ `title: ${yamlEscape(video.title)}`,
42
+ `channel: ${yamlEscape(video.channel)}`,
43
+ `video_id: ${video.videoId}`,
44
+ `url: ${video.url}`,
45
+ `duration: ${video.durationSeconds}`,
46
+ video.published ? `published: ${video.published}` : 'published:',
47
+ `fetched_at: ${fetchedAt}`,
48
+ `has_transcript: ${hasTranscript ? 'true' : 'false'}`,
49
+ '---',
50
+ '',
51
+ '',
52
+ ]
53
+ return lines.join('\n')
54
+ }
@@ -0,0 +1,114 @@
1
+ export interface Cue {
2
+ readonly timestamp: string
3
+ readonly text: string
4
+ }
5
+
6
+ const VTT_TIMESTAMP = /^(\d\d:)?\d\d:\d\d\.\d{3} --> .*$/
7
+ const VTT_INLINE_TAG = /<[^>]+>/g
8
+ const VTT_NUMERIC_LINE = /^\d+$/
9
+
10
+ export function parseVtt(raw: string): Cue[] {
11
+ const cues: Cue[] = []
12
+ let currentTimestamp: string | null = null
13
+ let currentLines: string[] = []
14
+ let inHeader = true
15
+
16
+ const flush = (): void => {
17
+ if (currentTimestamp !== null && currentLines.length) {
18
+ const text = currentLines.join(' ').trim()
19
+ if (text) cues.push({ timestamp: currentTimestamp, text })
20
+ }
21
+ currentTimestamp = null
22
+ currentLines = []
23
+ }
24
+
25
+ for (const rawLine of raw.split(/\r?\n/)) {
26
+ const line = rawLine.replace(/\s+$/, '')
27
+ if (inHeader) {
28
+ if (VTT_TIMESTAMP.test(line)) inHeader = false
29
+ else continue
30
+ }
31
+ if (VTT_TIMESTAMP.test(line)) {
32
+ flush()
33
+ currentTimestamp = line.split(' --> ', 1)[0].trim()
34
+ continue
35
+ }
36
+ if (line.trim() === '') {
37
+ flush()
38
+ continue
39
+ }
40
+ if (VTT_NUMERIC_LINE.test(line.trim())) continue
41
+ const cleaned = line.replace(VTT_INLINE_TAG, '').trim()
42
+ if (cleaned) currentLines.push(cleaned)
43
+ }
44
+ flush()
45
+ return cues
46
+ }
47
+
48
+ export function dedupeRollingCues(cues: Cue[]): Cue[] {
49
+ const deduped: Cue[] = []
50
+ let running = ''
51
+ for (const { timestamp, text } of cues) {
52
+ const maxOverlap = Math.min(running.length, text.length)
53
+ let overlap = 0
54
+ for (let size = maxOverlap; size > 0; size -= 1) {
55
+ if (running.endsWith(text.slice(0, size))) {
56
+ overlap = size
57
+ break
58
+ }
59
+ }
60
+ const addition = text.slice(overlap).trim()
61
+ if (!addition) continue
62
+ running = `${running} ${addition}`.trim()
63
+ deduped.push({ timestamp, text: addition })
64
+ }
65
+ return deduped
66
+ }
67
+
68
+ function vttTimestampToSeconds(stamp: string): number {
69
+ const parts = stamp.split(':')
70
+ let hours = '0'
71
+ let minutes: string
72
+ let rest: string
73
+ if (parts.length === 3) [hours, minutes, rest] = parts
74
+ else if (parts.length === 2) [minutes, rest] = parts
75
+ else return 0
76
+ const seconds = rest.split('.', 1)[0]
77
+ return Number(hours) * 3600 + Number(minutes) * 60 + Number(seconds)
78
+ }
79
+
80
+ function formatSeconds(seconds: number): string {
81
+ const minutes = Math.floor(seconds / 60)
82
+ const secs = seconds % 60
83
+ return `${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`
84
+ }
85
+
86
+ interface RenderOptions {
87
+ readonly keepTimestamps: boolean
88
+ }
89
+
90
+ export function renderBody(
91
+ cues: Cue[],
92
+ { keepTimestamps }: RenderOptions,
93
+ ): string {
94
+ if (!cues.length) return ''
95
+ if (keepTimestamps) {
96
+ const lines = cues.map(
97
+ ({ timestamp, text }) =>
98
+ `[${formatSeconds(vttTimestampToSeconds(timestamp))}] ${text}`,
99
+ )
100
+ return `${lines.join('\n')}\n`
101
+ }
102
+ const joined = cues.map(({ text }) => text).join(' ')
103
+ return `${paragraphWrap(joined)}\n`
104
+ }
105
+
106
+ function paragraphWrap(text: string, wordsPerParagraph = 60): string {
107
+ const words = text.split(/\s+/).filter(Boolean)
108
+ if (!words.length) return ''
109
+ const paragraphs: string[] = []
110
+ for (let start = 0; start < words.length; start += wordsPerParagraph) {
111
+ paragraphs.push(words.slice(start, start + wordsPerParagraph).join(' '))
112
+ }
113
+ return paragraphs.join('\n\n')
114
+ }
package/src/ui.ts ADDED
@@ -0,0 +1,187 @@
1
+ const GREEN = '\x1b[0;32m'
2
+ const RED = '\x1b[0;31m'
3
+ const YELLOW = '\x1b[0;33m'
4
+ const WHITE = '\x1b[1;37m'
5
+ const GREY = '\x1b[0;90m'
6
+ const NC = '\x1b[0m'
7
+
8
+ export function intro(title: string): void {
9
+ process.stderr.write(`${GREY}┌${NC}\n${GREY}│${NC} ${WHITE}${title}${NC}\n`)
10
+ }
11
+
12
+ /**
13
+ * Timeline log levels matching `scripts/lib/ui.sh`, so a migrated command
14
+ * prints the same frame as the bash it replaced. All output is stderr,
15
+ * leaving stdout clean for JSON and lists.
16
+ */
17
+ export function logInfo(message: string): void {
18
+ process.stderr.write(`${GREY}│${NC} ${GREEN}✓${NC} ${message}\n`)
19
+ }
20
+
21
+ export function logWarn(message: string): void {
22
+ process.stderr.write(`${GREY}│${NC} ${YELLOW}!${NC} ${message}\n`)
23
+ }
24
+
25
+ export function logAdd(message: string): void {
26
+ process.stderr.write(`${GREY}│${NC} ${GREEN}+${NC} ${message}\n`)
27
+ }
28
+
29
+ export function logRemove(message: string): void {
30
+ process.stderr.write(`${GREY}│${NC} ${RED}-${NC} ${message}\n`)
31
+ }
32
+
33
+ /**
34
+ * Renders the `✗` shape `docs/agents.md` specifies for a failure inside an
35
+ * open frame. It does not exit, so the caller closes the frame and returns an
36
+ * exit code rather than terminating mid-write.
37
+ */
38
+ export function logError(message: string): void {
39
+ process.stderr.write(`${GREY}│${NC} ${RED}✗${NC} ${message}\n`)
40
+ }
41
+
42
+ export function logStep(message: string): void {
43
+ process.stderr.write(`${GREY}│${NC}\n${GREY}├${NC} ${WHITE}${message}${NC}\n`)
44
+ }
45
+
46
+ export function outro(): void {
47
+ process.stderr.write(`${GREY}└${NC}\n`)
48
+ }
49
+
50
+ /**
51
+ * Indents borrowed output inside an open frame, matching `pipe_output` in
52
+ * `scripts/lib/ui.sh`. Used for a document the command did not compose itself,
53
+ * such as a pull request body or the output of a git mutation.
54
+ */
55
+ export function pipeOutput(text: string): void {
56
+ const lines = text.replace(/\n$/, '').split('\n')
57
+ process.stderr.write(
58
+ `${lines.map((line) => `${GREY}│${NC} ${line}`).join('\n')}\n`,
59
+ )
60
+ }
61
+
62
+ export function frameError(message: string): void {
63
+ process.stderr.write(
64
+ `${GREY}┌${NC}\n${GREY}│${NC} ${RED}✗${NC} ${message}\n${GREY}└${NC}\n`,
65
+ )
66
+ }
67
+
68
+ export function frameSuccess(command: string, target: string): void {
69
+ process.stderr.write(
70
+ `${GREY}┌${NC}\n${GREY}│${NC} ${WHITE}${command}${NC}\n${GREY}│${NC}\n${GREY}│${NC} ${GREEN}✓${NC} ${target}\n${GREY}└${NC}\n`,
71
+ )
72
+ }
73
+
74
+ export function isNonInteractive(): boolean {
75
+ return process.env.AITK_NON_INTERACTIVE === '1'
76
+ }
77
+
78
+ /**
79
+ * `nonInteractiveDefault` opts a prompt into the `select_option` behavior from
80
+ * `scripts/lib/ui.sh`, where `AITK_NON_INTERACTIVE=1` resolves to the first
81
+ * option instead of failing. Callers that would rather fail loudly than pick
82
+ * for the user leave it off.
83
+ */
84
+ export async function select<Value>(opts: {
85
+ message: string
86
+ options: { value: Value; label: string; hint?: string }[]
87
+ nonInteractiveDefault?: boolean
88
+ }): Promise<Value> {
89
+ const { message, options } = opts
90
+ const count = options.length
91
+ let cursor = 0
92
+
93
+ if (opts.nonInteractiveDefault && isNonInteractive()) {
94
+ process.stderr.write(
95
+ `${GREY}│${NC}\n${GREY}◇${NC} ${message} ${WHITE}${options[0].label}${NC}\n`,
96
+ )
97
+ return options[0].value
98
+ }
99
+
100
+ const render = (): void => {
101
+ let out = `${GREY}│${NC}\n${GREEN}◆${NC} ${message}\n`
102
+ for (let i = 0; i < count; i++) {
103
+ const label = options[i].label
104
+ const hint = options[i].hint ? ` ${GREY}${options[i].hint}${NC}` : ''
105
+ if (i === cursor) {
106
+ out += `${GREY}│${NC} ${GREEN}❯ ${label}${NC}${hint}\n`
107
+ } else {
108
+ out += `${GREY}│${NC} ${GREY}${label}${NC}${hint}\n`
109
+ }
110
+ }
111
+ process.stderr.write(out)
112
+ }
113
+
114
+ const clear = (): void => {
115
+ process.stderr.write(`\x1b[${count + 2}A\x1b[J`)
116
+ }
117
+
118
+ return new Promise<Value>((resolve) => {
119
+ if (!process.stdin.isTTY) {
120
+ process.stderr.write(
121
+ `${GREY}│${NC} ${RED}✗${NC} ${message} requires a TTY. Pass an argument or set AITK_NON_INTERACTIVE=1.\n${GREY}└${NC}\n`,
122
+ )
123
+ process.exit(1)
124
+ }
125
+
126
+ const wasRaw = process.stdin.isRaw
127
+ process.stdin.setRawMode(true)
128
+ process.stdin.resume()
129
+
130
+ render()
131
+
132
+ const onData = (data: Buffer): void => {
133
+ const key = data.toString()
134
+
135
+ if (key === '\x1b[A' || key === 'k') {
136
+ cursor = (cursor - 1 + count) % count
137
+ clear()
138
+ render()
139
+ } else if (key === '\x1b[B' || key === 'j') {
140
+ cursor = (cursor + 1) % count
141
+ clear()
142
+ render()
143
+ } else if (key === '\r' || key === '\n') {
144
+ cleanup()
145
+ clear()
146
+ process.stderr.write(
147
+ `${GREY}│${NC}\n${GREY}◇${NC} ${message} ${WHITE}${options[cursor].label}${NC}\n`,
148
+ )
149
+ resolve(options[cursor].value)
150
+ } else if (key === '\x1b' || key === 'q' || key === '\x03') {
151
+ cleanup()
152
+ clear()
153
+ process.stderr.write(
154
+ `${GREY}│${NC}\n${GREY}◇${NC} ${message} ${RED}Cancelled${NC}\n${GREY}└${NC}\n`,
155
+ )
156
+ process.exit(1)
157
+ }
158
+ }
159
+
160
+ const cleanup = (): void => {
161
+ process.stdin.removeListener('data', onData)
162
+ process.stdin.setRawMode(wasRaw ?? false)
163
+ process.stdin.pause()
164
+ }
165
+
166
+ process.stdin.on('data', onData)
167
+ })
168
+ }
169
+
170
+ export async function confirm(opts: {
171
+ message: string
172
+ active?: string
173
+ inactive?: string
174
+ }): Promise<boolean> {
175
+ const active = opts.active ?? 'Yes'
176
+ const inactive = opts.inactive ?? 'No'
177
+
178
+ const result = await select({
179
+ message: opts.message,
180
+ options: [
181
+ { value: true, label: active },
182
+ { value: false, label: inactive },
183
+ ],
184
+ })
185
+
186
+ return result
187
+ }
@@ -0,0 +1,85 @@
1
+ import { existsSync, statSync } from 'node:fs'
2
+ import { mkdir, writeFile } from 'node:fs/promises'
3
+ import { join } from 'node:path'
4
+
5
+ const WIKI_DIR = join('.claude', 'wiki')
6
+ const LEGACY_WIKI_DIR = 'wiki'
7
+ const INDEX_FILE = 'index.md'
8
+
9
+ export const WIKI_DIR_REL = `${WIKI_DIR}/`
10
+ export const WIKI_INDEX_REL = join(WIKI_DIR, INDEX_FILE)
11
+ export const LEGACY_WIKI_DIR_REL = `${LEGACY_WIKI_DIR}/`
12
+
13
+ const INDEX_SEED = `---
14
+ title: Wiki
15
+ subtitle: Reference pages for tools, workflows, and concepts
16
+ ---
17
+
18
+ # Wiki
19
+
20
+ Reference pages for tools, workflows, and concepts.
21
+ `
22
+
23
+ export type WikiChange = 'dir' | 'index'
24
+
25
+ export interface WikiPlan {
26
+ readonly changes: readonly WikiChange[]
27
+ readonly hasIndex: boolean
28
+ readonly hasLegacyWiki: boolean
29
+ }
30
+
31
+ export function wikiDir(target: string): string {
32
+ return join(target, WIKI_DIR)
33
+ }
34
+
35
+ /**
36
+ * A target scaffolded before the wiki moved under `.claude/` keeps its pages at
37
+ * the root. The verb reports that folder rather than moving it, because a move
38
+ * is a migration and the `migration-*` skills own those.
39
+ */
40
+ export function legacyWikiDir(target: string): string {
41
+ return join(target, LEGACY_WIKI_DIR)
42
+ }
43
+
44
+ /**
45
+ * Stands in for the `cd "$target"` in the bash `guard_root`, which validated
46
+ * the target existed as a side effect. Without it a typo'd path scaffolds a
47
+ * whole new tree, since the apply step creates parents.
48
+ */
49
+ export function isWikiTarget(target: string): boolean {
50
+ try {
51
+ return statSync(target).isDirectory()
52
+ } catch {
53
+ return false
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Reports what a scaffold would create without writing. The directory and the
59
+ * index are tracked separately because a target can carry one without the
60
+ * other, and only the index has content worth preserving.
61
+ */
62
+ export function planWikiInit(target: string): WikiPlan {
63
+ const dir = wikiDir(target)
64
+ const index = join(dir, INDEX_FILE)
65
+ const changes: WikiChange[] = []
66
+
67
+ if (!existsSync(dir)) changes.push('dir')
68
+
69
+ const hasIndex = existsSync(index)
70
+ if (!hasIndex) changes.push('index')
71
+
72
+ return { changes, hasIndex, hasLegacyWiki: existsSync(legacyWikiDir(target)) }
73
+ }
74
+
75
+ export async function applyWikiInit(
76
+ target: string,
77
+ plan: WikiPlan,
78
+ ): Promise<void> {
79
+ const dir = wikiDir(target)
80
+ await mkdir(dir, { recursive: true })
81
+
82
+ if (plan.changes.includes('index')) {
83
+ await writeFile(join(dir, INDEX_FILE), INDEX_SEED)
84
+ }
85
+ }
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Architecture reference
3
+ description: Shape and content rules for .claude/ARCHITECTURE.md
4
+ ---
5
+
6
+ # Architecture reference
7
+
8
+ Applies to `.claude/ARCHITECTURE.md`. Describes the system shape and the decisions behind it, not a tutorial, setup guide, or implementation walkthrough. Pair it with `CLAUDE.md`: principles live there, patterns and decisions live here. Update when a decision is made or a risk is resolved.
9
+
10
+ ## What goes in
11
+
12
+ - A high-level overview of how the system is structured and why
13
+ - Key technical decisions as named H3 entries: what was chosen and why over the alternatives, including stack and library choices
14
+ - Risks and open questions still unresolved
15
+
16
+ ## What does not go in
17
+
18
+ - Per-domain structure and narrative. That belongs in `.claude/context/<domain>.md`, one file per domain.
19
+ - Setup commands and install instructions. Those live in the README.
20
+ - How individual functions work line by line. Those go in code comments.
21
+ - Full type definitions. They live in code. Reference the shape conceptually if needed.
22
+
23
+ ## Sections
24
+
25
+ Use `## Overview`, `## Key technical decisions` with one named H3 per decision, and `## Risks / open questions`. Name each decision and give the reasoning, especially for non-obvious choices. Skip entries where the rationale is self-evident.
26
+
27
+ ## Template
28
+
29
+ ```markdown
30
+ # Architecture
31
+
32
+ ## Overview
33
+
34
+ ## Key technical decisions
35
+
36
+ ### Decision name
37
+
38
+ Reasoning and tradeoffs.
39
+
40
+ ## Risks / open questions
41
+ ```
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Branch reference
3
+ description: Branch naming format and type conventions
4
+ consumers: git-branch, git-split, git-pr, claude-standards-audit
5
+ ---
6
+
7
+ # Branch reference
8
+
9
+ ## Format
10
+
11
+ - Structure: `<type>/<description>` or `<type>/<ticket>-<description>`
12
+ - Length: 50 characters maximum
13
+ - Casing: kebab-case only, no underscores or camelCase
14
+ - Description: 2 words maximum, 3 only when genuinely needed for specificity
15
+ - Capture the core change, not the commit message verbatim
16
+ - For branches with multiple commits, use the unifying concern as the description.
17
+ - Do not duplicate type in description (e.g., `feat/feature-login`)
18
+
19
+ ## Types
20
+
21
+ - `feat`: new feature or capability
22
+ - `fix`: bug fix
23
+ - `refactor`: structural changes (not a fix or feature)
24
+ - `docs`: documentation only (README)
25
+ - `chore`: maintenance tasks (deps, tooling, configs)
26
+ - `perf`: performance improvements
27
+ - `test`: add or modify tests
28
+ - `style`: code formatting (whitespace, semicolons)
29
+ - `build`: build system changes (webpack, npm scripts)
30
+ - `ci`: CI/CD pipeline changes (GitHub Actions)
31
+ - `revert`: revert a previous commit
32
+
33
+ ## Examples
34
+
35
+ ### Correct
36
+
37
+ ```plaintext
38
+ feat/jwt-expiration # clear feature scope
39
+ fix/AUTH-123-connection-pool # includes ticket ID
40
+ refactor/remove-deprecated-endpoints # clear refactor intent
41
+ ```
42
+
43
+ ### Incorrect
44
+
45
+ ```plaintext
46
+ feature/auth_stuff # wrong type + underscore
47
+ feat/feature-add-login # duplicates type in description
48
+ fix/DB-456-fix-the-database-connection-pool-memory-leak # exceeds 50 chars + verbatim message
49
+ ```
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: Commit reference
3
+ description: Commit message format and type conventions
4
+ consumers: git-commit, git-stage
5
+ ---
6
+
7
+ # Commit message reference
8
+
9
+ ## Format
10
+
11
+ - Structure: `<type>(<scope>): <subject>`
12
+ - Casing: lowercase for `<type>`, `<scope>`, and first word of `<subject>`
13
+ - Subject: 72 characters maximum, no trailing period
14
+
15
+ ## Types
16
+
17
+ - `feat`: new feature or capability
18
+ - `fix`: bug fix
19
+ - `refactor`: structural changes (not a fix or feature)
20
+ - `docs`: documentation only (README)
21
+ - `chore`: maintenance tasks (deps, tooling, configs)
22
+ - `perf`: performance improvements
23
+ - `test`: add or modify tests
24
+ - `style`: code formatting (whitespace, semicolons)
25
+ - `build`: build system changes (webpack, npm scripts)
26
+ - `ci`: CI/CD pipeline changes (GitHub Actions)
27
+ - `revert`: revert a previous commit
28
+
29
+ ## Scope
30
+
31
+ - Single lowercase word representing a system component
32
+ - Prefer single word
33
+ - Use kebab-case only when two words are genuinely needed for specificity
34
+ - Do not use specific filenames as scopes
35
+ - Do not use a scope that duplicates the type
36
+ - Write scopes for release readability. They surface in `changelogithub` release notes.
37
+
38
+ ## Subject
39
+
40
+ - Use imperative mood (`add` not `added`)
41
+ - Describe the actual technical change, not that something changed
42
+ - Do not use vague verbs (`improve`, `refine`, `enhance`)
43
+ - Do not repeat the scope in the subject line
44
+ - Use single quotes if quoting
45
+ - No backslash escaping or internal double quotes
46
+ - No conversational filler or introductory phrases
47
+
48
+ ## Examples
49
+
50
+ ### Correct
51
+
52
+ ```plaintext
53
+ feat(api): add retry logic for failed webhooks # specific verb + clear change
54
+ fix(auth): update 'UserSession' validation logic # scoped + imperative + single quotes
55
+ ```
56
+
57
+ ### Incorrect
58
+
59
+ ```plaintext
60
+ fix(user-auth): Fixed the redirect loop. # wrong casing + period + multi-word scope
61
+ docs(docs): update the readme. # duplicate scope + period
62
+ docs(api): improve documentation # vague verb + lacks specificity
63
+ ```
@@ -0,0 +1,84 @@
1
+ ---
2
+ title: Issue reference
3
+ description: GitHub issue title, labels, and body conventions
4
+ consumers: git-issue
5
+ ---
6
+
7
+ # Issue reference
8
+
9
+ ## Title
10
+
11
+ - Format: `<type>: <subject>`
12
+ - Type is `bug` or `task`. Lowercase the type and the first word of the subject.
13
+ - Length: 72 characters maximum, no trailing period.
14
+
15
+ ## Labels
16
+
17
+ - Apply `bug` for a defect and `enhancement` for a task or improvement.
18
+ - Both are GitHub default labels. A label that does not exist makes `gh` reject the issue. Create it once with `gh label create`.
19
+ - One label per issue unless a second genuinely applies.
20
+
21
+ ## Content
22
+
23
+ - Use imperative mood and describe the actual defect or work, not that something is wrong.
24
+ - Do not open with "This issue," "I want," or "We should."
25
+ - Do not use buzzwords or speculative future scope.
26
+ - State observable behavior for a bug, not a guessed cause.
27
+
28
+ ## Sections
29
+
30
+ - `## Summary`: one line naming what and why.
31
+ - `## Details`: for a bug, what happens versus what is expected. For a task, what to build.
32
+ - `## Context`: for a bug, repro steps or commands. For a task, the driving reason, or `none`.
33
+ - `## Proposed` (optional): one line naming a fix or approach. Omit when open.
34
+
35
+ ## Formatting
36
+
37
+ - End every bullet with a period.
38
+ - Keep each section to one or two lines.
39
+
40
+ ## Examples
41
+
42
+ ### Correct (bug)
43
+
44
+ ```markdown
45
+ ## Summary
46
+
47
+ Fix the feedback CLI so it applies the `feedback` label.
48
+
49
+ ## Details
50
+
51
+ `aitk feedback --github` opens an issue with no label, so `toolkit-triage` never lists it.
52
+
53
+ ## Context
54
+
55
+ Run a piped `aitk feedback --github`, then check the issue carries no `feedback` label.
56
+
57
+ ## Proposed
58
+
59
+ Pass `--label feedback` through the shared issue helper.
60
+ ```
61
+
62
+ ### Correct (task)
63
+
64
+ ```markdown
65
+ ## Summary
66
+
67
+ Add a git-issue skill so a session can file an issue on the current repo.
68
+
69
+ ## Details
70
+
71
+ Format an issue from session context and file it with `gh issue create`, next to git-pr in the git family.
72
+
73
+ ## Context
74
+
75
+ The toolkit-issue skill only files on the toolkit repo. A general path is needed for target projects.
76
+ ```
77
+
78
+ ### Incorrect
79
+
80
+ ```markdown
81
+ ## Summary
82
+
83
+ This issue is about the feedback system being kind of broken, and we should probably make it more robust.
84
+ ```