@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,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
|
+
}
|