@punks/cli 1.0.2 → 1.0.4
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/README.md +10 -1
- package/dist/data/catalog/lint.ts +10 -18
- package/dist/data/catalog/packs.ts +2 -2
- package/dist/data/catalog/skills.ts +1 -0
- package/dist/data/scripts/sync-subagents.mjs +163 -120
- package/dist/data/subagents/manifest.mjs +29 -0
- package/dist/index.js +151 -159
- package/dist/skills/agnostic/backend/logging-best-practices/SKILL.md +127 -0
- package/dist/skills/agnostic/backend/logging-best-practices/rules/context.md +157 -0
- package/dist/skills/agnostic/backend/logging-best-practices/rules/pitfalls.md +118 -0
- package/dist/skills/agnostic/backend/logging-best-practices/rules/structure.md +193 -0
- package/dist/skills/agnostic/backend/logging-best-practices/rules/wide-events.md +113 -0
- package/dist/skills/agnostic/cli/dp-cli/SKILL.md +24 -5
- package/dist/skills/agnostic/cli/dp-cli/references/commands.md +2 -2
- package/dist/skills/agnostic/cli/dp-cli/references/post-command-flow.md +2 -0
- package/dist/skills/agnostic/requirements/write-backlog/REFERENCE.md +1 -1
- package/docs/README.md +7 -1
- package/docs/reference/dp-requirements.md +16 -1
- package/docs/runbooks/dp-cli-scaffolding.md +26 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Devpunks CLI
|
|
2
2
|
|
|
3
3
|
`punks` scaffolds the AI operating context for each project phase, from requirements and backlog prep to the repo-aware setup pass.
|
|
4
4
|
This repo carries the executable CLI plus the canonical bundled scaffold baseline under `src/data` and `skills/`.
|
|
@@ -82,6 +82,15 @@ bun run release:publish
|
|
|
82
82
|
|
|
83
83
|
`bun run release:publish` publishes the current `package.json` version to npm, updates the `latest` and `next` dist-tags, and pushes the matching `v<version>` git tag. Commit and push the version bump before running it; the script refuses dirty worktrees and existing tags that point at another commit.
|
|
84
84
|
|
|
85
|
+
Before npm releases, authenticate against the public npm registry:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm login --registry=https://registry.npmjs.org/
|
|
89
|
+
npm whoami
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The logged-in account must have publish access to `@punks/cli`.
|
|
93
|
+
|
|
85
94
|
## Development
|
|
86
95
|
|
|
87
96
|
```bash
|
|
@@ -25,31 +25,24 @@ export interface LintAssetDefinition {
|
|
|
25
25
|
|
|
26
26
|
const sharedReactPlacement = {
|
|
27
27
|
recommendedConfigFile: ".oxlintrc.json",
|
|
28
|
-
recommendedFiles: [
|
|
29
|
-
|
|
30
|
-
"packages/ui/**/*.{js,jsx,ts,tsx}",
|
|
31
|
-
],
|
|
32
|
-
recommendedWorkspaces: ["apps/web", "packages/ui"],
|
|
28
|
+
recommendedFiles: ["<detected-react-workspace>/**/*.{js,jsx,ts,tsx}"],
|
|
29
|
+
recommendedWorkspaces: ["detected React workspaces"],
|
|
33
30
|
placementNotes:
|
|
34
|
-
"Add as an override for React-rendered code. Keep
|
|
31
|
+
"Add as an override for detected React-rendered code. Keep backend packages outside this override unless they render React.",
|
|
35
32
|
} as const satisfies LintPlacementDefinition;
|
|
36
33
|
|
|
37
34
|
const webOnlyPlacement = {
|
|
38
35
|
recommendedConfigFile: ".oxlintrc.json",
|
|
39
|
-
recommendedFiles: ["
|
|
40
|
-
recommendedWorkspaces: ["
|
|
36
|
+
recommendedFiles: ["<detected-nextjs-workspace>/**/*.{js,jsx,ts,tsx}"],
|
|
37
|
+
recommendedWorkspaces: ["detected Next.js workspaces"],
|
|
41
38
|
placementNotes:
|
|
42
39
|
"Place this in the Next.js app override. If the repo uses a different frontend app path, retarget the file globs to that workspace before composing the final Oxlint config.",
|
|
43
40
|
} as const satisfies LintPlacementDefinition;
|
|
44
41
|
|
|
45
42
|
const effectPlacement = {
|
|
46
43
|
recommendedConfigFile: ".oxlintrc.json",
|
|
47
|
-
recommendedFiles: [
|
|
48
|
-
|
|
49
|
-
"packages/api/**/*.{js,jsx,ts,tsx}",
|
|
50
|
-
"packages/db/**/*.{js,jsx,ts,tsx}",
|
|
51
|
-
],
|
|
52
|
-
recommendedWorkspaces: ["apps/server", "packages/api", "packages/db"],
|
|
44
|
+
recommendedFiles: ["<detected-effect-workspace>/**/*.{js,jsx,ts,tsx}"],
|
|
45
|
+
recommendedWorkspaces: ["detected Effect workspaces"],
|
|
53
46
|
placementNotes:
|
|
54
47
|
"Apply this only where Effect code lives. If the target repo renames or splits backend workspaces, move the override with those code paths instead of broadening it repo-wide.",
|
|
55
48
|
} as const satisfies LintPlacementDefinition;
|
|
@@ -57,11 +50,10 @@ const effectPlacement = {
|
|
|
57
50
|
const vitestPlacement = {
|
|
58
51
|
recommendedConfigFile: ".oxlintrc.json",
|
|
59
52
|
recommendedFiles: [
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"packages/api/**/*.{test,spec}.{js,jsx,ts,tsx}",
|
|
53
|
+
"<detected-test-workspace>/**/*.{test,spec}.{js,jsx,ts,tsx}",
|
|
54
|
+
"<detected-test-workspace>/src/test/**/*.{js,jsx,ts,tsx}",
|
|
63
55
|
],
|
|
64
|
-
recommendedWorkspaces: ["
|
|
56
|
+
recommendedWorkspaces: ["detected JavaScript/TypeScript test workspaces"],
|
|
65
57
|
placementNotes:
|
|
66
58
|
"Attach this to test-only globs. Expand or narrow the file patterns to match the repo's actual Vitest test layout instead of treating it as a global default.",
|
|
67
59
|
} as const satisfies LintPlacementDefinition;
|
|
@@ -23,11 +23,11 @@ export interface PackCatalogEntry {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export const packCatalog = [
|
|
26
|
-
{ id: "backend", category: "surface", triggerPackages: [], description: "Backend pack: domain structure
|
|
26
|
+
{ id: "backend", category: "surface", triggerPackages: [], description: "Backend pack: domain structure, recoverable actions, and logging.", skills: ["backend-domain-structure", "backend-recoverable-actions", "logging-best-practices"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared backend domain baseline", "workspace backend action/recovery guidance", "workspace logging/observability guidance"] },
|
|
27
27
|
{ id: "better-auth", category: "detected", triggerPackages: ["better-auth"], description: "Better Auth guidance pack.", skills: ["better-auth-best-practices"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared auth guardrails", "workspace auth boundaries"] },
|
|
28
28
|
{ id: "debug", category: "default", triggerPackages: [], description: "Default debug pack: debug-agent runtime-evidence workflow.", skills: ["debug-agent"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared runtime debugging baseline", "workspace evidence-first debugging workflow"] },
|
|
29
29
|
{ id: "docs", category: "default", triggerPackages: [], description: "Default docs pack: docs-maintenance.", skills: ["docs-maintenance"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "docs-prompt-spec"], promptDetails: ["shared docs baseline", "docs scope spec"] },
|
|
30
|
-
{ id: "drizzle", category: "detected", triggerPackages: ["drizzle-kit", "drizzle-orm"], description: "Drizzle guidance pack.", skills: [
|
|
30
|
+
{ id: "drizzle", category: "detected", triggerPackages: ["drizzle-kit", "drizzle-orm"], description: "Drizzle guidance pack.", skills: [], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared data-layer baseline", "workspace db flow rules"] },
|
|
31
31
|
{ id: "effect", category: "detected", triggerPackages: ["effect", "@effect/"], description: "Effect guidance pack family.", skills: ["effect-authoring", "effect-best-practices", "effect-backend-structure", "effect-recoverable-actions"], lintAssets: ["effect-no-barrel-imports"], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared effect authoring baseline", "workspace service/layer rules"] },
|
|
32
32
|
{ id: "elysia", category: "detected", triggerPackages: ["elysia"], description: "Elysia guidance pack.", skills: ["elysiajs"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared api-server baseline", "workspace route/plugin rules"] },
|
|
33
33
|
{ id: "frontend", category: "surface", triggerPackages: [], description: "Frontend pack: agent-browser, design taste, and frontend domain structure.", skills: ["agent-browser", "design-taste-frontend", "frontend-domain-structure"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared product-ui baseline", "workspace UX/browser guidance", "workspace frontend domain boundaries"] },
|
|
@@ -15,6 +15,7 @@ export const skillCatalog = [
|
|
|
15
15
|
{ id: "agent-browser", sourceDirectory: "skills/agnostic/frontend/agent-browser", tier: "framework", language: null, framework: "browser-automation", requiresTools: ["agent-browser"] },
|
|
16
16
|
{ id: "backend-domain-structure", sourceDirectory: "skills/agnostic/backend/backend-domain-structure", tier: "agnostic", language: null, framework: null, requiresTools: [] },
|
|
17
17
|
{ id: "backend-recoverable-actions", sourceDirectory: "skills/agnostic/backend/backend-recoverable-actions", tier: "agnostic", language: null, framework: null, requiresTools: [] },
|
|
18
|
+
{ id: "logging-best-practices", sourceDirectory: "skills/agnostic/backend/logging-best-practices", tier: "agnostic", language: null, framework: null, requiresTools: [] },
|
|
18
19
|
{ id: "better-auth-best-practices", sourceDirectory: "skills/frameworks/better-auth/better-auth-best-practices", tier: "framework", language: "typescript", framework: "better-auth", requiresTools: [] },
|
|
19
20
|
{ id: "create-plan", sourceDirectory: "skills/agnostic/planning/create-plan", tier: "agnostic", language: null, framework: null, requiresTools: [] },
|
|
20
21
|
{ id: "create-spec", sourceDirectory: "skills/agnostic/planning/create-spec", tier: "agnostic", language: null, framework: null, requiresTools: [] },
|
|
@@ -52,92 +52,131 @@ const cursorManagedComment =
|
|
|
52
52
|
const opencodeManagedComment =
|
|
53
53
|
"<!-- Generated by scripts/sync-subagents.mjs. Edit .agents/subagents/manifest.mjs instead. -->";
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
55
|
+
function buildCodexAgentConfig({ hasFormatHook, hasTestHook }) {
|
|
56
|
+
const lines = [
|
|
57
|
+
"[agents]",
|
|
58
|
+
"max_threads = 6",
|
|
59
|
+
"max_depth = 1",
|
|
60
|
+
"",
|
|
61
|
+
"[features]",
|
|
62
|
+
"codex_hooks = true",
|
|
63
|
+
"",
|
|
64
|
+
"[hooks]",
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
if (hasFormatHook) {
|
|
68
|
+
lines.push(
|
|
69
|
+
"SessionStart = [",
|
|
70
|
+
' { matcher = "startup|resume", hooks = [',
|
|
71
|
+
' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/format-edited-file.mjs\\" session-start", statusMessage = "Capturing edited-file baseline", timeout = 30 },',
|
|
72
|
+
" ] },",
|
|
73
|
+
"]",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (hasTestHook) {
|
|
78
|
+
lines.push(
|
|
79
|
+
"PreToolUse = [",
|
|
80
|
+
' { matcher = "Bash|.*[Pp]ull.?[Rr]equest.*|.*[Pp][Rr].?[Cc]reate.*|.*create[_-]?pull[_-]?request.*", hooks = [',
|
|
81
|
+
' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/require-tests-for-pr.mjs\\" codex", statusMessage = "Checking tests before PR creation", timeout = 600 },',
|
|
82
|
+
" ] },",
|
|
83
|
+
"]",
|
|
84
|
+
);
|
|
85
|
+
}
|
|
81
86
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
87
|
+
if (hasFormatHook) {
|
|
88
|
+
lines.push(
|
|
89
|
+
"PostToolUse = [",
|
|
90
|
+
' { matcher = "Bash|apply_patch|.*apply.?patch.*|edit|write|multiedit", hooks = [',
|
|
91
|
+
' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/format-edited-file.mjs\\" post", statusMessage = "Auto-formatting edited files", timeout = 30 },',
|
|
92
|
+
" ] },",
|
|
93
|
+
"]",
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
lines.push("");
|
|
98
|
+
return lines.join("\n");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function buildClaudeSettingsConfig({ hasFormatHook, hasTestHook }) {
|
|
102
|
+
return {
|
|
103
|
+
hooks: {
|
|
104
|
+
...(hasTestHook
|
|
105
|
+
? {
|
|
106
|
+
PreToolUse: [
|
|
107
|
+
{
|
|
108
|
+
matcher: "mcp__github__create_pull_request",
|
|
109
|
+
hooks: [
|
|
110
|
+
{
|
|
111
|
+
type: "command",
|
|
112
|
+
command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/require-tests-for-pr.mjs claude',
|
|
113
|
+
timeout: 600,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
matcher: "Bash",
|
|
119
|
+
hooks: [
|
|
120
|
+
{
|
|
121
|
+
type: "command",
|
|
122
|
+
command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/require-tests-for-pr.mjs claude',
|
|
123
|
+
timeout: 600,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
}
|
|
129
|
+
: {}),
|
|
130
|
+
...(hasFormatHook
|
|
131
|
+
? {
|
|
132
|
+
PostToolUse: [
|
|
133
|
+
{
|
|
134
|
+
matcher: "Edit|Write|MultiEdit",
|
|
135
|
+
hooks: [
|
|
136
|
+
{
|
|
137
|
+
type: "command",
|
|
138
|
+
command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/format-edited-file.mjs claude',
|
|
139
|
+
timeout: 30,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
}
|
|
145
|
+
: {}),
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function buildCursorHooksConfig({ hasFormatHook, hasTestHook }) {
|
|
151
|
+
return {
|
|
152
|
+
version: 1,
|
|
153
|
+
hooks: {
|
|
154
|
+
...(hasTestHook
|
|
155
|
+
? {
|
|
156
|
+
beforeMCPExecution: [
|
|
157
|
+
{
|
|
158
|
+
command: "node .cursor/hooks/require-tests-for-pr.mjs cursor",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
beforeShellExecution: [
|
|
162
|
+
{
|
|
163
|
+
command: "node .cursor/hooks/require-tests-for-pr.mjs cursor",
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
}
|
|
167
|
+
: {}),
|
|
168
|
+
...(hasFormatHook
|
|
169
|
+
? {
|
|
170
|
+
afterFileEdit: [
|
|
171
|
+
{
|
|
172
|
+
command: "node .cursor/hooks/format-edited-file.mjs cursor",
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
}
|
|
176
|
+
: {}),
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
141
180
|
|
|
142
181
|
function getSkillNames(agent) {
|
|
143
182
|
if (Array.isArray(agent.skills)) {
|
|
@@ -306,6 +345,18 @@ async function ensureSymlink(linkPath, targetPath) {
|
|
|
306
345
|
await symlink(relativeTarget, linkPath);
|
|
307
346
|
}
|
|
308
347
|
|
|
348
|
+
async function pathExists(filePath) {
|
|
349
|
+
try {
|
|
350
|
+
await lstat(filePath);
|
|
351
|
+
return true;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
309
360
|
async function writeManagedFiles(directory, extension, renderedByName) {
|
|
310
361
|
await mkdir(directory, { recursive: true });
|
|
311
362
|
|
|
@@ -340,38 +391,26 @@ async function syncHookSurface() {
|
|
|
340
391
|
await mkdir(cursorHooksDir, { recursive: true });
|
|
341
392
|
await mkdir(opencodePluginsDir, { recursive: true });
|
|
342
393
|
|
|
343
|
-
|
|
344
|
-
path.join(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
await ensureSymlink(
|
|
364
|
-
path.join(cursorHooksDir, "require-tests-for-pr.mjs"),
|
|
365
|
-
path.join(sharedHooksPath, "require-tests-for-pr.mjs"),
|
|
366
|
-
);
|
|
367
|
-
await ensureSymlink(
|
|
368
|
-
path.join(opencodePluginsDir, "format-edited-file.mjs"),
|
|
369
|
-
path.join(sharedHooksPath, "format-edited-file.mjs"),
|
|
370
|
-
);
|
|
371
|
-
await ensureSymlink(
|
|
372
|
-
path.join(opencodePluginsDir, "require-tests-for-pr.mjs"),
|
|
373
|
-
path.join(sharedHooksPath, "require-tests-for-pr.mjs"),
|
|
374
|
-
);
|
|
394
|
+
for (const hookName of ["format-edited-file.mjs", "require-tests-for-pr.mjs"]) {
|
|
395
|
+
const sourcePath = path.join(sharedHooksPath, hookName);
|
|
396
|
+
const targetPaths = [
|
|
397
|
+
path.join(codexHooksDir, hookName),
|
|
398
|
+
path.join(claudeHooksDir, hookName),
|
|
399
|
+
path.join(cursorHooksDir, hookName),
|
|
400
|
+
path.join(opencodePluginsDir, hookName),
|
|
401
|
+
];
|
|
402
|
+
|
|
403
|
+
if (await pathExists(sourcePath)) {
|
|
404
|
+
for (const targetPath of targetPaths) {
|
|
405
|
+
await ensureSymlink(targetPath, sourcePath);
|
|
406
|
+
}
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
for (const targetPath of targetPaths) {
|
|
411
|
+
await rm(targetPath, { force: true, recursive: true });
|
|
412
|
+
}
|
|
413
|
+
}
|
|
375
414
|
}
|
|
376
415
|
|
|
377
416
|
async function syncSkillMirrors() {
|
|
@@ -404,10 +443,14 @@ async function main() {
|
|
|
404
443
|
await mkdir(path.dirname(codexConfigPath), { recursive: true });
|
|
405
444
|
await mkdir(path.dirname(claudeSettingsPath), { recursive: true });
|
|
406
445
|
await mkdir(path.dirname(cursorHooksJsonPath), { recursive: true });
|
|
407
|
-
|
|
446
|
+
const availableHooks = {
|
|
447
|
+
hasFormatHook: await pathExists(path.join(sharedHooksPath, "format-edited-file.mjs")),
|
|
448
|
+
hasTestHook: await pathExists(path.join(sharedHooksPath, "require-tests-for-pr.mjs")),
|
|
449
|
+
};
|
|
450
|
+
await writeFile(codexConfigPath, buildCodexAgentConfig(availableHooks), "utf8");
|
|
408
451
|
await rm(path.join(codexDir, "hooks.json"), { force: true });
|
|
409
|
-
await writeFile(claudeSettingsPath, encodeJson(
|
|
410
|
-
await writeFile(cursorHooksJsonPath, encodeJson(
|
|
452
|
+
await writeFile(claudeSettingsPath, encodeJson(buildClaudeSettingsConfig(availableHooks)), "utf8");
|
|
453
|
+
await writeFile(cursorHooksJsonPath, encodeJson(buildCursorHooksConfig(availableHooks)), "utf8");
|
|
411
454
|
await writeManagedFiles(claudeAgentsDir, "md", claudeFiles);
|
|
412
455
|
await writeManagedFiles(codexAgentsDir, "toml", codexFiles);
|
|
413
456
|
await writeManagedFiles(cursorAgentsDir, "md", cursorFiles);
|
|
@@ -62,6 +62,11 @@ const capabilityPacks = {
|
|
|
62
62
|
"Repo documentation maintenance, routing, and human-facing durable knowledge capture.",
|
|
63
63
|
skills: ["docs-maintenance"],
|
|
64
64
|
},
|
|
65
|
+
"review-core": {
|
|
66
|
+
description:
|
|
67
|
+
"Cross-cutting review, simplification, and architecture-friction analysis for changed code.",
|
|
68
|
+
skills: ["simplify", "improve-codebase-architecture"],
|
|
69
|
+
},
|
|
65
70
|
"python-core": {
|
|
66
71
|
description:
|
|
67
72
|
"Python project structure, code style, design boundaries, and everyday implementation guidance.",
|
|
@@ -102,7 +107,31 @@ const skillActivationInstructions = [
|
|
|
102
107
|
"Do not rely on role name or inherited context alone; scoped AGENTS.md skill routing is part of the task contract.",
|
|
103
108
|
];
|
|
104
109
|
|
|
110
|
+
const reviewActivationInstructions = [
|
|
111
|
+
...skillActivationInstructions,
|
|
112
|
+
"Stay read-only unless the parent explicitly asks for fixes.",
|
|
113
|
+
"Lead with findings, sorted by severity, with precise file/line references.",
|
|
114
|
+
"Use `simplify` to evaluate whether recently changed code can be clearer, smaller, or less stateful.",
|
|
115
|
+
"Use `improve-codebase-architecture` only when the review reveals cross-module coupling, shallow-module sprawl, testability friction, or AI-navigation problems worth surfacing.",
|
|
116
|
+
];
|
|
117
|
+
|
|
105
118
|
const agents = [
|
|
119
|
+
{
|
|
120
|
+
name: "code-review",
|
|
121
|
+
description:
|
|
122
|
+
"Use for cross-cutting code review centered on bugs, regressions, simplification opportunities, architecture friction, and review-ready findings across changed code.",
|
|
123
|
+
ownedPaths: ["**/*"],
|
|
124
|
+
guidanceFiles: ["AGENTS.md"],
|
|
125
|
+
activationInstructions: reviewActivationInstructions,
|
|
126
|
+
packs: ["review-core"],
|
|
127
|
+
skills: ["simplify", "improve-codebase-architecture"],
|
|
128
|
+
boundaries: [
|
|
129
|
+
"Review first: identify concrete defects, behavioral risks, missing tests, and simplification opportunities before summarizing.",
|
|
130
|
+
"Do not edit files unless the parent explicitly assigns implementation after the review.",
|
|
131
|
+
"Keep architecture notes grounded in observed code friction; return candidate refactors or follow-up RFC recommendations instead of speculative rewrites.",
|
|
132
|
+
"If the task asks for feature work rather than review, tell the parent to use the relevant implementation specialist.",
|
|
133
|
+
],
|
|
134
|
+
},
|
|
106
135
|
{
|
|
107
136
|
name: "docs-maintenance",
|
|
108
137
|
description:
|