@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.
- package/LICENSE +21 -0
- package/README.md +99 -0
- package/claude/.claude-plugin/plugin.json +19 -0
- package/claude/skills/bash-script/SKILL.md +96 -0
- package/claude/skills/bash-script/references/patterns.md +349 -0
- package/claude/skills/ci-workflow/SKILL.md +52 -0
- package/claude/skills/ci-workflow/references/workflows.md +74 -0
- package/claude/skills/claude-address-review/SKILL.md +107 -0
- package/claude/skills/claude-autoship/SKILL.md +137 -0
- package/claude/skills/claude-design-extract/SKILL.md +69 -0
- package/claude/skills/claude-design-propose/SKILL.md +75 -0
- package/claude/skills/claude-diagram/SKILL.md +126 -0
- package/claude/skills/claude-docs/SKILL.md +204 -0
- package/claude/skills/claude-feature/REQUIREMENT.md +35 -0
- package/claude/skills/claude-feature/SKILL.md +148 -0
- package/claude/skills/claude-groundwork/SKILL.md +148 -0
- package/claude/skills/claude-groundwork/references/folder-format.md +107 -0
- package/claude/skills/claude-memory-capture/SKILL.md +80 -0
- package/claude/skills/claude-memory-review/REQUIREMENT.md +37 -0
- package/claude/skills/claude-memory-review/SKILL.md +206 -0
- package/claude/skills/claude-orchestrate/SKILL.md +125 -0
- package/claude/skills/claude-pr-review/SKILL.md +150 -0
- package/claude/skills/claude-review/SKILL.md +136 -0
- package/claude/skills/claude-roadmap/SKILL.md +61 -0
- package/claude/skills/claude-roadmap/references/roadmap.md +52 -0
- package/claude/skills/claude-screencast/SKILL.md +160 -0
- package/claude/skills/claude-seed-sync/SKILL.md +141 -0
- package/claude/skills/claude-slides-draft/SKILL.md +62 -0
- package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
- package/claude/skills/claude-standards-audit/SKILL.md +79 -0
- package/claude/skills/claude-standards-audit/references/branch.md +49 -0
- package/claude/skills/claude-standards-audit/references/pr.md +124 -0
- package/claude/skills/claude-tasks/SKILL.md +123 -0
- package/claude/skills/claude-ui-test/SKILL.md +75 -0
- package/claude/skills/claude-ux-audit/SKILL.md +78 -0
- package/claude/skills/claude-worktree/SKILL.md +79 -0
- package/claude/skills/cli-script/SKILL.md +47 -0
- package/claude/skills/cli-script/references/template.md +43 -0
- package/claude/skills/create-rule/SKILL.md +68 -0
- package/claude/skills/create-skill/REQUIREMENT.md +30 -0
- package/claude/skills/create-skill/SKILL.md +24 -0
- package/claude/skills/create-snippet/SKILL.md +28 -0
- package/claude/skills/create-snippet/references/snippets.md +57 -0
- package/claude/skills/create-standard/SKILL.md +31 -0
- package/claude/skills/create-standard/references/standard.md +52 -0
- package/claude/skills/docs-sync/SKILL.md +87 -0
- package/claude/skills/git-branch/REQUIREMENT.md +38 -0
- package/claude/skills/git-branch/SKILL.md +60 -0
- package/claude/skills/git-branch/references/branch.md +49 -0
- package/claude/skills/git-commit/REQUIREMENT.md +33 -0
- package/claude/skills/git-commit/SKILL.md +51 -0
- package/claude/skills/git-commit/references/commit.md +63 -0
- package/claude/skills/git-followup/REQUIREMENT.md +38 -0
- package/claude/skills/git-followup/SKILL.md +35 -0
- package/claude/skills/git-issue/REQUIREMENT.md +38 -0
- package/claude/skills/git-issue/SKILL.md +69 -0
- package/claude/skills/git-issue/references/issue.md +84 -0
- package/claude/skills/git-pr/REQUIREMENT.md +37 -0
- package/claude/skills/git-pr/SKILL.md +119 -0
- package/claude/skills/git-pr/references/branch.md +49 -0
- package/claude/skills/git-pr/references/pr.md +124 -0
- package/claude/skills/git-ship/REQUIREMENT.md +34 -0
- package/claude/skills/git-ship/SKILL.md +39 -0
- package/claude/skills/git-split/REQUIREMENT.md +38 -0
- package/claude/skills/git-split/SKILL.md +160 -0
- package/claude/skills/git-split/references/branch.md +49 -0
- package/claude/skills/git-split/references/pr.md +124 -0
- package/claude/skills/git-stage/REQUIREMENT.md +36 -0
- package/claude/skills/git-stage/SKILL.md +74 -0
- package/claude/skills/git-stage/references/commit.md +63 -0
- package/claude/skills/git-worktree/REQUIREMENT.md +37 -0
- package/claude/skills/git-worktree/SKILL.md +120 -0
- package/claude/skills/migration-claude-md/SKILL.md +74 -0
- package/claude/skills/migration-context/SKILL.md +93 -0
- package/claude/skills/migration-standards/SKILL.md +75 -0
- package/claude/skills/project-commands/SKILL.md +73 -0
- package/claude/skills/session-resume/SKILL.md +36 -0
- package/claude/skills/setup-gov/SKILL.md +71 -0
- package/claude/skills/setup-indexes/SKILL.md +148 -0
- package/claude/skills/setup-init/SKILL.md +114 -0
- package/claude/skills/setup-plugins/SKILL.md +81 -0
- package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
- package/claude/skills/setup-verify/SKILL.md +51 -0
- package/claude/skills/systematic-debugging/SKILL.md +70 -0
- package/claude/skills/toolkit-cli/SKILL.md +38 -0
- package/claude/skills/toolkit-feedback/SKILL.md +80 -0
- package/claude/skills/toolkit-operator/SKILL.md +45 -0
- package/claude/skills/toolkit-triage/SKILL.md +63 -0
- package/claude/skills/youtube-transcripts/SKILL.md +34 -0
- package/docs/agents.md +371 -0
- package/docs/ai-workflow.md +157 -0
- package/docs/index.md +20 -0
- package/docs/operating-model.md +106 -0
- package/docs/target-projects.md +183 -0
- package/docs/visual-design-workflow.md +136 -0
- package/docs/zshrc-aliases.md +65 -0
- package/governance/rules/claude/500-prose.md +12 -0
- package/governance/rules/claude/510-context.md +16 -0
- package/governance/rules/claude/520-wireframes.md +12 -0
- package/governance/rules/claude/530-requirements.md +11 -0
- package/governance/rules/claude/540-architecture.md +11 -0
- package/governance/rules/claude/550-design.md +11 -0
- package/governance/rules/claude/555-tasks.md +12 -0
- package/governance/rules/claude/560-diagrams.md +11 -0
- package/governance/rules/claude/570-skill.md +18 -0
- package/governance/rules/claude/580-readme.md +11 -0
- package/governance/rules/claude/590-rule-authoring.md +12 -0
- package/governance/rules/core/000-constitution.md +30 -0
- package/governance/rules/core/010-testing.md +35 -0
- package/governance/rules/core/020-concurrency.md +22 -0
- package/governance/rules/core/030-error-handling.md +31 -0
- package/governance/rules/core/040-performance.md +20 -0
- package/governance/rules/core/050-logging.md +20 -0
- package/governance/rules/core/060-naming.md +19 -0
- package/governance/rules/core/070-planning.md +13 -0
- package/governance/rules/core/080-config-comments.md +22 -0
- package/governance/rules/framework/200-react.md +51 -0
- package/governance/rules/framework/210-astro.md +41 -0
- package/governance/rules/framework/220-fastapi.md +43 -0
- package/governance/rules/framework/230-nextjs.md +48 -0
- package/governance/rules/framework/250-tailwind.md +32 -0
- package/governance/rules/framework/260-shadcn.md +34 -0
- package/governance/rules/lang/100-typescript.md +40 -0
- package/governance/rules/lang/110-python.md +42 -0
- package/governance/rules/lib/300-testing-ts.md +38 -0
- package/governance/rules/lib/310-zod.md +25 -0
- package/governance/rules/lib/320-tanstack-query.md +32 -0
- package/governance/rules/lib/330-testing-py.md +44 -0
- package/governance/rules/lib/340-pydantic.md +38 -0
- package/governance/rules/lib/350-security-web.md +31 -0
- package/governance/rules/ui/400-ui.md +34 -0
- package/governance/rules/ui/410-a11y.md +44 -0
- package/governance/rules/ui/420-forms.md +34 -0
- package/governance/rules/ui/430-ux-completeness.md +62 -0
- package/governance/stacks/astro.toml +2 -0
- package/governance/stacks/base.toml +2 -0
- package/governance/stacks/node.toml +2 -0
- package/governance/stacks/python-fastapi.toml +2 -0
- package/governance/stacks/python.toml +2 -0
- package/governance/stacks/react.toml +2 -0
- package/package.json +67 -0
- package/scripts/config.sh +11 -0
- package/scripts/core/bootstrap.sh +81 -0
- package/scripts/core/check-plugin-boundary.sh +45 -0
- package/scripts/core/check-skill-paths.sh +25 -0
- package/scripts/core/clean.sh +36 -0
- package/scripts/core/install-check.sh +93 -0
- package/scripts/core/regen-claude-copies.sh +26 -0
- package/scripts/core/regen-indexes.sh +10 -0
- package/scripts/core/regen-skill-references.sh +27 -0
- package/scripts/core/snapshot.sh +132 -0
- package/scripts/core/update.sh +35 -0
- package/scripts/core/verify.sh +201 -0
- package/scripts/docs/list.sh +129 -0
- package/scripts/gov/list.sh +234 -0
- package/scripts/lib/frontmatter.sh +30 -0
- package/scripts/lib/gov.sh +14 -0
- package/scripts/lib/sandbox-fixtures.sh +109 -0
- package/scripts/lib/sandbox-git.sh +73 -0
- package/scripts/lib/tooling.sh +24 -0
- package/scripts/lib/ui.sh +173 -0
- package/scripts/lib/worktree.sh +20 -0
- package/scripts/manage-sandbox.sh +453 -0
- package/scripts/snippets/create.sh +156 -0
- package/scripts/standards/list.sh +91 -0
- package/scripts/tooling/create.sh +109 -0
- package/scripts/tooling/ref.sh +141 -0
- package/scripts/tooling/verify.sh +179 -0
- package/snippets/claude/decision-memo.md +39 -0
- package/snippets/claude/feature-recap.md +19 -0
- package/snippets/claude/figma-steps.md +18 -0
- package/snippets/claude/orchestrator-resume.md +23 -0
- package/snippets/claude/orchestrator-sweep.md +10 -0
- package/snippets/compact-summary.md +5 -0
- package/snippets/create-snippet.md +7 -0
- package/snippets/decision-help.md +6 -0
- package/snippets/meta-prompt.md +14 -0
- package/snippets/research-prompt.md +7 -0
- package/snippets/session-notes.md +11 -0
- package/snippets/snippets.toml +6 -0
- package/snippets/step-by-step.md +10 -0
- package/snippets/web-research.md +21 -0
- package/src/claude/gitignore.ts +51 -0
- package/src/claude/seeds-list.ts +47 -0
- package/src/claude/seeds.ts +124 -0
- package/src/claude/settings.ts +151 -0
- package/src/cli-run.ts +43 -0
- package/src/cli.ts +111 -0
- package/src/commands/claude.ts +349 -0
- package/src/commands/design.ts +39 -0
- package/src/commands/docs.ts +59 -0
- package/src/commands/feedback-format.ts +23 -0
- package/src/commands/feedback.ts +103 -0
- package/src/commands/gov.ts +268 -0
- package/src/commands/indexes.ts +182 -0
- package/src/commands/init.ts +117 -0
- package/src/commands/pass-through.ts +39 -0
- package/src/commands/sandbox.ts +315 -0
- package/src/commands/slides.ts +106 -0
- package/src/commands/snippets.ts +236 -0
- package/src/commands/standards.ts +89 -0
- package/src/commands/sync.ts +211 -0
- package/src/commands/tasks.ts +185 -0
- package/src/commands/tooling.ts +432 -0
- package/src/commands/transcripts.ts +48 -0
- package/src/commands/wiki.ts +101 -0
- package/src/copy.ts +30 -0
- package/src/design/parse.ts +79 -0
- package/src/design/render.ts +170 -0
- package/src/docs/read.ts +59 -0
- package/src/exec.ts +17 -0
- package/src/frontmatter.ts +13 -0
- package/src/github-format.ts +13 -0
- package/src/github.ts +20 -0
- package/src/gov/adapter.ts +73 -0
- package/src/gov/install.ts +103 -0
- package/src/gov/payload.ts +39 -0
- package/src/gov/stacks.ts +124 -0
- package/src/indexes/frontmatter.ts +46 -0
- package/src/indexes/regen.ts +84 -0
- package/src/indexes/render.ts +181 -0
- package/src/indexes/walk.ts +111 -0
- package/src/init/flags.ts +66 -0
- package/src/init/plan.ts +128 -0
- package/src/init/run.ts +46 -0
- package/src/init/steps.ts +91 -0
- package/src/sandbox/coverage.ts +115 -0
- package/src/sandbox/expect.ts +412 -0
- package/src/slides/layouts.ts +391 -0
- package/src/slides/open.ts +18 -0
- package/src/slides/parse.ts +84 -0
- package/src/slides/render.ts +88 -0
- package/src/slides/styles.ts +44 -0
- package/src/snippets/adapter.ts +34 -0
- package/src/snippets/categories.ts +59 -0
- package/src/snippets/install.ts +125 -0
- package/src/snippets/list.ts +32 -0
- package/src/snippets/presets.ts +50 -0
- package/src/standards/adapter.ts +51 -0
- package/src/standards/index-refresh.ts +44 -0
- package/src/standards/install.ts +52 -0
- package/src/sync/check.ts +269 -0
- package/src/sync/engine.ts +416 -0
- package/src/sync/git.ts +204 -0
- package/src/sync/stamp.ts +202 -0
- package/src/sync/target.ts +79 -0
- package/src/sync/workflow.ts +201 -0
- package/src/target.ts +43 -0
- package/src/tasks/archive.ts +304 -0
- package/src/tooling/gitignore.ts +122 -0
- package/src/tooling/inject.ts +214 -0
- package/src/tooling/list.ts +39 -0
- package/src/tooling/manifest.ts +178 -0
- package/src/tooling/package.ts +166 -0
- package/src/tooling/scan.ts +186 -0
- package/src/transcripts/fetch.ts +156 -0
- package/src/transcripts/metadata.ts +54 -0
- package/src/transcripts/vtt.ts +114 -0
- package/src/ui.ts +187 -0
- package/src/wiki/init.ts +85 -0
- package/standards/architecture.md +41 -0
- package/standards/bundled/branch.md +49 -0
- package/standards/bundled/commit.md +63 -0
- package/standards/bundled/issue.md +84 -0
- package/standards/bundled/pr.md +124 -0
- package/standards/bundled/roadmap.md +52 -0
- package/standards/bundled/snippets.md +57 -0
- package/standards/bundled/standard.md +52 -0
- package/standards/context.md +132 -0
- package/standards/design.md +31 -0
- package/standards/diagrams.md +55 -0
- package/standards/index.md +21 -0
- package/standards/prose.md +122 -0
- package/standards/readme.md +163 -0
- package/standards/requirements.md +61 -0
- package/standards/rule.md +79 -0
- package/standards/skill.md +257 -0
- package/standards/tasks.md +140 -0
- package/standards/versioning.md +47 -0
- package/standards/wireframes.md +67 -0
- package/tooling/astro/configs/astro.config.mjs +17 -0
- package/tooling/astro/configs/eslint.config.js +79 -0
- package/tooling/astro/configs/playwright.config.ts +25 -0
- package/tooling/astro/configs/tsconfig.json +12 -0
- package/tooling/astro/configs/vitest.config.ts +22 -0
- package/tooling/astro/manifest.toml +32 -0
- package/tooling/astro/reference.md +60 -0
- package/tooling/base/configs/.editorconfig +5 -0
- package/tooling/base/configs/.github/pull_request_template.md +18 -0
- package/tooling/base/configs/.github/workflows/verify.yml +35 -0
- package/tooling/base/configs/.husky/commit-msg +1 -0
- package/tooling/base/configs/.husky/post-merge +61 -0
- package/tooling/base/configs/.husky/post-rewrite +21 -0
- package/tooling/base/configs/.husky/pre-commit +1 -0
- package/tooling/base/configs/.husky/pre-push +1 -0
- package/tooling/base/configs/.prettierrc +12 -0
- package/tooling/base/configs/.shellcheckrc +1 -0
- package/tooling/base/configs/.vscode/extensions.json +9 -0
- package/tooling/base/configs/.vscode/settings.json +3 -0
- package/tooling/base/configs/commitlint.config.js +11 -0
- package/tooling/base/configs/scripts/clean.sh +45 -0
- package/tooling/base/configs/scripts/update.sh +49 -0
- package/tooling/base/configs/scripts/verify.sh +64 -0
- package/tooling/base/manifest.toml +32 -0
- package/tooling/base/reference.md +114 -0
- package/tooling/base/seeds/.claude/context/ci.md +27 -0
- package/tooling/base/seeds/.claude/context/development.md +32 -0
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/base/seeds/.lintstagedrc +8 -0
- package/tooling/base/seeds/.prettierignore +0 -0
- package/tooling/base/seeds/cspell.json +20 -0
- package/tooling/claude/manifest.toml +11 -0
- package/tooling/claude/reference.md +62 -0
- package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
- package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
- package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
- package/tooling/claude/seeds/.claude/context/index.md +8 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +43 -0
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +45 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +61 -0
- package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +60 -0
- package/tooling/claude/seeds/.claude/settings.json +39 -0
- package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
- package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
- package/tooling/claude/seeds/CLAUDE.md +87 -0
- package/tooling/claude/user/settings.template.json +10 -0
- package/tooling/claude/user/statusline-command.sh +53 -0
- package/tooling/python/configs/.coveragerc +14 -0
- package/tooling/python/configs/.python-version +1 -0
- package/tooling/python/configs/mypy.ini +6 -0
- package/tooling/python/configs/pytest.ini +4 -0
- package/tooling/python/configs/ruff.toml +15 -0
- package/tooling/python/configs/scripts/verify.sh +77 -0
- package/tooling/python/manifest.toml +16 -0
- package/tooling/python/reference.md +66 -0
- package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/python/seeds/tests/test_smoke.py +2 -0
- package/tooling/vite-react/configs/playwright.config.ts +25 -0
- package/tooling/vite-react/configs/tsconfig.json +35 -0
- package/tooling/vite-react/configs/vite.config.ts +14 -0
- package/tooling/vite-react/configs/vitest.config.ts +26 -0
- package/tooling/vite-react/manifest.toml +21 -0
- package/tooling/vite-react/reference.md +55 -0
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
- package/tooling/web/configs/.github/workflows/verify.yml +134 -0
- package/tooling/web/configs/.vscode/extensions.json +13 -0
- package/tooling/web/configs/.vscode/settings.json +10 -0
- package/tooling/web/configs/e2e/home.spec.ts +6 -0
- package/tooling/web/configs/e2e/screenshot.ts +41 -0
- package/tooling/web/configs/eslint.config.js +82 -0
- package/tooling/web/configs/scripts/screenshot.sh +28 -0
- package/tooling/web/configs/scripts/verify.sh +80 -0
- package/tooling/web/configs/src/test/setup.ts +8 -0
- package/tooling/web/manifest.toml +57 -0
- package/tooling/web/reference.md +95 -0
- package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
- 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
|
+
}
|
package/src/wiki/init.ts
ADDED
|
@@ -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
|
+
```
|