@punks/cli 1.0.0 → 1.0.2

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 CHANGED
@@ -1,8 +1,8 @@
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
- This repo now carries the canonical scaffold content base under `src/data` plus a local `skills/` copy sourced from the public [wearedevpunks/skills](https://github.com/wearedevpunks/skills) repo.
5
- The CLI runtime stays private; `skills/` is the public, shareable skill surface refreshed through a local shallow-clone cache.
4
+ This repo carries the executable CLI plus the canonical bundled scaffold baseline under `src/data` and `skills/`.
5
+ At runtime, scaffold content resolves from the latest stable GitHub release baseline with bundled fallback; the public [wearedevpunks/skills](https://github.com/wearedevpunks/skills) repo remains only the Vercel skills CLI interface.
6
6
 
7
7
  ## Commands
8
8
 
@@ -27,6 +27,7 @@ punks scaffold setup
27
27
  punks scaffold setup -i /path/to/repo
28
28
  punks scaffold setup -i /path/to/repo -o /path/to/output
29
29
  bun run sync:skills
30
+ bun run baseline:build
30
31
  ```
31
32
 
32
33
  `bun run sync:skills` updates a local cache clone of `wearedevpunks/skills` and then replaces only `skills/`, overwriting any local changes there.
@@ -35,7 +36,21 @@ bun run sync:skills
35
36
 
36
37
  `punks scaffold backlog` does not currently copy any stage-specific packs. It prints the fixed operator prompt for the backlog gate so the lifecycle stays explicit.
37
38
 
38
- `punks scaffold setup` scans the target repo from `cwd` or `-i`, writes scaffold output into the scan root or `-o`, copies the selected skills from the bundled `skills/` catalog, resolves pack-owned lint assets into `.devpunks/specs/lint/`, and ensures required global tool prerequisites for those skills.
39
+ `punks scaffold setup` scans the target repo from `cwd` or `-i`, resolves the active scaffold baseline, writes scaffold output into the scan root or `-o`, copies the selected baseline skills, resolves pack-owned lint assets into `.devpunks/specs/lint/`, and ensures required global tool prerequisites for those skills.
40
+
41
+ Use `--baseline bundled` to force the npm-shipped baseline, or `--refresh-baseline` to refetch the stable remote baseline.
42
+
43
+ Language packs are detected separately from framework packs. TypeScript is selected when scanned manifests depend on `typescript` or when nested source files include `.ts` / `.tsx`; Python is selected from nested `.py` files. Root-level config files and vendor, virtualenv, generated, scaffold, docs, examples, `scripts`, `opensrc`, cache, and build output directories are ignored.
44
+
45
+ The default subagent manifest includes Python templates that combine the language skills into `python-app`, `python-async`, and `python-testing` specialists.
46
+
47
+ To install only the local `dp-cli` operator skill from the public skills repo checkout:
48
+
49
+ ```bash
50
+ npx skills add /Users/stefan/Desktop/repos/wearedevpunks-skills --skill dp-cli --full-depth
51
+ ```
52
+
53
+ The skill source lives at `/Users/stefan/Desktop/repos/wearedevpunks-skills/skills/agnostic/cli/dp-cli`.
39
54
 
40
55
  The lint scaffold is intentionally agent-facing rather than repo-mutating:
41
56
 
@@ -47,18 +62,37 @@ The lint scaffold is intentionally agent-facing rather than repo-mutating:
47
62
  Current scaffold-managed global tools:
48
63
 
49
64
  - `agent-browser`
65
+ - `debug-agent`
50
66
  - `opensrc`
67
+ - `portless`
68
+ - `skills`
69
+
70
+ On startup, `punks` checks npm for a newer CLI version. When it can infer whether the installed binary came from Bun, pnpm, or npm, it updates itself with the same global package manager; otherwise it prints a manual update hint. If the `dp-cli` operator skill is installed in the current project or globally, startup also asks the `skills` CLI to update that skill. Set `DP_NO_UPDATE_CHECK=1` or `DP_NO_SKILL_UPDATE_CHECK=1` to skip those checks.
71
+
72
+ ## Publishing
73
+
74
+ Use one command per release type:
75
+
76
+ ```bash
77
+ bun run baseline:publish
78
+ bun run release:publish
79
+ ```
80
+
81
+ `bun run baseline:publish` builds the current scaffold baseline, creates or updates the `baseline/stable/<date>-<sha>` GitHub release, and uploads the baseline manifest plus tarball. Use it when scaffold data changes but the npm executable does not need a new version.
82
+
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.
51
84
 
52
85
  ## Development
53
86
 
54
87
  ```bash
55
88
  bun install
56
89
  bun run build
90
+ bun run baseline:build
57
91
  bun run test
58
92
  bun run check-types
59
93
  ```
60
94
 
61
95
  ## Docs
62
96
 
63
- - [Scaffolding runbook](./docs/runbooks/punks-cli-scaffolding.md)
97
+ - [Scaffolding runbook](./docs/runbooks/dp-cli-scaffolding.md)
64
98
  - [Example: cicilca-doc-portal](./examples/cicilca-doc-portal/README.md)
@@ -98,12 +98,6 @@ Strong success criteria let you loop independently. Weak criteria ("make it work
98
98
 
99
99
  In readonly scenarios ONLY spawn subagents aggressively for parallelization opportunities outside code writing. Examples: research, auditing, docs updating, investigating multiple hypotheses, exploring unrelated areas. Fan out whenever possible, synthesize findings before acting.
100
100
 
101
- ## Harness Skill Layout
102
-
103
- - Keep `.agents/skills/` as the main project-local skill directory.
104
- - Keep `.claude/skills` as a symlink to `.agents/skills` for Claude compatibility.
105
- - Do not create `.codex/skills`, `.cursor/skills`, or `.opencode/skills`; Codex, Cursor, and OpenCode should read from `.agents/skills`.
106
-
107
101
  ## Notes — Cross-session Memory
108
102
 
109
103
  Notebook at `.agents/notes/`. Shared memory across sessions. Never ask permission.
@@ -0,0 +1,26 @@
1
+ export interface HookDefinition {
2
+ readonly id: string;
3
+ readonly harness: "shared";
4
+ readonly outputPath: string;
5
+ readonly description: string;
6
+ readonly sourcePath: string;
7
+ }
8
+
9
+ export const hookCatalog = [
10
+ {
11
+ id: "format-edited-file",
12
+ harness: "shared",
13
+ outputPath: ".agents/hooks/format-edited-file.mjs",
14
+ description:
15
+ "Shared hook that auto-formats edited JS/TS/JSON files and lint-checks product files after tool use.",
16
+ sourcePath: "hooks/format-edited-file.mjs",
17
+ },
18
+ {
19
+ id: "require-tests-for-pr",
20
+ harness: "shared",
21
+ outputPath: ".agents/hooks/require-tests-for-pr.mjs",
22
+ description:
23
+ "Shared hook that blocks PR creation while tests are failing.",
24
+ sourcePath: "hooks/require-tests-for-pr.mjs",
25
+ },
26
+ ] as const satisfies ReadonlyArray<HookDefinition>;
@@ -1,11 +1,4 @@
1
- export type LintAssetId =
2
- | "effect-no-barrel-imports"
3
- | "next-core"
4
- | "react-core"
5
- | "react-hooks"
6
- | "react-you-might-not-need-an-effect"
7
- | "tanstack-query-core"
8
- | "vitest-core";
1
+ export type LintAssetId = string;
9
2
 
10
3
  export interface LintJsPluginDefinition {
11
4
  readonly name: string;
@@ -25,6 +25,7 @@ export interface PackCatalogEntry {
25
25
  export const packCatalog = [
26
26
  { id: "backend", category: "surface", triggerPackages: [], description: "Backend pack: domain structure and recoverable actions.", skills: ["backend-domain-structure", "backend-recoverable-actions"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared backend domain baseline", "workspace backend action/recovery 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
+ { 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"] },
28
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"] },
29
30
  { id: "drizzle", category: "detected", triggerPackages: ["drizzle-kit", "drizzle-orm"], description: "Drizzle guidance pack.", skills: ["effect-backend-structure", "effect-recoverable-actions"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared data-layer baseline", "workspace db flow rules"] },
30
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"] },
@@ -40,5 +41,6 @@ export const packCatalog = [
40
41
  { id: "tanstack-query", category: "detected", triggerPackages: ["@tanstack/react-query"], description: "TanStack Query guidance pack.", skills: ["tanstack-query"], lintAssets: ["tanstack-query-core"], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared tanstack query baseline", "workspace server-state rules"] },
41
42
  { id: "trpc", category: "detected", triggerPackages: ["@trpc/"], description: "tRPC guidance pack.", skills: [], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared contract-first baseline", "workspace client/server boundaries"] },
42
43
  { id: "turborepo", category: "detected", triggerPackages: ["turbo"], description: "Turborepo guidance pack.", skills: ["turborepo"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared monorepo baseline", "workspace task boundary rules"] },
43
- { id: "typescript", category: "language", triggerPackages: ["typescript"], description: "Shared JavaScript / TypeScript language pack for hook and language-level scaffold assets.", skills: [], lintAssets: [], hooks: ["format-edited-file", "require-tests-for-pr"], promptSurfaces: [], promptDetails: [] },
44
+ { id: "python", category: "language", triggerPackages: [], description: "Shared Python language pack for async, style, structure, testing, and design guidance.", skills: ["async-python-patterns", "python-code-style", "python-design-patterns", "python-project-structure", "python-testing-patterns"], lintAssets: [], hooks: [], promptSurfaces: [], promptDetails: [] },
45
+ { id: "typescript", category: "language", triggerPackages: ["typescript"], description: "Shared JavaScript / TypeScript language pack for hook and language-level scaffold assets.", skills: ["quality-types"], lintAssets: [], hooks: ["format-edited-file", "require-tests-for-pr"], promptSurfaces: [], promptDetails: [] },
44
46
  ] as const satisfies ReadonlyArray<PackCatalogEntry>;
@@ -18,6 +18,7 @@ export const skillCatalog = [
18
18
  { id: "better-auth-best-practices", sourceDirectory: "skills/frameworks/better-auth/better-auth-best-practices", tier: "framework", language: "typescript", framework: "better-auth", requiresTools: [] },
19
19
  { id: "create-plan", sourceDirectory: "skills/agnostic/planning/create-plan", tier: "agnostic", language: null, framework: null, requiresTools: [] },
20
20
  { id: "create-spec", sourceDirectory: "skills/agnostic/planning/create-spec", tier: "agnostic", language: null, framework: null, requiresTools: [] },
21
+ { id: "debug-agent", sourceDirectory: "skills/agnostic/debug/debug-agent", tier: "agnostic", language: null, framework: null, requiresTools: ["debug-agent"] },
21
22
  { id: "docs-maintenance", sourceDirectory: "skills/agnostic/docs/docs-maintenance", tier: "agnostic", language: null, framework: null, requiresTools: [] },
22
23
  { id: "effect-authoring", sourceDirectory: "skills/frameworks/effect/effect-authoring", tier: "framework", language: "typescript", framework: "effect", requiresTools: ["opensrc"] },
23
24
  { id: "effect-backend-structure", sourceDirectory: "skills/frameworks/effect/effect-backend-structure", tier: "framework", language: "typescript", framework: "effect", requiresTools: ["opensrc"] },
@@ -32,6 +33,12 @@ export const skillCatalog = [
32
33
  { id: "next-best-practices", sourceDirectory: "skills/frameworks/nextjs/next-best-practices", tier: "framework", language: "typescript", framework: "nextjs", requiresTools: [] },
33
34
  { id: "next-cache-components", sourceDirectory: "skills/frameworks/nextjs/next-cache-components", tier: "framework", language: "typescript", framework: "nextjs", requiresTools: [] },
34
35
  { id: "parallel-research", sourceDirectory: "skills/agnostic/research/parallel-research", tier: "agnostic", language: null, framework: null, requiresTools: [] },
36
+ { id: "async-python-patterns", sourceDirectory: "skills/languages/python/async-python-patterns", tier: "language", language: "python", framework: null, requiresTools: [] },
37
+ { id: "python-code-style", sourceDirectory: "skills/languages/python/python-code-style", tier: "language", language: "python", framework: null, requiresTools: [] },
38
+ { id: "python-design-patterns", sourceDirectory: "skills/languages/python/python-design-patterns", tier: "language", language: "python", framework: null, requiresTools: [] },
39
+ { id: "python-project-structure", sourceDirectory: "skills/languages/python/python-project-structure", tier: "language", language: "python", framework: null, requiresTools: [] },
40
+ { id: "python-testing-patterns", sourceDirectory: "skills/languages/python/python-testing-patterns", tier: "language", language: "python", framework: null, requiresTools: [] },
41
+ { id: "quality-types", sourceDirectory: "skills/languages/typescript/quality-types", tier: "language", language: "typescript", framework: null, requiresTools: [] },
35
42
  { id: "async-react-patterns", sourceDirectory: "skills/frameworks/react/async-react-patterns", tier: "framework", language: "typescript", framework: "react", requiresTools: [] },
36
43
  { id: "requirements-grill", sourceDirectory: "skills/agnostic/requirements/requirements-grill", tier: "agnostic", language: null, framework: null, requiresTools: [] },
37
44
  { id: "simplify", sourceDirectory: "skills/agnostic/quality/simplify", tier: "agnostic", language: null, framework: null, requiresTools: [] },
@@ -44,4 +51,4 @@ export const skillCatalog = [
44
51
  { id: "write-backlog", sourceDirectory: "skills/agnostic/requirements/write-backlog", tier: "agnostic", language: null, framework: null, requiresTools: [] },
45
52
  ] as const satisfies ReadonlyArray<SkillCatalogEntry>;
46
53
 
47
- export type SkillId = (typeof skillCatalog)[number]["id"];
54
+ export type SkillId = string;
@@ -5,6 +5,12 @@ export const toolCatalog = [
5
5
  requiredBins: ["node"],
6
6
  ensureCommands: [["agent-browser", "install"]],
7
7
  },
8
+ {
9
+ id: "debug-agent",
10
+ packageName: "debug-agent",
11
+ requiredBins: ["node"],
12
+ ensureCommands: [],
13
+ },
8
14
  {
9
15
  id: "opensrc",
10
16
  packageName: "opensrc",
@@ -17,6 +23,12 @@ export const toolCatalog = [
17
23
  requiredBins: ["node"],
18
24
  ensureCommands: [],
19
25
  },
26
+ {
27
+ id: "skills",
28
+ packageName: "skills",
29
+ requiredBins: ["node"],
30
+ ensureCommands: [],
31
+ },
20
32
  ] as const;
21
33
 
22
- export type ToolId = (typeof toolCatalog)[number]["id"];
34
+ export type ToolId = string;
@@ -62,6 +62,35 @@ const capabilityPacks = {
62
62
  "Repo documentation maintenance, routing, and human-facing durable knowledge capture.",
63
63
  skills: ["docs-maintenance"],
64
64
  },
65
+ "python-core": {
66
+ description:
67
+ "Python project structure, code style, design boundaries, and everyday implementation guidance.",
68
+ skills: [
69
+ "python-project-structure",
70
+ "python-design-patterns",
71
+ "python-code-style",
72
+ "python-testing-patterns",
73
+ ],
74
+ },
75
+ "python-async": {
76
+ description:
77
+ "Python asyncio, concurrent I/O, async API boundaries, and async test strategy.",
78
+ skills: [
79
+ "async-python-patterns",
80
+ "python-project-structure",
81
+ "python-code-style",
82
+ "python-testing-patterns",
83
+ ],
84
+ },
85
+ "python-quality": {
86
+ description:
87
+ "Python pytest coverage, fixture design, style checks, and refactor-safe quality work.",
88
+ skills: [
89
+ "python-testing-patterns",
90
+ "python-code-style",
91
+ "python-design-patterns",
92
+ ],
93
+ },
65
94
  };
66
95
 
67
96
  const skillActivationInstructions = [
@@ -248,6 +277,96 @@ const agents = [
248
277
  "If the task is mainly HTTP transport or route mounting, tell the parent to use server-transport instead.",
249
278
  ],
250
279
  },
280
+ {
281
+ name: "python-app",
282
+ description:
283
+ "Use for Python application work centered on module structure, implementation, code style, maintainability, and tests.",
284
+ ownedPaths: [
285
+ "src/**",
286
+ "packages/**",
287
+ "services/**",
288
+ "apps/**",
289
+ "tests/**",
290
+ "pyproject.toml",
291
+ "requirements*.txt",
292
+ "uv.lock",
293
+ "poetry.lock",
294
+ ],
295
+ guidanceFiles: ["AGENTS.md"],
296
+ activationInstructions: skillActivationInstructions,
297
+ packs: ["python-core", "python-quality", "simplify"],
298
+ skills: [
299
+ "python-project-structure",
300
+ "python-design-patterns",
301
+ "python-code-style",
302
+ "python-testing-patterns",
303
+ "simplify",
304
+ ],
305
+ boundaries: [
306
+ "Own ordinary Python implementation, project layout, module boundaries, and nearby tests.",
307
+ "If the task is mainly asyncio, concurrent I/O, WebSockets, or async API behavior, tell the parent to use python-async instead.",
308
+ "If the task is mainly test suite design, fixture cleanup, or pytest behavior without feature work, tell the parent to use python-testing instead.",
309
+ "If the task is mainly TypeScript, frontend, Effect, or auth-specific work, tell the parent to use the matching non-Python specialist.",
310
+ ],
311
+ },
312
+ {
313
+ name: "python-async",
314
+ description:
315
+ "Use for Python async work centered on asyncio, concurrent I/O, async APIs, background tasks, and async test coverage.",
316
+ ownedPaths: [
317
+ "src/**",
318
+ "packages/**",
319
+ "services/**",
320
+ "apps/**",
321
+ "tests/**",
322
+ "pyproject.toml",
323
+ ],
324
+ guidanceFiles: ["AGENTS.md"],
325
+ activationInstructions: skillActivationInstructions,
326
+ packs: ["python-async", "python-quality", "simplify"],
327
+ skills: [
328
+ "async-python-patterns",
329
+ "python-project-structure",
330
+ "python-code-style",
331
+ "python-testing-patterns",
332
+ "simplify",
333
+ ],
334
+ boundaries: [
335
+ "Own async Python flows, cancellation, task lifetime, backpressure, concurrent I/O, and async test coverage.",
336
+ "Keep structural refactors limited to what the async change needs; broader project layout belongs to python-app.",
337
+ "If the task is synchronous business logic or package structure, tell the parent to use python-app instead.",
338
+ "If the task is only pytest fixture or assertion work, tell the parent to use python-testing instead.",
339
+ ],
340
+ },
341
+ {
342
+ name: "python-testing",
343
+ description:
344
+ "Use for Python test work centered on pytest, fixtures, integration boundaries, mocks, coverage, and refactor-safe assertions.",
345
+ ownedPaths: [
346
+ "tests/**",
347
+ "**/tests/**",
348
+ "src/**",
349
+ "packages/**",
350
+ "services/**",
351
+ "apps/**",
352
+ "pyproject.toml",
353
+ ],
354
+ guidanceFiles: ["AGENTS.md"],
355
+ activationInstructions: skillActivationInstructions,
356
+ packs: ["python-quality", "simplify"],
357
+ skills: [
358
+ "python-testing-patterns",
359
+ "python-code-style",
360
+ "python-design-patterns",
361
+ "simplify",
362
+ ],
363
+ boundaries: [
364
+ "Own pytest structure, fixtures, parameterization, integration-test shape, and test readability.",
365
+ "Prefer tests that exercise real behavior over brittle mocks unless the boundary is genuinely external.",
366
+ "If fixing production Python code becomes the main task, tell the parent to use python-app or python-async depending on the failure.",
367
+ "If test work crosses into TypeScript, frontend, or Effect-specific systems, tell the parent to split that work to the matching specialist.",
368
+ ],
369
+ },
251
370
  ];
252
371
 
253
372
  export { agents, capabilityPacks };