@evertonferreira96/agents 0.0.0-stage → 0.1.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/.claude/agents/api.md +45 -0
- package/.claude/agents/app.md +41 -0
- package/.claude/agents/architect.md +49 -0
- package/.claude/agents/infra.md +27 -0
- package/.claude/agents/product.md +58 -0
- package/.claude/agents/quick.md +33 -0
- package/.claude/agents/security.md +39 -0
- package/.claude/agents/ui.md +54 -0
- package/.claude/agents/verifier.md +56 -0
- package/.claude/agents/web.md +41 -0
- package/.claude/hooks/config-update-check.mjs +14 -0
- package/.claude/hooks/context-budget.mjs +51 -0
- package/.claude/hooks/graphify-update.sh +16 -0
- package/.claude/hooks/guard-bash.sh +64 -0
- package/.claude/hooks/orchestrator-guard.sh +49 -0
- package/.claude/hooks/post-compact.sh +26 -0
- package/.claude/hooks/readonly-guard.sh +54 -0
- package/.claude/hooks/stop-verify.sh +52 -0
- package/.claude/rules/api.md +21 -0
- package/.claude/rules/db.md +9 -0
- package/.claude/rules/delivery-diagram.md +16 -0
- package/.claude/rules/git-workflow.md +34 -0
- package/.claude/rules/graphify.md +3 -0
- package/.claude/rules/mobile.md +22 -0
- package/.claude/rules/tickets.md +9 -0
- package/.claude/rules/ui.md +14 -0
- package/.claude/rules/web.md +27 -0
- package/.claude/settings.json +114 -0
- package/.claude/skills/animate/RECIPES.md +324 -0
- package/.claude/skills/animate/SKILL.md +208 -0
- package/.claude/skills/animate/agents/openai.yaml +5 -0
- package/.claude/skills/animate-expo/RECIPES.md +385 -0
- package/.claude/skills/animate-expo/SKILL.md +264 -0
- package/.claude/skills/animate-expo/agents/openai.yaml +5 -0
- package/.claude/skills/animation-performance/SKILL.md +223 -0
- package/.claude/skills/animation-performance/agents/openai.yaml +5 -0
- package/.claude/skills/apple-design/SKILL.md +291 -0
- package/.claude/skills/apple-design/agents/openai.yaml +5 -0
- package/.claude/skills/arch-api/SKILL.md +291 -0
- package/.claude/skills/arch-api/agents/openai.yaml +3 -0
- package/.claude/skills/arch-api/references/common.md +174 -0
- package/.claude/skills/arch-api/references/contract.md +289 -0
- package/.claude/skills/arch-api/references/domain.md +301 -0
- package/.claude/skills/arch-api/references/endpoints.md +184 -0
- package/.claude/skills/arch-api/references/review.md +228 -0
- package/.claude/skills/arch-api/references/security.md +151 -0
- package/.claude/skills/arch-app/SKILL.md +278 -0
- package/.claude/skills/arch-app/agents/openai.yaml +3 -0
- package/.claude/skills/arch-app/references/navigation-session.md +257 -0
- package/.claude/skills/arch-app/references/review.md +155 -0
- package/.claude/skills/arch-app/references/screens.md +214 -0
- package/.claude/skills/arch-app/references/services.md +301 -0
- package/.claude/skills/arch-app/references/ui-mobile.md +124 -0
- package/.claude/skills/arch-db/SKILL.md +181 -0
- package/.claude/skills/arch-db/agents/openai.yaml +3 -0
- package/.claude/skills/arch-db/references/indexes-queries.md +251 -0
- package/.claude/skills/arch-db/references/migrations.md +191 -0
- package/.claude/skills/arch-db/references/modeling.md +214 -0
- package/.claude/skills/arch-db/references/mysql.md +262 -0
- package/.claude/skills/arch-db/references/pooling-ops.md +112 -0
- package/.claude/skills/arch-db/references/review.md +143 -0
- package/.claude/skills/arch-db/references/transactions-locks.md +141 -0
- package/.claude/skills/arch-web/SKILL.md +307 -0
- package/.claude/skills/arch-web/agents/openai.yaml +3 -0
- package/.claude/skills/arch-web/references/auth-session-env.md +165 -0
- package/.claude/skills/arch-web/references/blocks.md +198 -0
- package/.claude/skills/arch-web/references/cache.md +124 -0
- package/.claude/skills/arch-web/references/review.md +142 -0
- package/.claude/skills/arch-web/references/services.md +297 -0
- package/.claude/skills/arch-web/references/tests.md +159 -0
- package/.claude/skills/arch-web/references/ui-forms.md +143 -0
- package/.claude/skills/break-ui/CATALOG.md +135 -0
- package/.claude/skills/break-ui/SKILL.md +176 -0
- package/.claude/skills/break-ui/agents/openai.yaml +5 -0
- package/.claude/skills/brief/SKILL.md +91 -0
- package/.claude/skills/brief/agents/openai.yaml +3 -0
- package/.claude/skills/diagnosing-bugs/SKILL.md +138 -0
- package/.claude/skills/diagnosing-bugs/agents/openai.yaml +3 -0
- package/.claude/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
- package/.claude/skills/emil-design-eng/SKILL.md +675 -0
- package/.claude/skills/emil-design-eng/agents/openai.yaml +5 -0
- package/.claude/skills/find-animation-opportunities/SKILL.md +141 -0
- package/.claude/skills/find-animation-opportunities/agents/openai.yaml +5 -0
- package/.claude/skills/graphify/.graphify_version +1 -0
- package/.claude/skills/graphify/SKILL.md +742 -0
- package/.claude/skills/graphify/agents/openai.yaml +3 -0
- package/.claude/skills/graphify/references/add-watch.md +56 -0
- package/.claude/skills/graphify/references/exports.md +91 -0
- package/.claude/skills/graphify/references/extraction-spec.md +70 -0
- package/.claude/skills/graphify/references/github-and-merge.md +46 -0
- package/.claude/skills/graphify/references/hooks.md +33 -0
- package/.claude/skills/graphify/references/query.md +317 -0
- package/.claude/skills/graphify/references/transcribe.md +52 -0
- package/.claude/skills/graphify/references/update.md +221 -0
- package/.claude/skills/grill-me/SKILL.md +7 -0
- package/.claude/skills/grill-me/agents/openai.yaml +5 -0
- package/.claude/skills/grill-with-docs/SKILL.md +64 -0
- package/.claude/skills/grill-with-docs/agents/openai.yaml +5 -0
- package/.claude/skills/grilling/SKILL.md +30 -0
- package/.claude/skills/grilling/agents/openai.yaml +3 -0
- package/.claude/skills/handoff/SKILL.md +28 -0
- package/.claude/skills/handoff/agents/openai.yaml +5 -0
- package/.claude/skills/impeccable/SKILL.md +89 -0
- package/.claude/skills/impeccable/agents/openai.yaml +5 -0
- package/.claude/skills/impeccable/reference/adapt.md +318 -0
- package/.claude/skills/impeccable/reference/adapt.native.md +58 -0
- package/.claude/skills/impeccable/reference/android.md +46 -0
- package/.claude/skills/impeccable/reference/animate.md +89 -0
- package/.claude/skills/impeccable/reference/audit.md +137 -0
- package/.claude/skills/impeccable/reference/audit.native.md +139 -0
- package/.claude/skills/impeccable/reference/bolder.md +33 -0
- package/.claude/skills/impeccable/reference/clarify.md +94 -0
- package/.claude/skills/impeccable/reference/colorize.md +86 -0
- package/.claude/skills/impeccable/reference/component-review.md +63 -0
- package/.claude/skills/impeccable/reference/craft-floor.md +44 -0
- package/.claude/skills/impeccable/reference/craft.md +5 -0
- package/.claude/skills/impeccable/reference/critique.md +809 -0
- package/.claude/skills/impeccable/reference/degraded/asset-producer.md +42 -0
- package/.claude/skills/impeccable/reference/degraded/documenter.md +24 -0
- package/.claude/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
- package/.claude/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
- package/.claude/skills/impeccable/reference/delight.md +70 -0
- package/.claude/skills/impeccable/reference/distill.md +111 -0
- package/.claude/skills/impeccable/reference/doctor.md +54 -0
- package/.claude/skills/impeccable/reference/document.md +416 -0
- package/.claude/skills/impeccable/reference/extract.md +69 -0
- package/.claude/skills/impeccable/reference/generate.md +101 -0
- package/.claude/skills/impeccable/reference/harden.md +345 -0
- package/.claude/skills/impeccable/reference/hooks.md +113 -0
- package/.claude/skills/impeccable/reference/init.md +131 -0
- package/.claude/skills/impeccable/reference/ios.md +51 -0
- package/.claude/skills/impeccable/reference/layout.md +84 -0
- package/.claude/skills/impeccable/reference/live-setup.md +104 -0
- package/.claude/skills/impeccable/reference/live.md +325 -0
- package/.claude/skills/impeccable/reference/mode-operate.md +21 -0
- package/.claude/skills/impeccable/reference/mode-persuade.md +19 -0
- package/.claude/skills/impeccable/reference/mode-read.md +21 -0
- package/.claude/skills/impeccable/reference/new-work.md +154 -0
- package/.claude/skills/impeccable/reference/onboard.md +234 -0
- package/.claude/skills/impeccable/reference/operate.md +61 -0
- package/.claude/skills/impeccable/reference/optimize.md +258 -0
- package/.claude/skills/impeccable/reference/overdrive.md +127 -0
- package/.claude/skills/impeccable/reference/polish.md +105 -0
- package/.claude/skills/impeccable/reference/quieter.md +99 -0
- package/.claude/skills/impeccable/reference/region-map.md +26 -0
- package/.claude/skills/impeccable/reference/routing.md +24 -0
- package/.claude/skills/impeccable/reference/shape.md +59 -0
- package/.claude/skills/impeccable/reference/typeset.md +80 -0
- package/.claude/skills/impeccable/reference/visualize.md +47 -0
- package/.claude/skills/impeccable/scripts/VERSION +1 -0
- package/.claude/skills/impeccable/scripts/command-metadata.json +98 -0
- package/.claude/skills/impeccable/scripts/data/font-index-failures.json +121 -0
- package/.claude/skills/impeccable/scripts/data/font-index.json +1 -0
- package/.claude/skills/impeccable/scripts/impeccable +206 -0
- package/.claude/skills/impeccable/scripts/impeccable.cmd +214 -0
- package/.claude/skills/impeccable/scripts/live-browser-dom.js +281 -0
- package/.claude/skills/impeccable/scripts/live-browser-ignores.js +242 -0
- package/.claude/skills/impeccable/scripts/live-browser-session.js +148 -0
- package/.claude/skills/impeccable/scripts/live-browser.js +13532 -0
- package/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/.claude/skills/improve-animations/AUDIT.md +115 -0
- package/.claude/skills/improve-animations/PLAN-TEMPLATE.md +73 -0
- package/.claude/skills/improve-animations/SKILL.md +110 -0
- package/.claude/skills/improve-animations/agents/openai.yaml +5 -0
- package/.claude/skills/mobile-native/SKILL.md +311 -0
- package/.claude/skills/mobile-native/agents/openai.yaml +3 -0
- package/.claude/skills/orchestrate/SKILL.md +181 -0
- package/.claude/skills/orchestrate/agents/openai.yaml +3 -0
- package/.claude/skills/pick-ui-library/SKILL.md +85 -0
- package/.claude/skills/pick-ui-library/agents/openai.yaml +5 -0
- package/.claude/skills/ponytail/SKILL.md +52 -0
- package/.claude/skills/ponytail/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-audit/SKILL.md +103 -0
- package/.claude/skills/ponytail-audit/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-debt/SKILL.md +44 -0
- package/.claude/skills/ponytail-debt/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-review/SKILL.md +101 -0
- package/.claude/skills/ponytail-review/agents/openai.yaml +3 -0
- package/.claude/skills/postgres-best-practices/SKILL.md +42 -0
- package/.claude/skills/postgres-best-practices/agents/openai.yaml +3 -0
- package/.claude/skills/postgres-best-practices/references/backup-restore.md +372 -0
- package/.claude/skills/postgres-best-practices/references/bulk-loading.md +315 -0
- package/.claude/skills/postgres-best-practices/references/connection-pooling.md +310 -0
- package/.claude/skills/postgres-best-practices/references/hot-standby.md +221 -0
- package/.claude/skills/postgres-best-practices/references/indexing.md +318 -0
- package/.claude/skills/postgres-best-practices/references/logical-replication.md +610 -0
- package/.claude/skills/postgres-best-practices/references/major-version-upgrades.md +334 -0
- package/.claude/skills/postgres-best-practices/references/performance-diagnostics.md +553 -0
- package/.claude/skills/postgres-best-practices/references/query-optimization.md +294 -0
- package/.claude/skills/postgres-best-practices/references/query-patterns.md +566 -0
- package/.claude/skills/postgres-best-practices/references/schema-design.md +362 -0
- package/.claude/skills/postgres-best-practices/references/security-roles.md +489 -0
- package/.claude/skills/postgres-best-practices/references/transaction-isolation.md +344 -0
- package/.claude/skills/project-docs/SKILL.md +330 -0
- package/.claude/skills/project-docs/agents/openai.yaml +3 -0
- package/.claude/skills/prototype/PICKER.md +197 -0
- package/.claude/skills/prototype/SKILL.md +98 -0
- package/.claude/skills/prototype/agents/openai.yaml +5 -0
- package/.claude/skills/retro/SKILL.md +43 -0
- package/.claude/skills/retro/agents/openai.yaml +5 -0
- package/.claude/skills/review/SKILL.md +74 -0
- package/.claude/skills/review/agents/openai.yaml +3 -0
- package/.claude/skills/review/references/smells.md +23 -0
- package/.claude/skills/review-animations/SKILL.md +120 -0
- package/.claude/skills/review-animations/STANDARDS.md +187 -0
- package/.claude/skills/review-animations/agents/openai.yaml +5 -0
- package/.claude/skills/tdd/SKILL.md +38 -0
- package/.claude/skills/tdd/agents/openai.yaml +3 -0
- package/.claude/skills/tdd/mocking.md +59 -0
- package/.claude/skills/tdd/tests.md +77 -0
- package/.claude/skills/triage/SKILL.md +58 -0
- package/.claude/skills/triage/agents/openai.yaml +3 -0
- package/.claude/skills/ui-ux-pro-max/SKILL.md +378 -0
- package/.claude/skills/ui-ux-pro-max/agents/openai.yaml +5 -0
- package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.claude/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/.claude/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
- package/.claude/skills/writing-for-agents/SKILL.md +81 -0
- package/.claude/skills/writing-for-agents/agents/openai.yaml +3 -0
- package/.worktreeinclude +3 -0
- package/AGENTS.md +44 -0
- package/README.md +14 -2
- package/VERSION +1 -0
- package/bin/agents.mjs +45 -0
- package/docs/adr/README.md +31 -0
- package/docs/brief-template.md +3 -0
- package/docs/plans/README.md +73 -0
- package/package.json +46 -4
- package/scripts/bootstrap.mjs +188 -0
- package/scripts/check-catalog.mjs +43 -0
- package/scripts/skills-update.mjs +51 -0
- package/skills-lock.json +269 -0
- package/templates/CLAUDE.project.md +41 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Install this config into a project, keep it updated, or check it for drift.
|
|
3
|
+
// Preferred entry: the package CLI, bin/agents.mjs (`npx <package> init | update | check`).
|
|
4
|
+
// Legacy entry, kept for projects bootstrapped from a local clone:
|
|
5
|
+
// node scripts/bootstrap.mjs <target> init: copy what is missing; never overwrite
|
|
6
|
+
// node scripts/bootstrap.mjs <target> --check check: list missing, outdated, edited and obsolete files; exit 1 on drift
|
|
7
|
+
// node scripts/bootstrap.mjs <target> --force update --force: also overwrite files edited in the project
|
|
8
|
+
// node scripts/bootstrap.mjs --sync inside a project bootstrapped from a local clone: pull it, then update
|
|
9
|
+
// Protected (never written over): CLAUDE.md, .claude/settings.local.json, .claude/agent-memory/**
|
|
10
|
+
// .claude/config-manifest.json records the hash of every file the config installed. `update` uses it to tell a file that is
|
|
11
|
+
// only outdated (overwritten) from one edited in the project (kept unless --force), and deletes files that left the config
|
|
12
|
+
// only when the project copy is untouched.
|
|
13
|
+
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, rmdirSync, statSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { spawnSync } from "node:child_process";
|
|
15
|
+
import { createHash } from "node:crypto";
|
|
16
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
|
|
19
|
+
export const SYNC = [".claude/agents", ".claude/hooks", ".claude/rules", ".claude/skills", ".claude/settings.json", "AGENTS.md", ".worktreeinclude",
|
|
20
|
+
"docs/plans/README.md", "docs/adr/README.md", "docs/brief-template.md", "scripts/skills-update.mjs", "scripts/check-catalog.mjs", "scripts/bootstrap.mjs", "skills-lock.json"];
|
|
21
|
+
export const SKIP = /(^|\/)(scripts\/bin|__pycache__|node_modules|\.context-band)(\/|$)|\.pyc$/;
|
|
22
|
+
export const PROTECTED = /^(CLAUDE\.md|\.claude\/settings\.local\.json|\.claude\/agent-memory\/.*)$/;
|
|
23
|
+
export const GITIGNORE = [".claude/worktrees/", ".claude/handoffs/", ".claude/.context-band", ".claude/.stop-verify-ran", ".claude/settings.local.json",
|
|
24
|
+
".claude/agent-memory-local/", "graphify-out/", ".claude/skills/impeccable/scripts/bin/", "__pycache__/", "*.pyc"];
|
|
25
|
+
export const MANIFEST = ".claude/config-manifest.json";
|
|
26
|
+
export const SOURCE_FILE = ".claude/config-source.json";
|
|
27
|
+
export const DEFAULT_SRC = fileURLToPath(new URL("..", import.meta.url));
|
|
28
|
+
|
|
29
|
+
const sha = (p) => createHash("sha256").update(readFileSync(p)).digest("hex");
|
|
30
|
+
const readJson = (p) => { try { return JSON.parse(readFileSync(p, "utf8")); } catch { return null; } };
|
|
31
|
+
function* walk(p) { if (statSync(p).isDirectory()) { for (const n of readdirSync(p)) yield* walk(join(p, n)); } else yield p; }
|
|
32
|
+
|
|
33
|
+
// Name and version of the config at `src`: package.json first, VERSION as fallback.
|
|
34
|
+
export function readPackage(src = DEFAULT_SRC) {
|
|
35
|
+
const pkg = readJson(join(src, "package.json")) || {};
|
|
36
|
+
const versionFile = join(src, "VERSION");
|
|
37
|
+
const version = pkg.version || (existsSync(versionFile) ? readFileSync(versionFile, "utf8").trim() : "unknown");
|
|
38
|
+
return { name: pkg.name || "agents-config", version };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Every file the config installs, keyed by its path relative to the config root (forward slashes).
|
|
42
|
+
export function configFiles(src = DEFAULT_SRC) {
|
|
43
|
+
const files = new Map();
|
|
44
|
+
for (const entry of SYNC) {
|
|
45
|
+
const abs = join(src, entry);
|
|
46
|
+
if (!existsSync(abs)) continue;
|
|
47
|
+
for (const f of walk(abs)) {
|
|
48
|
+
const rel = relative(src, f).split(sep).join("/");
|
|
49
|
+
if (!SKIP.test(rel)) files.set(rel, f);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return files;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function removeEmptyParents(target, rel) {
|
|
56
|
+
let dir = dirname(join(target, rel));
|
|
57
|
+
const root = resolve(target);
|
|
58
|
+
while (resolve(dir) !== root && existsSync(dir) && readdirSync(dir).length === 0) {
|
|
59
|
+
rmdirSync(dir);
|
|
60
|
+
dir = dirname(dir);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// mode: "init" (copy what is missing), "update" (also refresh untouched files and drop obsolete ones), "check" (report only).
|
|
65
|
+
export function install({ src = DEFAULT_SRC, target, mode = "init", force = false, dryRun = false }) {
|
|
66
|
+
if (!["init", "update", "check"].includes(mode)) throw new Error(`unknown mode: ${mode}`);
|
|
67
|
+
if (!target || !existsSync(target) || !statSync(target).isDirectory()) throw new Error(`target is not a directory: ${target}`);
|
|
68
|
+
if (resolve(target) === resolve(src)) throw new Error("target is the config repo itself; pass a project directory");
|
|
69
|
+
|
|
70
|
+
const write = mode !== "check" && !dryRun;
|
|
71
|
+
const pkg = readPackage(src);
|
|
72
|
+
const files = configFiles(src);
|
|
73
|
+
const previous = readJson(join(target, MANIFEST));
|
|
74
|
+
const installed = previous?.files ?? null; // hashes of what the config wrote last time
|
|
75
|
+
const next = {};
|
|
76
|
+
const r = { pkg, mode, dryRun, force, hadManifest: Boolean(installed), same: 0, added: [], updated: [], kept: [], removed: [], obsoleteKept: [], missing: [], outdated: [], edited: [], obsolete: [], written: [] };
|
|
77
|
+
|
|
78
|
+
for (const [rel, abs] of files) {
|
|
79
|
+
const want = sha(abs);
|
|
80
|
+
const dst = join(target, rel);
|
|
81
|
+
if (!existsSync(dst)) {
|
|
82
|
+
if (mode === "check") { r.missing.push(rel); continue; }
|
|
83
|
+
if (write) { mkdirSync(dirname(dst), { recursive: true }); copyFileSync(abs, dst); }
|
|
84
|
+
r.added.push(rel); next[rel] = want;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const have = sha(dst);
|
|
88
|
+
if (have === want) { r.same++; next[rel] = want; continue; }
|
|
89
|
+
const untouched = installed?.[rel] === have;
|
|
90
|
+
if (mode === "check") { (untouched ? r.outdated : r.edited).push(rel); continue; }
|
|
91
|
+
if (mode === "update" && (untouched || force) && !PROTECTED.test(rel)) {
|
|
92
|
+
if (write) copyFileSync(abs, dst);
|
|
93
|
+
r.updated.push(rel); next[rel] = want;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
r.kept.push(rel);
|
|
97
|
+
if (installed?.[rel]) next[rel] = installed[rel];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const [rel, hash] of Object.entries(installed ?? {})) {
|
|
101
|
+
if (files.has(rel)) continue;
|
|
102
|
+
const dst = join(target, rel);
|
|
103
|
+
if (!existsSync(dst)) continue;
|
|
104
|
+
const untouched = sha(dst) === hash;
|
|
105
|
+
if (mode === "check") { r.obsolete.push(rel); continue; }
|
|
106
|
+
if (mode === "update" && untouched && !PROTECTED.test(rel)) {
|
|
107
|
+
if (write) { rmSync(dst); removeEmptyParents(target, rel); }
|
|
108
|
+
r.removed.push(rel);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (mode === "update") r.obsoleteKept.push(rel);
|
|
112
|
+
next[rel] = hash; // keep tracking it so a later update can still remove it
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (mode !== "check") {
|
|
116
|
+
const isClone = existsSync(join(src, ".git"));
|
|
117
|
+
const sourceInfo = { package: pkg.name, version: pkg.version, ...(isClone ? { source: resolve(src) } : {}), syncedAt: new Date().toISOString() };
|
|
118
|
+
const manifest = { package: pkg.name, version: pkg.version, files: Object.fromEntries(Object.entries(next).sort(([a], [b]) => a.localeCompare(b))) };
|
|
119
|
+
if (write) {
|
|
120
|
+
mkdirSync(join(target, ".claude", "agent-memory"), { recursive: true });
|
|
121
|
+
writeFileSync(join(target, SOURCE_FILE), JSON.stringify(sourceInfo, null, 2) + "\n");
|
|
122
|
+
writeFileSync(join(target, MANIFEST), JSON.stringify(manifest, null, 2) + "\n");
|
|
123
|
+
}
|
|
124
|
+
r.written.push(`${SOURCE_FILE} (${pkg.name} ${pkg.version}${isClone ? `, source ${resolve(src)}` : ""})`, `${MANIFEST} (${Object.keys(next).length} files)`);
|
|
125
|
+
const claude = join(target, "CLAUDE.md");
|
|
126
|
+
if (!existsSync(claude)) {
|
|
127
|
+
if (write) copyFileSync(join(src, "templates", "CLAUDE.project.md"), claude);
|
|
128
|
+
r.written.push("CLAUDE.md (from templates/CLAUDE.project.md: fill in purpose and commands)");
|
|
129
|
+
}
|
|
130
|
+
const gi = join(target, ".gitignore");
|
|
131
|
+
const have = existsSync(gi) ? readFileSync(gi, "utf8").split(/\r?\n/) : [];
|
|
132
|
+
const add = GITIGNORE.filter((l) => !have.includes(l));
|
|
133
|
+
if (add.length) {
|
|
134
|
+
if (write) appendFileSync(gi, (have.length && have.at(-1) !== "" ? "\n" : "") + add.join("\n") + "\n");
|
|
135
|
+
r.written.push(`.gitignore (+${add.length} lines)`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return r;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function drift(r) { return r.missing.length + r.outdated.length + r.edited.length + r.obsolete.length; }
|
|
142
|
+
|
|
143
|
+
export function report(r, log = console.log) {
|
|
144
|
+
const head = `${r.pkg.name} ${r.pkg.version} - ${r.mode}${r.force ? " --force" : ""}${r.dryRun ? " (dry run: nothing written)" : ""}`;
|
|
145
|
+
log(head);
|
|
146
|
+
const list = (label, items, note = "") => { for (const i of items) log(` ${label.padEnd(8)} ${i}${note}`); };
|
|
147
|
+
if (r.mode === "check") {
|
|
148
|
+
log(`${r.same} identical, ${r.missing.length} missing, ${r.outdated.length} outdated, ${r.edited.length} edited here, ${r.obsolete.length} obsolete`);
|
|
149
|
+
list("missing", r.missing); list("outdated", r.outdated); list("edited", r.edited); list("obsolete", r.obsolete);
|
|
150
|
+
if (drift(r)) log("run `update` to apply; `update --force` also overwrites the files edited here");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
log(`${r.added.length} added, ${r.updated.length} updated, ${r.removed.length} removed, ${r.kept.length + r.obsoleteKept.length} kept, ${r.same} unchanged`);
|
|
154
|
+
list("added", r.added); list("updated", r.updated); list("removed", r.removed);
|
|
155
|
+
list("kept", r.kept, r.mode === "init" ? " (differs; init never overwrites)" : " (edited here)");
|
|
156
|
+
list("kept", r.obsoleteKept, " (left the config, but edited here)");
|
|
157
|
+
if (r.written.length) { log("written:"); for (const w of r.written) log(` ${w}`); }
|
|
158
|
+
if (r.mode === "update" && !r.hadManifest && r.kept.length) log("no manifest from a previous install, so differing files count as edited; review them and run `update --force` once to adopt the config versions");
|
|
159
|
+
else if (r.kept.length && r.mode === "update") log("`update --force` overwrites the files kept above (protected files excepted)");
|
|
160
|
+
else if (r.kept.length) log("run `update` to refresh differing files");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Legacy CLI (scripts/bootstrap.mjs <target> [--check|--force] | --sync).
|
|
164
|
+
function legacy(argv) {
|
|
165
|
+
let [target, ...flags] = argv;
|
|
166
|
+
let src = DEFAULT_SRC;
|
|
167
|
+
if (target === "--sync" || flags.includes("--sync")) {
|
|
168
|
+
const info = readJson(join(process.cwd(), SOURCE_FILE));
|
|
169
|
+
if (!info) { console.error(`--sync needs ${SOURCE_FILE} (written by a previous install)`); return 2; }
|
|
170
|
+
if (!info.source || !existsSync(info.source)) {
|
|
171
|
+
console.log(`This project was installed from the ${info.package || "config"} package. Update it with: npx ${info.package || "<package>"}@latest update`);
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
src = info.source; target = process.cwd();
|
|
175
|
+
if (existsSync(join(src, ".git"))) { const g = spawnSync("git", ["-C", src, "pull", "--ff-only"], { encoding: "utf8" }); console.log((g.stdout || g.stderr || "").trim()); }
|
|
176
|
+
flags = ["--update", ...flags.filter((f) => f !== "--sync")];
|
|
177
|
+
}
|
|
178
|
+
if (!target) { console.error("usage: node scripts/bootstrap.mjs <target-project> [--check|--force] | --sync"); return 2; }
|
|
179
|
+
const mode = flags.includes("--check") ? "check" : flags.includes("--force") || flags.includes("--update") ? "update" : "init";
|
|
180
|
+
const r = install({ src, target, mode, force: flags.includes("--force"), dryRun: flags.includes("--dry-run") });
|
|
181
|
+
report(r);
|
|
182
|
+
return mode === "check" && drift(r) ? 1 : 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const isMain = (() => { try { return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } })();
|
|
186
|
+
if (isMain) {
|
|
187
|
+
try { process.exitCode = legacy(process.argv.slice(2)); } catch (e) { console.error(e.message); process.exitCode = 2; }
|
|
188
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Drift checks: skills on disk vs docs/skills.md vs frontmatter vs skills-lock.json vs agents' skills: vs settings hooks.
|
|
3
|
+
// Exit 1 on any error. Warnings do not fail.
|
|
4
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
5
|
+
const errors = [], warnings = [];
|
|
6
|
+
const read = (p) => readFileSync(p, "utf8");
|
|
7
|
+
const fm = (p) => read(p).split("---")[1] ?? "";
|
|
8
|
+
|
|
9
|
+
const skills = readdirSync(".claude/skills").filter((d) => existsSync(`.claude/skills/${d}/SKILL.md`)).sort();
|
|
10
|
+
const catalog = read("docs/skills.md");
|
|
11
|
+
const rows = new Map([...catalog.matchAll(/^\| ([a-z0-9-]+) \| (auto|manual) \|/gm)].map((m) => [m[1], m[2]]));
|
|
12
|
+
const lockFile = JSON.parse(read("skills-lock.json"));
|
|
13
|
+
const lock = lockFile.skills, own = new Set(lockFile.own ?? []);
|
|
14
|
+
|
|
15
|
+
for (const s of skills) {
|
|
16
|
+
const f = fm(`.claude/skills/${s}/SKILL.md`);
|
|
17
|
+
const name = /^name:\s*(\S+)/m.exec(f)?.[1];
|
|
18
|
+
if (name !== s) errors.push(`${s}: frontmatter name is "${name}"`);
|
|
19
|
+
const manual = /^disable-model-invocation:\s*true/m.test(f);
|
|
20
|
+
if (!rows.has(s)) errors.push(`${s}: no row in docs/skills.md`);
|
|
21
|
+
else if (rows.get(s) !== (manual ? "manual" : "auto")) errors.push(`${s}: catalog says ${rows.get(s)}, frontmatter says ${manual ? "manual" : "auto"}`);
|
|
22
|
+
if (!existsSync(`.claude/skills/${s}/agents/openai.yaml`)) warnings.push(`${s}: no agents/openai.yaml (Codex metadata)`);
|
|
23
|
+
if (!lock[s] && !own.has(s)) warnings.push(`${s}: neither in skills-lock.json nor in its "own" list`);
|
|
24
|
+
}
|
|
25
|
+
for (const r of rows.keys()) if (!skills.includes(r)) errors.push(`docs/skills.md row "${r}" has no .claude/skills/${r}/SKILL.md`);
|
|
26
|
+
for (const [n, e] of Object.entries(lock)) {
|
|
27
|
+
if (!skills.includes(n)) errors.push(`skills-lock.json entry "${n}" has no skill folder`);
|
|
28
|
+
if (e.sourceType === "github" && !e.sha256) warnings.push(`${n}: lock has no sha256 (run scripts/skills-update.mjs --lock)`);
|
|
29
|
+
}
|
|
30
|
+
for (const a of readdirSync(".claude/agents").filter((f) => f.endsWith(".md"))) {
|
|
31
|
+
const f = fm(`.claude/agents/${a}`);
|
|
32
|
+
const block = /^skills:\n((?:\s+-\s+\S+\n)+)/m.exec(f)?.[1] ?? "";
|
|
33
|
+
for (const s of [...block.matchAll(/-\s+(\S+)/g)].map((m) => m[1])) if (!skills.includes(s)) errors.push(`agent ${a}: preloads unknown skill "${s}"`);
|
|
34
|
+
}
|
|
35
|
+
const settings = JSON.parse(read(".claude/settings.json"));
|
|
36
|
+
for (const list of Object.values(settings.hooks ?? {})) for (const e of list) for (const h of e.hooks ?? []) {
|
|
37
|
+
const m = /\$CLAUDE_PROJECT_DIR\/(\.claude\/hooks\/[^" ]+)/.exec(h.command ?? "");
|
|
38
|
+
if (m && !existsSync(m[1])) errors.push(`settings.json: hook file ${m[1]} does not exist`);
|
|
39
|
+
}
|
|
40
|
+
for (const w of warnings) console.log(`warn ${w}`);
|
|
41
|
+
for (const e of errors) console.log(`ERROR ${e}`);
|
|
42
|
+
console.log(`${skills.length} skills, ${rows.size} catalog rows, ${Object.keys(lock).length} lock entries: ${errors.length} error(s), ${warnings.length} warning(s)`);
|
|
43
|
+
process.exit(errors.length ? 1 : 0);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Compare vendored skills with their upstream and say what to do.
|
|
3
|
+
// node scripts/skills-update.mjs report only
|
|
4
|
+
// node scripts/skills-update.mjs --lock also record the upstream sha256 and commit in skills-lock.json
|
|
5
|
+
// Needs Node 18+ (global fetch). No dependencies.
|
|
6
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
|
|
9
|
+
const LOCK = "skills-lock.json";
|
|
10
|
+
const lock = JSON.parse(readFileSync(LOCK, "utf8"));
|
|
11
|
+
const writeLock = process.argv.includes("--lock");
|
|
12
|
+
const sha = (s) => createHash("sha256").update(s).digest("hex");
|
|
13
|
+
const headers = (url) => ({
|
|
14
|
+
"User-Agent": "skills-update",
|
|
15
|
+
// the token only helps api.github.com rate limits; raw.githubusercontent.com rejects it
|
|
16
|
+
...(process.env.GITHUB_TOKEN && url.startsWith("https://api.github.com/") ? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } : {}),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
async function text(url) {
|
|
20
|
+
try { const r = await fetch(url, { headers: headers(url) }); return r.ok ? await r.text() : null; } catch { return null; }
|
|
21
|
+
}
|
|
22
|
+
async function latestCommit(src, path) {
|
|
23
|
+
const j = await text(`https://api.github.com/repos/${src}/commits?path=${encodeURIComponent(path)}&per_page=1`);
|
|
24
|
+
try { return JSON.parse(j)[0]?.sha?.slice(0, 7) ?? null; } catch { return null; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const rows = [];
|
|
28
|
+
for (const [name, e] of Object.entries(lock.skills)) {
|
|
29
|
+
const localFile = `.claude/skills/${name}/SKILL.md`;
|
|
30
|
+
const local = existsSync(localFile) ? sha(readFileSync(localFile, "utf8").replace(/\r\n/g, "\n")) : null;
|
|
31
|
+
if (e.sourceType !== "github" || !e.skillPath) {
|
|
32
|
+
rows.push([name, local ? "manual source" : "missing locally", e.installedWith ?? e.source ?? ""]);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const remoteText = await text(`https://raw.githubusercontent.com/${e.source}/main/${e.skillPath}`);
|
|
36
|
+
const remote = remoteText ? sha(remoteText.replace(/\r\n/g, "\n")) : null;
|
|
37
|
+
const commit = await latestCommit(e.source, e.skillPath);
|
|
38
|
+
let status, hint = commit ? `upstream ${commit}` : "";
|
|
39
|
+
if (!remote) status = "unreachable";
|
|
40
|
+
else if (!local) { status = "missing locally"; hint = `npx skills add ${e.source} -a claude-code -s ${name} -y --copy`; }
|
|
41
|
+
else if (remote === local) status = "up to date";
|
|
42
|
+
else if (remote === e.sha256) status = e.adapted ? "adapted (upstream unchanged)" : "LOCAL EDITS: mark adapted in the lock, or restore";
|
|
43
|
+
else if (e.adapted) { status = "UPSTREAM CHANGED (adapted: merge by hand)"; hint = `https://github.com/${e.source}/commits/main/${e.skillPath}`; }
|
|
44
|
+
else { status = "UPSTREAM CHANGED"; hint = `npx skills add ${e.source} -a claude-code -s ${name} -y --copy`; }
|
|
45
|
+
if (writeLock && remote) { e.sha256 = remote; delete e.sha256Note; if (commit) e.sourceCommit = commit; }
|
|
46
|
+
rows.push([name, status, hint]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const w = [Math.max(...rows.map((r) => r[0].length)), Math.max(...rows.map((r) => r[1].length))];
|
|
50
|
+
for (const [n, s, h] of rows) console.log(`${n.padEnd(w[0])} ${s.padEnd(w[1])} ${h}`);
|
|
51
|
+
if (writeLock) { writeFileSync(LOCK, JSON.stringify(lock, null, 2) + "\n"); console.log(`\n${LOCK} updated`); }
|
package/skills-lock.json
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"own": [
|
|
4
|
+
"orchestrate",
|
|
5
|
+
"brief",
|
|
6
|
+
"review",
|
|
7
|
+
"project-docs",
|
|
8
|
+
"arch-api",
|
|
9
|
+
"arch-web",
|
|
10
|
+
"arch-app",
|
|
11
|
+
"arch-db",
|
|
12
|
+
"triage"
|
|
13
|
+
],
|
|
14
|
+
"skills": {
|
|
15
|
+
"animate": {
|
|
16
|
+
"source": "emilkowalski/skills",
|
|
17
|
+
"sourceType": "github",
|
|
18
|
+
"skillPath": "skills/animate/SKILL.md",
|
|
19
|
+
"computedHash": "7598d33e7f60dd5c24531eaaa897621cc3bdb48e8050324211627973bc59c4ce",
|
|
20
|
+
"sha256": "87889357e7bc8427a31ec45d6637ee945ce7227b7417358a2ffd5ae724631064",
|
|
21
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
22
|
+
"adapted": true,
|
|
23
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
24
|
+
},
|
|
25
|
+
"animate-expo": {
|
|
26
|
+
"source": "emilkowalski/skills",
|
|
27
|
+
"sourceType": "github",
|
|
28
|
+
"skillPath": "skills/animate-expo/SKILL.md",
|
|
29
|
+
"computedHash": "5de09593d564091f9db60aabede7bed760251e118548272050a247c653c417d2",
|
|
30
|
+
"sha256": "36086a5c9493a888076ff45593748b2940e76cdf6939fd60d623a2e3e57d0e1c",
|
|
31
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
32
|
+
"adapted": true,
|
|
33
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
34
|
+
},
|
|
35
|
+
"animation-performance": {
|
|
36
|
+
"source": "emilkowalski/skills",
|
|
37
|
+
"sourceType": "github",
|
|
38
|
+
"skillPath": "skills/animation-performance/SKILL.md",
|
|
39
|
+
"computedHash": "b68ba704106e27b1f83df0cb817e09ec947abb76825d86eabdee2954b6c1bb84",
|
|
40
|
+
"sha256": "c16c9ea0e2fb753e47cdb376b068f89b89ca1058a8330c545501dbd35e63fae7",
|
|
41
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
42
|
+
"adapted": true,
|
|
43
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
44
|
+
},
|
|
45
|
+
"apple-design": {
|
|
46
|
+
"source": "emilkowalski/skills",
|
|
47
|
+
"sourceType": "github",
|
|
48
|
+
"skillPath": "skills/apple-design/SKILL.md",
|
|
49
|
+
"computedHash": "0190417d092a0df447b000154e39733ea6d97efad6d3bec8a6ce3845aeb88914",
|
|
50
|
+
"sha256": "62dfdafaf5c56c67a96f7505c22fde7284e772fec9d564c1c7fc43b1fc40258e",
|
|
51
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
52
|
+
"adapted": true,
|
|
53
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
54
|
+
},
|
|
55
|
+
"break-ui": {
|
|
56
|
+
"source": "emilkowalski/skills",
|
|
57
|
+
"sourceType": "github",
|
|
58
|
+
"skillPath": "skills/break-ui/SKILL.md",
|
|
59
|
+
"computedHash": "60ada67662925f4df5e3c6ff41cac3ab241b66f8898100a5ffcd7ba7196cb868",
|
|
60
|
+
"sha256": "c5e2bdc98a0e261569219b942a54d207ad19d29e1417476ec4fedd4c3d658ee2",
|
|
61
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
62
|
+
"adapted": true,
|
|
63
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
64
|
+
},
|
|
65
|
+
"diagnosing-bugs": {
|
|
66
|
+
"source": "mattpocock/skills",
|
|
67
|
+
"sourceType": "github",
|
|
68
|
+
"sourceCommit": "49dd158",
|
|
69
|
+
"skillPath": "skills/engineering/diagnosing-bugs/SKILL.md",
|
|
70
|
+
"sha256": "849198df88cdb65fd0d97236604c1fca7ff2f22d2f705f9724a800d0266b118d"
|
|
71
|
+
},
|
|
72
|
+
"emil-design-eng": {
|
|
73
|
+
"source": "emilkowalski/skills",
|
|
74
|
+
"sourceType": "github",
|
|
75
|
+
"skillPath": "skills/emil-design-eng/SKILL.md",
|
|
76
|
+
"computedHash": "51f2537e04d15911b41d78e2de24c36a0e26d41beae15e82a954fe5496a5eda9",
|
|
77
|
+
"sha256": "b54101b99461deeae06a1782310b232519c025f2083e53652980f139880039fa",
|
|
78
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
79
|
+
"adapted": true,
|
|
80
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
81
|
+
},
|
|
82
|
+
"find-animation-opportunities": {
|
|
83
|
+
"source": "emilkowalski/skills",
|
|
84
|
+
"sourceType": "github",
|
|
85
|
+
"skillPath": "skills/find-animation-opportunities/SKILL.md",
|
|
86
|
+
"computedHash": "465d087c41768e4f14ed640dd049036009f613feb55baaa5831b68b33178f9d2",
|
|
87
|
+
"sha256": "fb7bdc5112e2a01aacbd3c89d372b5b50090746020a0e6d542affd80b3622cd5",
|
|
88
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
89
|
+
"adapted": true,
|
|
90
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
91
|
+
},
|
|
92
|
+
"graphify": {
|
|
93
|
+
"source": "graphifyy",
|
|
94
|
+
"sourceType": "pypi",
|
|
95
|
+
"installedWith": "pip install graphifyy",
|
|
96
|
+
"version": "0.9.92"
|
|
97
|
+
},
|
|
98
|
+
"grill-me": {
|
|
99
|
+
"source": "mattpocock/skills",
|
|
100
|
+
"sourceType": "github",
|
|
101
|
+
"sourceCommit": "49dd158",
|
|
102
|
+
"skillPath": "skills/productivity/grill-me/SKILL.md",
|
|
103
|
+
"sha256": "caaf8b8de1684f96e26b28f3c29189db5c89cce4b73e1c93d86164f66ef88637"
|
|
104
|
+
},
|
|
105
|
+
"grill-with-docs": {
|
|
106
|
+
"source": "mattpocock/skills",
|
|
107
|
+
"sourceType": "github",
|
|
108
|
+
"sourceCommit": "49dd158",
|
|
109
|
+
"skillPath": "skills/engineering/grill-with-docs/SKILL.md",
|
|
110
|
+
"note": "adapted: upstream calls grilling + domain-modeling; local version inlines glossary/ADR rules and adds docs/plans read-first, graphify and the decisions block for the orchestrator",
|
|
111
|
+
"adapted": true,
|
|
112
|
+
"sha256": "4a6d8bb82e01431ecee9a13b06ccfc4b911f6ee2efcf09bc6686a8e4cee58f72",
|
|
113
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
|
|
114
|
+
},
|
|
115
|
+
"grilling": {
|
|
116
|
+
"source": "mattpocock/skills",
|
|
117
|
+
"sourceType": "github",
|
|
118
|
+
"sourceCommit": "49dd158",
|
|
119
|
+
"skillPath": "skills/productivity/grilling/SKILL.md",
|
|
120
|
+
"sha256": "befdff1e27a1dfe2a294d5871169ac1afe16d983911daa4f32627514a48c1e15"
|
|
121
|
+
},
|
|
122
|
+
"handoff": {
|
|
123
|
+
"source": "mattpocock/skills",
|
|
124
|
+
"sourceType": "github",
|
|
125
|
+
"sourceCommit": "49dd158",
|
|
126
|
+
"skillPath": "skills/productivity/handoff/SKILL.md",
|
|
127
|
+
"sha256": "<upstream; run scripts/skills-update.mjs --lock>",
|
|
128
|
+
"adapted": true,
|
|
129
|
+
"adaptedNote": "saves to .claude/handoffs/ inside the worktree instead of the OS temp dir (orchestrator-guard and durability); opens with worktree, branch, base ref, plan and frontier"
|
|
130
|
+
},
|
|
131
|
+
"impeccable": {
|
|
132
|
+
"source": "pbakaus/impeccable",
|
|
133
|
+
"sourceType": "github",
|
|
134
|
+
"installedWith": "npx impeccable install",
|
|
135
|
+
"version": "0.1.15 (scripts) / 4.6.0 (skill)",
|
|
136
|
+
"sha256": "9665ab04249cc7fe889ddf3a6dc92023de1edc5edd949e2710424b51febdf84a",
|
|
137
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
138
|
+
"adapted": true,
|
|
139
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
140
|
+
},
|
|
141
|
+
"improve-animations": {
|
|
142
|
+
"source": "emilkowalski/skills",
|
|
143
|
+
"sourceType": "github",
|
|
144
|
+
"skillPath": "skills/improve-animations/SKILL.md",
|
|
145
|
+
"computedHash": "524ea241e41d58bbdd8e288700fe24f5725e2a2f3ae7186ad7cebf9055058356",
|
|
146
|
+
"sha256": "52850830943147b1df7c02be596d8871b3540a7d9519f11157433940a6c6da79",
|
|
147
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
148
|
+
"adapted": true,
|
|
149
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
150
|
+
},
|
|
151
|
+
"mobile-native": {
|
|
152
|
+
"source": "emilkowalski/skills",
|
|
153
|
+
"sourceType": "github",
|
|
154
|
+
"skillPath": "skills/mobile-native/SKILL.md",
|
|
155
|
+
"computedHash": "f221cea36642168df6d3d6d7f236237cbf1ae669138ff7df07775674223d49ad",
|
|
156
|
+
"sha256": "888b7651d66d66dbac4e72b7c554638eb19bd971d686d6cbdf030a5ef3788f55",
|
|
157
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
|
|
158
|
+
},
|
|
159
|
+
"pick-ui-library": {
|
|
160
|
+
"source": "emilkowalski/skills",
|
|
161
|
+
"sourceType": "github",
|
|
162
|
+
"skillPath": "skills/pick-ui-library/SKILL.md",
|
|
163
|
+
"computedHash": "5d2a77bf0ecafbda85aa95fb49999b6d77945d9066ec83d970b62e5b388cd686",
|
|
164
|
+
"sha256": "675fdce308683256ed617351a9b74d23457a5fbd0a562d9831b9c764b8c5e682",
|
|
165
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
166
|
+
"adapted": true,
|
|
167
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
168
|
+
},
|
|
169
|
+
"ponytail": {
|
|
170
|
+
"source": "DietrichGebert/ponytail",
|
|
171
|
+
"sourceType": "github",
|
|
172
|
+
"skillPath": "skills/ponytail/SKILL.md",
|
|
173
|
+
"computedHash": "061f887d9e3e735f85db3be3655a8936a00f24d5fb65ac4ab74a968a770fe342",
|
|
174
|
+
"sha256": "9badd22a32e19cb884e46dfa8d3aae82bb81dfa5484105b8b4f0262df823a509",
|
|
175
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
|
|
176
|
+
},
|
|
177
|
+
"ponytail-audit": {
|
|
178
|
+
"source": "DietrichGebert/ponytail",
|
|
179
|
+
"sourceType": "github",
|
|
180
|
+
"skillPath": "skills/ponytail-audit/SKILL.md",
|
|
181
|
+
"computedHash": "1d718f893dabc01caad0dacef86444b5b4b3e1e59409527d66e8b5dd0cd85ae0",
|
|
182
|
+
"sha256": "2b3223a02c386d1263e1b08343cb8eb3a53e444cdafb1d79e26c8ec2a8fcad28",
|
|
183
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
|
|
184
|
+
},
|
|
185
|
+
"ponytail-debt": {
|
|
186
|
+
"source": "DietrichGebert/ponytail",
|
|
187
|
+
"sourceType": "github",
|
|
188
|
+
"skillPath": "skills/ponytail-debt/SKILL.md",
|
|
189
|
+
"computedHash": "f5d1d2ab891ff0a650a90b67235e487828e7d2a189de08a1ae073032de379407",
|
|
190
|
+
"sha256": "b5ec2762f6ba8c4af9ea7173aa6c9f91b88655a25e43f9de0264f6ce8722b25f",
|
|
191
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
|
|
192
|
+
},
|
|
193
|
+
"ponytail-review": {
|
|
194
|
+
"source": "DietrichGebert/ponytail",
|
|
195
|
+
"sourceType": "github",
|
|
196
|
+
"skillPath": "skills/ponytail-review/SKILL.md",
|
|
197
|
+
"computedHash": "800dc0c86402978e12359f701b9e0c81ba4607a0cd0027f4596d0f835a67eadc",
|
|
198
|
+
"sha256": "33fe4ebe22a460924e5d4a261e223df22e409cc94ab76182bee9fb91a3ef022e",
|
|
199
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
|
|
200
|
+
},
|
|
201
|
+
"postgres-best-practices": {
|
|
202
|
+
"source": "neondatabase/postgres-skills",
|
|
203
|
+
"sourceType": "github",
|
|
204
|
+
"skillPath": "skills/postgres-best-practices/SKILL.md",
|
|
205
|
+
"computedHash": "f0e9670a035895d50945ca10ed4466513df2c486414c6fcebd3b4e38cc98a88c",
|
|
206
|
+
"sha256": "ade0096e963f1b7c3ec4c209318df50a8a891f3335c1dd05eca4b3f84d3e192f",
|
|
207
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
|
|
208
|
+
},
|
|
209
|
+
"prototype": {
|
|
210
|
+
"source": "emilkowalski/skills",
|
|
211
|
+
"sourceType": "github",
|
|
212
|
+
"skillPath": "skills/prototype/SKILL.md",
|
|
213
|
+
"computedHash": "77be567d8c946608fdd15e61b62ab383cdf289a194dce2479828b7eda860d3ba",
|
|
214
|
+
"sha256": "bba39c955eb1871c5a02733976ceec5d0324198e0812e667604756489c89f7b9",
|
|
215
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
216
|
+
"adapted": true,
|
|
217
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
218
|
+
},
|
|
219
|
+
"retro": {
|
|
220
|
+
"source": "mattpocock/skills",
|
|
221
|
+
"sourceType": "github",
|
|
222
|
+
"sourceCommit": "49dd158",
|
|
223
|
+
"skillPath": "skills/engineering/retro/SKILL.md",
|
|
224
|
+
"sha256": "d39f65cfd1027788ac2ff9e9aa6caa555d9dd2e6e9d3eaea4c28cf493a45cdff",
|
|
225
|
+
"adapted": true,
|
|
226
|
+
"adaptedNote": "frontmatter only: disable-model-invocation removed so the orchestrator can call it after L tasks and verifier blocks"
|
|
227
|
+
},
|
|
228
|
+
"review-animations": {
|
|
229
|
+
"source": "emilkowalski/skills",
|
|
230
|
+
"sourceType": "github",
|
|
231
|
+
"skillPath": "skills/review-animations/SKILL.md",
|
|
232
|
+
"computedHash": "b4e5f0f4fe3e2743c85bf7354108f48a0b9d502cb20ef5c4a9c195da91f93736",
|
|
233
|
+
"sha256": "6ff590d29e436766135aa3d137be1fac2a867165c7257fc315b189361f1873af",
|
|
234
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
235
|
+
"adapted": true,
|
|
236
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
237
|
+
},
|
|
238
|
+
"tdd": {
|
|
239
|
+
"source": "mattpocock/skills",
|
|
240
|
+
"sourceType": "github",
|
|
241
|
+
"sourceCommit": "49dd158",
|
|
242
|
+
"skillPath": "skills/engineering/tdd/SKILL.md",
|
|
243
|
+
"sha256": "5505d25bbaa8fc14a79e4d20163936958992a2995b7f1dd1d6197edc9ed722e0"
|
|
244
|
+
},
|
|
245
|
+
"ui-ux-pro-max": {
|
|
246
|
+
"source": "nextlevelbuilder/ui-ux-pro-max-skill",
|
|
247
|
+
"sourceType": "github",
|
|
248
|
+
"skillPath": ".claude/skills/ui-ux-pro-max/SKILL.md",
|
|
249
|
+
"installedWith": "npx ui-ux-pro-max-cli init --ai claude",
|
|
250
|
+
"note": "skillPath is the repo's dev copy; the CLI generates the installed files from src/ui-ux-pro-max",
|
|
251
|
+
"sha256": "6c0b6c49351f88d579f95a55a37bcda7f00e8213c88b77490a97d9a31fa23498",
|
|
252
|
+
"sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`",
|
|
253
|
+
"adapted": true,
|
|
254
|
+
"adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
|
|
255
|
+
},
|
|
256
|
+
"writing-for-agents": {
|
|
257
|
+
"source": "mattpocock/skills",
|
|
258
|
+
"sourceType": "github",
|
|
259
|
+
"sourceCommit": "49dd158",
|
|
260
|
+
"skillPath": "skills/productivity/writing-for-agents/SKILL.md",
|
|
261
|
+
"sha256": "551adca942227b44192edba88acd4e8db911f0121ce58ad16944ccf6a896a74a"
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"notes": {
|
|
265
|
+
"sha256": "sha256 of the upstream SKILL.md at sourceCommit (or of the local file when sha256Note says so)",
|
|
266
|
+
"adapted": "local SKILL.md differs from upstream on purpose; skills-update.mjs never suggests overwriting it",
|
|
267
|
+
"computedHash": "hash written by skills.sh at install time; not reproducible here"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@AGENTS.md
|
|
2
|
+
|
|
3
|
+
# <Project name>
|
|
4
|
+
|
|
5
|
+
<One sentence: what this project is for the user.>
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
- Install: `<pnpm install>`
|
|
10
|
+
- Dev: `<pnpm dev>`
|
|
11
|
+
- Lint / typecheck / test: `<pnpm lint>` / `<pnpm typecheck>` / `<pnpm test>`
|
|
12
|
+
|
|
13
|
+
## Work size
|
|
14
|
+
|
|
15
|
+
- Orchestrator writes only docs/plans, docs/adr and git integration. Everything else is delegated.
|
|
16
|
+
- S: 1 file, diff fits in 1 sentence -> /quick (opus high, short brief). The orchestrator never edits code.
|
|
17
|
+
- M: 1-2 scopes, paths known -> grill if a decision is open, /product plan with tickets, one implementer per ticket, /verifier.
|
|
18
|
+
- L: 3+ scopes or architecture trigger -> grill, /product, /architect, tickets on the frontier, integrate, /architect again, /verifier, /security on trigger.
|
|
19
|
+
- Full playbook: skill `orchestrate`.
|
|
20
|
+
- Enforced by hook `orchestrator-guard` (main session has no `agent_id` in hook input).
|
|
21
|
+
- Context: hook `context-budget` warns at 60k / 90k / 110k tokens; `autoCompactWindow` compacts at 120k. Phase-boundary tree in skill `orchestrate` section 14.
|
|
22
|
+
|
|
23
|
+
## Where things live
|
|
24
|
+
|
|
25
|
+
- Rules: `.claude/rules/` (loaded by `paths:` glob or always)
|
|
26
|
+
- Agents: `.claude/agents/`
|
|
27
|
+
- Skills: `.claude/skills/` (catalog and wiring: docs/skills.md)
|
|
28
|
+
- Architecture skills: arch-api (NestJS), arch-web (Next.js), arch-app (Expo), arch-db (Postgres/MySQL; loaded by rule db.md)
|
|
29
|
+
- Plans: `docs/plans/` (template in docs/plans/README.md)
|
|
30
|
+
- ADRs: `docs/adr/` (template and numbering in docs/adr/README.md)
|
|
31
|
+
- Brief template: skill `brief` (`docs/brief-template.md` points there)
|
|
32
|
+
- Vendored skills: origins in `skills-lock.json`; check upstream with `node scripts/skills-update.mjs`
|
|
33
|
+
- Decisions about this repo: `docs/adr/`; changes: `CHANGELOG.md`
|
|
34
|
+
|
|
35
|
+
## graphify
|
|
36
|
+
|
|
37
|
+
Skill `graphify` is installed (`.claude/skills/graphify`). Rule `.claude/rules/graphify.md` says when to query it; it applies only when `graphify-out/graph.json` exists. First build in a project: `/graphify .`
|
|
38
|
+
|
|
39
|
+
# Compact instructions
|
|
40
|
+
|
|
41
|
+
When compacting, keep: the task worktree path, branch and base ref; the plan path and every decision, ticket status and open question in it; files changed and commands run with their errors; the next step. Drop file contents, tool output and agent returns already reflected in `docs/plans/<task>.md`. The plan file is re-injected after compaction by the post-compact hook.
|