@brunosps00/dev-workflow 1.0.4 → 1.0.5
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 +58 -14
- package/bin/dev-workflow.js +29 -3
- package/lib/agents.js +410 -0
- package/lib/constants.js +12 -0
- package/lib/doctor.js +213 -0
- package/lib/init.js +96 -8
- package/lib/install-state.js +57 -0
- package/lib/list-installed.js +27 -0
- package/lib/migrate-skills.js +26 -2
- package/lib/profiles.js +44 -0
- package/lib/skill-registry.js +109 -0
- package/lib/subtasks.js +264 -0
- package/lib/uninstall.js +21 -12
- package/lib/utils.js +42 -1
- package/lib/wrappers.js +2 -1
- package/package.json +1 -1
- package/scaffold/agent-registry.json +272 -0
- package/scaffold/agents/core/dw-build-fixer.md +21 -0
- package/scaffold/agents/core/dw-code-explorer.md +32 -0
- package/scaffold/agents/core/dw-code-reviewer.md +28 -0
- package/scaffold/agents/core/dw-planner.md +23 -0
- package/scaffold/agents/core/dw-test-author.md +21 -0
- package/scaffold/agents/csharp/dw-csharp-reviewer.md +15 -0
- package/scaffold/agents/csharp/dw-dotnet-build-fixer.md +15 -0
- package/scaffold/agents/frontend/dw-qa-runner.md +21 -0
- package/scaffold/agents/python/dw-python-build-fixer.md +15 -0
- package/scaffold/agents/python/dw-python-reviewer.md +15 -0
- package/scaffold/agents/rust/dw-rust-build-fixer.md +15 -0
- package/scaffold/agents/rust/dw-rust-reviewer.md +15 -0
- package/scaffold/agents/security/dw-security-reviewer.md +24 -0
- package/scaffold/agents/security/dw-silent-failure-hunter.md +22 -0
- package/scaffold/agents/typescript/dw-typescript-build-fixer.md +15 -0
- package/scaffold/agents/typescript/dw-typescript-reviewer.md +15 -0
- package/scaffold/en/agent-instructions.md +44 -1
- package/scaffold/en/commands/dw-bugfix.md +9 -0
- package/scaffold/en/commands/dw-context-budget.md +28 -0
- package/scaffold/en/commands/dw-harness-audit.md +31 -0
- package/scaffold/en/commands/dw-help.md +15 -5
- package/scaffold/en/commands/dw-intel.md +6 -0
- package/scaffold/en/commands/dw-plan.md +11 -0
- package/scaffold/en/commands/dw-review.md +12 -0
- package/scaffold/en/commands/dw-skill-health.md +29 -0
- package/scaffold/en/commands/dw-subtask-complete.md +40 -0
- package/scaffold/en/commands/dw-subtask-resume.md +21 -0
- package/scaffold/en/commands/dw-subtask-start.md +22 -0
- package/scaffold/pt-br/agent-instructions.md +44 -1
- package/scaffold/pt-br/commands/dw-bugfix.md +9 -0
- package/scaffold/pt-br/commands/dw-context-budget.md +28 -0
- package/scaffold/pt-br/commands/dw-harness-audit.md +31 -0
- package/scaffold/pt-br/commands/dw-help.md +15 -5
- package/scaffold/pt-br/commands/dw-intel.md +6 -0
- package/scaffold/pt-br/commands/dw-plan.md +11 -0
- package/scaffold/pt-br/commands/dw-review.md +12 -0
- package/scaffold/pt-br/commands/dw-skill-health.md +29 -0
- package/scaffold/pt-br/commands/dw-subtask-complete.md +40 -0
- package/scaffold/pt-br/commands/dw-subtask-resume.md +21 -0
- package/scaffold/pt-br/commands/dw-subtask-start.md +22 -0
- package/scaffold/skill-registry.json +258 -0
- package/scaffold/skills/dw-codebase-intel/SKILL.md +12 -5
- package/scaffold/skills/dw-context-budget/SKILL.md +45 -0
- package/scaffold/skills/dw-search-first/SKILL.md +31 -0
- package/scaffold/skills/dw-silent-failure/SKILL.md +33 -0
- package/scaffold/skills/dw-verify/SKILL.md +2 -29
- package/scaffold/skills/dw-verify/references/verification-discovery-and-attribution.md +32 -0
- package/scaffold/skills/humanizer/SKILL.md +7 -412
- package/scaffold/skills/humanizer/references/ai-writing-patterns.md +418 -0
package/README.md
CHANGED
|
@@ -10,11 +10,11 @@ npx @brunosps00/dev-workflow init
|
|
|
10
10
|
|
|
11
11
|
This will:
|
|
12
12
|
1. Ask you to select a language (English or Portuguese)
|
|
13
|
-
2. Create `.dw/commands/` with
|
|
13
|
+
2. Create `.dw/commands/` with workflow commands
|
|
14
14
|
3. Create `.dw/templates/` with document templates (PRD, TechSpec, Tasks, ADR, etc.)
|
|
15
15
|
4. Create `.dw/rules/` (populated by `/dw-analyze-project`)
|
|
16
16
|
5. Install bundled skills (`dw-verify`, `dw-memory`, `dw-review-rigor`, `dw-ui-discipline`, `dw-testing-discipline`, `security-review`, etc.) to `.agents/skills/`
|
|
17
|
-
6. Generate skill wrappers for Claude Code, Codex, Copilot, and OpenCode
|
|
17
|
+
6. Generate skill wrappers and project agents for Claude Code, Codex, Copilot, and OpenCode
|
|
18
18
|
7. Configure MCP servers (Context7 + Playwright)
|
|
19
19
|
|
|
20
20
|
> **Compozy-inspired disciplines.** Since 0.5.0, dev-workflow bundles three primitives — `dw-verify`, `dw-memory`, `dw-review-rigor` — adapted from the [Compozy](https://github.com/compozy/compozy) project and invoked internally by existing commands. See [docs/compozy-integration.md](docs/compozy-integration.md) for what was ported and what was not.
|
|
@@ -26,7 +26,7 @@ npx @brunosps00/dev-workflow install-deps
|
|
|
26
26
|
|
|
27
27
|
## Commands
|
|
28
28
|
|
|
29
|
-
dev-workflow v1.0.
|
|
29
|
+
dev-workflow v1.0.5 ships **30 commands** organized into four tiers. Most users only invoke Tier 1 + Tier 2.
|
|
30
30
|
|
|
31
31
|
### Tier 1 — Gateway (3)
|
|
32
32
|
|
|
@@ -52,19 +52,22 @@ Use these when you want step-by-step control instead of `/dw-autopilot`.
|
|
|
52
52
|
| **`/dw-commit`** | Atomic Conventional Commits for pending changes. Applies `dw-git-discipline` (one intent per commit, lint+tests+build green before). |
|
|
53
53
|
| **`/dw-generate-pr [target]`** | Push the branch, draft a PR body with summary + test plan, open the browser. Hard gates: dw-verify PASS + secure-audit. |
|
|
54
54
|
|
|
55
|
-
### Tier 3 — Specialty (
|
|
55
|
+
### Tier 3 — Specialty (8)
|
|
56
56
|
|
|
57
57
|
| Command | What |
|
|
58
58
|
|---------|------|
|
|
59
59
|
| **`/dw-analyze-project`** | Scans the repo, writes `.dw/rules/` (per-module conventions, anti-patterns, naming). Step 8 offers to generate `.dw/constitution.md` (declarative principles the team commits to). Step 9 generates `.dw/rules/concerns.md` (risk map: hot spots, fragile integrations, hostile code, bug history). Run once per project; refresh after major refactors. |
|
|
60
60
|
| **`/dw-redesign-ui "target"`** | Audits a frontend page, runs the `dw-ui-discipline` 4-question grounding, proposes 2-3 design directions, ships the redesign. WCAG 2.2 AA accessibility floor is non-negotiable. |
|
|
61
61
|
| **`/dw-functional-doc`** | Maps screens + user flows into a functional doc, validated end-to-end with Playwright. |
|
|
62
|
+
| **`/dw-context-budget`** | Audits context overhead from commands, skills, agents, instruction files, and MCPs. |
|
|
63
|
+
| **`/dw-harness-audit`** | Deterministic health scorecard for the dev-workflow install, agents, wrappers, MCPs, and gates. |
|
|
64
|
+
| **`/dw-skill-health`** | Audits installed skills and agents for bloat, duplication, and missing references. |
|
|
62
65
|
| **`/dw-new-project`** | Bootstrap a new project from empty directory. Stack interview, wraps official `create-*` tools, composes docker-compose for dev, seeds `.env`, scripts, CI, `.dw/rules/`. |
|
|
63
66
|
| **`/dw-dockerize`** | Reads existing project, detects stack + runtime deps, proposes Dockerfile + docker-compose for dev/prod with explicit trade-offs (Conservative/Balanced/Bold). |
|
|
64
67
|
| **`/dw-install-azure-skills`** | **Opt-in.** Clones curated Azure skills from [`MicrosoftDocs/Agent-Skills`](https://github.com/MicrosoftDocs/Agent-Skills) (CC-BY-4.0) into `.agents/skills/azure/` and registers the [Microsoft Learn MCP Server](https://learn.microsoft.com/en-us/training/support/mcp-get-started) (HTTP, no-auth). Interactive category selection (Compute / Data & Storage / AI & ML / Networking / Identity & Security / DevOps / Observability / Integration / Architecture / All). Re-run to refresh from upstream. Also available as CLI: `npx @brunosps00/dev-workflow install-azure-skills`. |
|
|
65
68
|
| **`/dw-install-aws-skills`** | **Opt-in.** Clones curated AWS skills from [`aws/agent-toolkit-for-aws`](https://github.com/aws/agent-toolkit-for-aws) (Apache 2.0) into `.agents/skills/aws/` and registers the unified [AWS MCP Server](https://docs.aws.amazon.com/aws-mcp/) (stdio via `uvx mcp-proxy-for-aws@latest`). **Requires `uv`, `aws cli ≥ 2.32.0`, and AWS credentials.** Interactive category selection (Core / Analytics / Database / EC2 / Migration / Networking / Operations / Security / Serverless / Storage / All). The agent gains `aws___call_aws` (executes 15,000+ AWS APIs) and `aws___run_script` (Python sandboxed) — review `.dw/references/aws-mcp-instructions.md` for the destructive-operations protocol. Also available as CLI: `npx @brunosps00/dev-workflow install-aws-skills [--region=<aws-region>]`. |
|
|
66
69
|
|
|
67
|
-
### Tier 4 — Hidden/Internal (
|
|
70
|
+
### Tier 4 — Hidden/Internal (8)
|
|
68
71
|
|
|
69
72
|
These are auto-invoked by Tier 1-3 commands. Available standalone via `/dw-help --advanced`.
|
|
70
73
|
|
|
@@ -75,6 +78,9 @@ These are auto-invoked by Tier 1-3 commands. Available standalone via `/dw-help
|
|
|
75
78
|
| **`/dw-secure-audit`** | Unified security: OWASP + Trivy SCA/secret/IaC + lockfile + supply-chain check. Hard gate. Flags: `--scan-only`, `--plan`, `--execute`. | `/dw-review`, `/dw-generate-pr` (for TS/Python/C#/Rust) |
|
|
76
79
|
| **`/dw-find-skills "query"`** | Searches `npx skills` ecosystem, vets, installs. | manual when extending the bundle |
|
|
77
80
|
| **`/dw-update`** | Updates dev-workflow to latest npm release with rollback snapshot. | manual maintenance |
|
|
81
|
+
| **`/dw-subtask-start`** | Creates a minimal input packet for a subagent without injecting the parent transcript. | parent agent before delegation |
|
|
82
|
+
| **`/dw-subtask-complete`** | Records a structured child-session handoff. | subagent / child session |
|
|
83
|
+
| **`/dw-subtask-resume`** | Consumes and archives pending handoffs for parent synthesis. | parent agent after delegation |
|
|
78
84
|
|
|
79
85
|
## Workflow
|
|
80
86
|
|
|
@@ -157,7 +163,7 @@ npx @brunosps00/dev-workflow update
|
|
|
157
163
|
|----------|-----------------|--------|
|
|
158
164
|
| Claude Code | `.claude/skills/` | Full support |
|
|
159
165
|
| Codex CLI | `.agents/skills/` | Full support |
|
|
160
|
-
| Copilot | `.agents/skills/` | Full support |
|
|
166
|
+
| Copilot | `.agents/skills/` + `.github/agents/` | Full support |
|
|
161
167
|
| OpenCode | `.opencode/commands/` | Full support |
|
|
162
168
|
|
|
163
169
|
All wrappers point to `.dw/commands/` as the single source of truth.
|
|
@@ -167,29 +173,67 @@ All wrappers point to `.dw/commands/` as the single source of truth.
|
|
|
167
173
|
```
|
|
168
174
|
your-project/
|
|
169
175
|
├── .dw/
|
|
170
|
-
│ ├── commands/ #
|
|
176
|
+
│ ├── commands/ # workflow command files
|
|
171
177
|
│ ├── templates/ # Document templates (PRD, TechSpec, state, concerns, bugfix-summary, etc.)
|
|
172
178
|
│ │ └── overrides/ # Project-local template customizations (override > core)
|
|
173
179
|
│ ├── rules/ # Project-specific rules (run /dw-analyze-project)
|
|
174
180
|
│ │ └── concerns.md # Risk map: hot spots, fragile integrations, bug history (Step 9 of /dw-analyze-project)
|
|
175
181
|
│ ├── constitution.md # Declarative principles (auto-installed when missing)
|
|
182
|
+
│ ├── skill-registry.json # Local skill taxonomy, triggers, owners, load policy, and context limits
|
|
176
183
|
│ ├── references/ # Reference documentation
|
|
177
184
|
│ ├── scripts/ # Utility scripts
|
|
178
185
|
│ ├── spec/ # PRD directories — each contains tasks-validation.md
|
|
179
186
|
│ ├── bugfixes/ # Persistent bugfix records: NNN-<slug>/{TASK.md, SUMMARY.md, fix-report.md} + review/, QA/
|
|
187
|
+
│ ├── subtasks/ # Local ephemeral subagent input packets and handoffs (pending/archive ignored by Git)
|
|
180
188
|
│ └── STATE.md # Session state: Decisions, Blockers, Todos, Open Loops, Deferred Ideas, Lessons, Preferences (managed by /dw-pause + /dw-resume)
|
|
181
189
|
├── CLAUDE.md # Auto-trigger decision tree for Claude Code (merge-aware, includes Auto-Sizing Matrix)
|
|
182
190
|
├── AGENTS.md # Same content for Codex / Copilot / OpenCode
|
|
183
191
|
├── .claude/
|
|
184
192
|
│ ├── skills/ # Claude Code wrappers
|
|
193
|
+
│ ├── agents/ # Claude Code project agents
|
|
185
194
|
│ └── settings.json # MCP servers (Context7, Playwright)
|
|
186
195
|
├── .agents/skills/ # Codex/Copilot wrappers + bundled skills
|
|
187
|
-
|
|
196
|
+
├── .agents/agents/ # Codex/Copilot fallback agent definitions
|
|
197
|
+
├── .github/agents/ # GitHub Copilot custom agents
|
|
198
|
+
├── .opencode/commands/ # OpenCode wrappers
|
|
199
|
+
└── .opencode/agent/ # OpenCode project agents
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Agents
|
|
203
|
+
|
|
204
|
+
`dev-workflow` installs a compact agent layer in addition to skills. Skills remain protocols and reference material; agents are dispatchable roles such as `dw-code-explorer`, `dw-build-fixer`, `dw-code-reviewer`, and language-specific reviewers.
|
|
205
|
+
|
|
206
|
+
Profiles control agent breadth:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npx @brunosps00/dev-workflow init --profile=core
|
|
210
|
+
npx @brunosps00/dev-workflow init --profile=standard
|
|
211
|
+
npx @brunosps00/dev-workflow init --profile=full
|
|
212
|
+
npx @brunosps00/dev-workflow init --modules=typescript,python
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Claude Code and OpenCode receive native project-agent files. Copilot receives `.github/agents/*.agent.md`. Codex receives fallback agent definitions and dispatch instructions through `AGENTS.md`.
|
|
216
|
+
|
|
217
|
+
Subagent handoffs use local packets under `.dw/subtasks/`:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npx @brunosps00/dev-workflow subtask create --agent=dw-code-explorer --goal="Map the auth flow"
|
|
221
|
+
npx @brunosps00/dev-workflow subtask complete --slug=<slug> --file=<handoff.md>
|
|
222
|
+
npx @brunosps00/dev-workflow subtask consume
|
|
188
223
|
```
|
|
189
224
|
|
|
190
225
|
## Bundled Skills
|
|
191
226
|
|
|
192
|
-
Skills installed to `.agents/skills/` for use by all commands.
|
|
227
|
+
Skills installed to `.agents/skills/` for use by all commands. The bundle is governed by `scaffold/skill-registry.json`, which records each skill's kind, tier, owner, trigger, expected output, load policy, and context limit.
|
|
228
|
+
|
|
229
|
+
Skill kinds:
|
|
230
|
+
|
|
231
|
+
- `protocol`: execution discipline or gate used by commands.
|
|
232
|
+
- `domain-pack`: deeper expertise for a domain such as security, UI, testing, React, Remotion, incident response, or LLM evals.
|
|
233
|
+
- `recipe-pack`: tactical recipes for a narrow implementation surface.
|
|
234
|
+
- `asset-pack`: reusable non-code material, prompts, templates, or editorial references.
|
|
235
|
+
|
|
236
|
+
The rule is deliberate: `SKILL.md` should be a compact entrypoint. Large examples, rules, assets, and checklists live under `references/`, `assets/`, `scripts/`, or `rules/` and are loaded only when the trigger actually needs them. `dev-workflow doctor` validates the registry, installed bundled skills, and context-size limits; `/dw-skill-health` is the agent-facing audit for overlap, bloat, and weak triggers.
|
|
193
237
|
|
|
194
238
|
### Workflow discipline (invoked internally by dw-* commands)
|
|
195
239
|
|
|
@@ -273,7 +317,7 @@ Incident response (`dw-incident-response`) adapted from [`wilsto/claude-code-sta
|
|
|
273
317
|
|
|
274
318
|
LLM evaluation (`dw-llm-eval`) trajectory-match modes (strict / unordered / subset / superset) and tool-argument matching strategies adapted from [`langchain-ai/agentevals`](https://github.com/langchain-ai/agentevals) (MIT). The broader oracle-ladder framing, judge-calibration discipline, and reference-dataset principle are distilled from the open evaluations literature (OpenAI evals cookbook, Anthropic evals guidance, the academic eval-of-LLM body of work) and rewritten in our voice.
|
|
275
319
|
|
|
276
|
-
Optional AWS integration (v1.0.
|
|
320
|
+
Optional AWS integration (v1.0.5). The `/dw-install-aws-skills` command and `npx @brunosps00/dev-workflow install-aws-skills` CLI pull curated agent skills from [`aws/agent-toolkit-for-aws`](https://github.com/aws/agent-toolkit-for-aws) (Apache 2.0, by AWS) into `.agents/skills/aws/` and register the unified [AWS MCP Server](https://docs.aws.amazon.com/aws-mcp/) via [`mcp-proxy-for-aws`](https://github.com/aws/mcp-proxy-for-aws) (stdio transport with SigV4 authentication). Unlike the Azure equivalent, the AWS MCP Server requires `uv`, `aws cli ≥ 2.32.0`, and valid AWS credentials configured via `aws login` or an IAM profile — the command detects each prerequisite and prints OS-specific install instructions if missing (without auto-installing anything). Capability includes `aws___search_documentation`, `aws___read_documentation`, `aws___retrieve_skill`, plus `aws___call_aws` (executes any of 15,000+ AWS APIs with the user's IAM permissions) and `aws___run_script` (Python sandboxed). `.dw/references/aws-mcp-instructions.md` encodes the destructive-operations protocol — agents must confirm before any `create*`/`update*`/`delete*`/`modify*` call, IAM change, or billing-affecting operation. The AWS Knowledge MCP (HTTP, no-auth) was considered for symmetry with Microsoft Learn MCP but is officially deprecated by AWS in favor of the unified server, which AWS explicitly recommends against running alongside the legacy endpoint ("tool conflicts that confuse AI agents"). Default endpoint is `us-east-1` with `eu-central-1` available; region overridable via `--region=<aws-region>` or by editing `.claude/settings.json` directly. Not installed by default; user explicitly invokes the command. Re-run refreshes from upstream; `dev-workflow update` deliberately does not touch `.agents/skills/aws/`.
|
|
277
321
|
|
|
278
322
|
Optional Azure integration (v1.0.3). The `/dw-install-azure-skills` command and `npx @brunosps00/dev-workflow install-azure-skills` CLI pull curated agent skills from [`MicrosoftDocs/Agent-Skills`](https://github.com/MicrosoftDocs/Agent-Skills) (CC-BY-4.0, by Microsoft) into `.agents/skills/azure/` and register the [Microsoft Learn MCP Server](https://learn.microsoft.com/en-us/training/support/mcp-get-started) (HTTP endpoint, no authentication required) into `.claude/settings.json`. The MCP server exposes three tools — `microsoft_docs_search`, `microsoft_docs_fetch`, `microsoft_code_sample_search` — that give the agent live access to Microsoft Learn documentation. **Not installed by default**: `init` and `update` do not touch `.agents/skills/azure/` or register the MCP. Users explicitly invoke the command when they begin Azure-focused work. The 10 categories (Compute, Data & Storage, AI & ML, Networking, Identity & Security, DevOps, Observability, Integration, Architecture, All) are dev-workflow's curated grouping over the 200+ skills in the upstream repo; the `--products=<csv>` flag lets advanced users pick individual services. Re-running the command refreshes from upstream; `dev-workflow update` deliberately does not touch these external skills so the Microsoft upstream release cadence is decoupled from the dev-workflow npm release cadence. Skills are copied verbatim from the upstream repo (CC-BY-4.0 permits this with attribution); the agent-facing `.dw/references/azure-mcp-instructions.md` is a clean-room adaptation of Microsoft's "Set instructions" guidance.
|
|
279
323
|
|
|
@@ -283,7 +327,7 @@ Four patterns from [`mattpocock/skills`](https://github.com/mattpocock/skills) b
|
|
|
283
327
|
|
|
284
328
|
## Migration from v0.x (1.0.0 is a consolidation release)
|
|
285
329
|
|
|
286
|
-
v1.0.0
|
|
330
|
+
v1.0.0 consolidated the legacy command surface into the current `dw-*` pipeline. **The `dev-workflow init`, `update`, and `repair` flows auto-remove obsolete wrappers and known removed command sources**; no manual action required.
|
|
287
331
|
|
|
288
332
|
### Command renames (15 → 7 merged)
|
|
289
333
|
|
|
@@ -319,8 +363,8 @@ On the next `npx @brunosps00/dev-workflow update`, the following happens automat
|
|
|
319
363
|
|
|
320
364
|
1. The 15 renamed commands' wrappers are detected as orphans (their names no longer exist in `lib/constants.js`) and removed from `.claude/skills/`, `.agents/skills/`, and `.opencode/commands/`.
|
|
321
365
|
2. The migrator prints each removal with the friendly "old → new" mapping (e.g., `[orphan] Removing wrapper .agents/skills/dw-create-prd (replaced in v1.0.0 by 'dw-plan prd')`).
|
|
322
|
-
3. The
|
|
323
|
-
4. The
|
|
366
|
+
3. The current command wrappers are installed for the consolidated commands.
|
|
367
|
+
4. The bundled skills are refreshed.
|
|
324
368
|
|
|
325
369
|
### Backwards compatibility
|
|
326
370
|
|
|
@@ -332,7 +376,7 @@ The Trigger Map block (between `<!-- dev-workflow:start -->` and `<!-- dev-workf
|
|
|
332
376
|
|
|
333
377
|
### Skill conventions
|
|
334
378
|
|
|
335
|
-
Skill description format ("pushy" trigger phrases ≤200 chars, "Use when X. Triggers on Y." pattern) and structural conventions (`SKILL.md` + `references/` / `scripts/` / `assets/` / `agents/` subdirectories, explicit `allowed-tools` in frontmatter) follow the official guidance from [`anthropics/skills/skill-creator`](https://github.com/anthropics/skills/tree/main/skills/skill-creator) (Apache 2.0). dev-workflow's
|
|
379
|
+
Skill description format ("pushy" trigger phrases ≤200 chars, "Use when X. Triggers on Y." pattern) and structural conventions (`SKILL.md` + `references/` / `scripts/` / `assets/` / `agents/` subdirectories, explicit `allowed-tools` in frontmatter) follow the official guidance from [`anthropics/skills/skill-creator`](https://github.com/anthropics/skills/tree/main/skills/skill-creator) (Apache 2.0). dev-workflow's bundled skills are not derived from skill-creator's content — only its conventions are followed for auto-trigger reliability across Claude Code, Codex CLI, Copilot, and OpenCode.
|
|
336
380
|
|
|
337
381
|
## License
|
|
338
382
|
|
package/bin/dev-workflow.js
CHANGED
|
@@ -22,8 +22,16 @@ const HELP_TEXT = `
|
|
|
22
22
|
|
|
23
23
|
Usage:
|
|
24
24
|
npx dev-workflow init [--force] [--lang=en|pt-br]
|
|
25
|
-
npx dev-workflow
|
|
25
|
+
npx dev-workflow init [--force] [--lang=en|pt-br] [--profile=core|standard|full] [--modules=<csv>]
|
|
26
|
+
npx dev-workflow update [--lang=en|pt-br] [--profile=core|standard|full] [--modules=<csv>]
|
|
26
27
|
npx dev-workflow install-deps
|
|
28
|
+
npx dev-workflow list-installed
|
|
29
|
+
npx dev-workflow doctor
|
|
30
|
+
npx dev-workflow repair
|
|
31
|
+
npx dev-workflow subtask create --agent=<name> --goal="<goal>"
|
|
32
|
+
npx dev-workflow subtask complete --slug=<slug> --file=<handoff.md>
|
|
33
|
+
npx dev-workflow subtask consume
|
|
34
|
+
npx dev-workflow subtask list
|
|
27
35
|
npx dev-workflow install-azure-skills [--products=<csv>]
|
|
28
36
|
npx dev-workflow install-aws-skills [--region=<aws-region>]
|
|
29
37
|
npx dev-workflow help
|
|
@@ -32,6 +40,10 @@ const HELP_TEXT = `
|
|
|
32
40
|
init Scaffold .dw/ (commands, templates, references, scripts, skills, rules, MCPs)
|
|
33
41
|
update Update managed files (commands, templates, references, scripts, skills, wrappers, MCPs)
|
|
34
42
|
Preserves: .dw/rules/, .dw/spec/, .dw/bugfixes/, .dw/STATE.md, .agents/skills/azure/, user data
|
|
43
|
+
list-installed Show dev-workflow install state for this project
|
|
44
|
+
doctor Check managed files, wrappers, agents, and MCP configuration
|
|
45
|
+
repair Reconcile managed files using the recorded install state
|
|
46
|
+
subtask Create, complete, consume, and list local subagent handoffs
|
|
35
47
|
install-deps Install system dependencies (Playwright browsers, MCP servers)
|
|
36
48
|
install-azure-skills Opt-in: clone curated Azure skills from MicrosoftDocs/Agent-Skills
|
|
37
49
|
into .agents/skills/azure/ and register the Microsoft Learn MCP
|
|
@@ -47,6 +59,8 @@ const HELP_TEXT = `
|
|
|
47
59
|
Options:
|
|
48
60
|
--force Overwrite existing files (init only; update always overwrites managed files)
|
|
49
61
|
--lang=LANG Set language without prompt (en or pt-br)
|
|
62
|
+
--profile=NAME Install profile for agents (core, standard, full)
|
|
63
|
+
--modules=CSV Extra agent modules to install (typescript, python, csharp, rust, security, frontend)
|
|
50
64
|
|
|
51
65
|
Examples:
|
|
52
66
|
npx dev-workflow init # Interactive language selection
|
|
@@ -61,10 +75,22 @@ const HELP_TEXT = `
|
|
|
61
75
|
async function main() {
|
|
62
76
|
switch (command) {
|
|
63
77
|
case 'init':
|
|
64
|
-
await run({ force: !!flags.force, lang: flags.lang, mode: 'init' });
|
|
78
|
+
await run({ force: !!flags.force, lang: flags.lang, mode: 'init', profile: flags.profile, modules: flags.modules });
|
|
65
79
|
break;
|
|
66
80
|
case 'update':
|
|
67
|
-
await run({ force: !!flags.force, lang: flags.lang, mode: 'update' });
|
|
81
|
+
await run({ force: !!flags.force, lang: flags.lang, mode: 'update', profile: flags.profile, modules: flags.modules });
|
|
82
|
+
break;
|
|
83
|
+
case 'list-installed':
|
|
84
|
+
require('../lib/list-installed').run();
|
|
85
|
+
break;
|
|
86
|
+
case 'doctor':
|
|
87
|
+
require('../lib/doctor').run({ repair: false });
|
|
88
|
+
break;
|
|
89
|
+
case 'repair':
|
|
90
|
+
await run({ force: true, lang: flags.lang, mode: 'repair', profile: flags.profile, modules: flags.modules });
|
|
91
|
+
break;
|
|
92
|
+
case 'subtask':
|
|
93
|
+
require('../lib/subtasks').run(args.slice(1));
|
|
68
94
|
break;
|
|
69
95
|
case 'install-deps':
|
|
70
96
|
installDeps.run();
|
package/lib/agents.js
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { ensureDir, readJson, writeFile, log } = require('./utils');
|
|
4
|
+
|
|
5
|
+
const SCAFFOLD_DIR = path.join(__dirname, '..', 'scaffold');
|
|
6
|
+
const REGISTRY_PATH = path.join(SCAFFOLD_DIR, 'agent-registry.json');
|
|
7
|
+
|
|
8
|
+
const AGENT_TARGETS = {
|
|
9
|
+
claude: {
|
|
10
|
+
dir: '.claude/agents',
|
|
11
|
+
fileName: (name) => `${name}.md`,
|
|
12
|
+
render: renderClaudeAgent,
|
|
13
|
+
},
|
|
14
|
+
opencode: {
|
|
15
|
+
dir: '.opencode/agent',
|
|
16
|
+
fileName: (name) => `${name}.md`,
|
|
17
|
+
render: renderOpenCodeAgent,
|
|
18
|
+
},
|
|
19
|
+
agents: {
|
|
20
|
+
dir: '.agents/agents',
|
|
21
|
+
fileName: (name) => `${name}.md`,
|
|
22
|
+
render: renderFallbackAgent,
|
|
23
|
+
},
|
|
24
|
+
copilot: {
|
|
25
|
+
dir: '.github/agents',
|
|
26
|
+
fileName: (name) => `${name}.agent.md`,
|
|
27
|
+
render: renderCopilotAgent,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const LEGACY_AGENT_TARGETS = {
|
|
32
|
+
copilot: {
|
|
33
|
+
dir: '.github/copilot/agents',
|
|
34
|
+
fileName: (name) => `${name}.agent.md`,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const REQUIRED_AGENT_FIELDS = [
|
|
39
|
+
'name',
|
|
40
|
+
'module',
|
|
41
|
+
'description',
|
|
42
|
+
'mode',
|
|
43
|
+
'context_mode',
|
|
44
|
+
'tool_policy',
|
|
45
|
+
'max_turns',
|
|
46
|
+
'input_budget_words',
|
|
47
|
+
'output_budget_words',
|
|
48
|
+
'parallel_safe',
|
|
49
|
+
'handoff_required',
|
|
50
|
+
'skill_policy',
|
|
51
|
+
'recommended_for',
|
|
52
|
+
'avoid_when',
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
function readAgentRegistry() {
|
|
56
|
+
const registry = readJson(REGISTRY_PATH, null);
|
|
57
|
+
if (!registry || !Array.isArray(registry.agents)) {
|
|
58
|
+
throw new Error('Invalid scaffold/agent-registry.json');
|
|
59
|
+
}
|
|
60
|
+
return registry;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function validateAgentRegistry(registry = readAgentRegistry()) {
|
|
64
|
+
const issues = [];
|
|
65
|
+
const warnings = [];
|
|
66
|
+
if (registry.schema_version !== '2.0') {
|
|
67
|
+
issues.push('Agent registry must use schema_version 2.0.');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const names = new Set();
|
|
71
|
+
for (const agent of registry.agents || []) {
|
|
72
|
+
for (const field of REQUIRED_AGENT_FIELDS) {
|
|
73
|
+
if (agent[field] === undefined || agent[field] === null || agent[field] === '') {
|
|
74
|
+
issues.push(`Agent ${agent.name || '<unnamed>'} is missing required field: ${field}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (names.has(agent.name)) issues.push(`Duplicate agent name: ${agent.name}`);
|
|
78
|
+
names.add(agent.name);
|
|
79
|
+
|
|
80
|
+
if (!Array.isArray(agent.recommended_for)) {
|
|
81
|
+
issues.push(`Agent ${agent.name} recommended_for must be an array.`);
|
|
82
|
+
}
|
|
83
|
+
if (!Array.isArray(agent.avoid_when)) {
|
|
84
|
+
issues.push(`Agent ${agent.name} avoid_when must be an array.`);
|
|
85
|
+
}
|
|
86
|
+
if (agent.mode === 'read-only' && agent.tool_policy !== 'read-only') {
|
|
87
|
+
issues.push(`Read-only agent ${agent.name} must use tool_policy read-only.`);
|
|
88
|
+
}
|
|
89
|
+
if (agent.output_budget_words > 1500) {
|
|
90
|
+
warnings.push(`Agent ${agent.name} output budget is above 1500 words.`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (const [commandName, agents] of Object.entries(registry.commands || {})) {
|
|
95
|
+
if (!Array.isArray(agents)) {
|
|
96
|
+
issues.push(`Agent registry command ${commandName} must map to an array.`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
for (const agentName of agents) {
|
|
100
|
+
if (!names.has(agentName)) issues.push(`Agent registry references missing agent: ${agentName}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { issues, warnings };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function selectAgents(modules) {
|
|
108
|
+
const registry = readAgentRegistry();
|
|
109
|
+
const validation = validateAgentRegistry(registry);
|
|
110
|
+
if (validation.issues.length) {
|
|
111
|
+
throw new Error(`Invalid scaffold/agent-registry.json:\n- ${validation.issues.join('\n- ')}`);
|
|
112
|
+
}
|
|
113
|
+
const selectedModules = new Set(modules || []);
|
|
114
|
+
return registry.agents.filter((agent) => selectedModules.has(agent.module));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function generateAgents(projectRoot, modules, force = false) {
|
|
118
|
+
const results = { created: 0, skipped: 0, overwritten: 0, files: [] };
|
|
119
|
+
const agents = selectAgents(modules);
|
|
120
|
+
|
|
121
|
+
if (force) removeLegacyAgentTargets(projectRoot, agents);
|
|
122
|
+
|
|
123
|
+
for (const agent of agents) {
|
|
124
|
+
const source = readAgentSource(agent);
|
|
125
|
+
for (const target of Object.values(AGENT_TARGETS)) {
|
|
126
|
+
const dest = path.join(projectRoot, target.dir, target.fileName(agent.name));
|
|
127
|
+
const status = writeFile(dest, target.render(agent, source), force);
|
|
128
|
+
results[status]++;
|
|
129
|
+
results.files.push(dest);
|
|
130
|
+
log(status, dest);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
writeAgentIndex(projectRoot, agents, force);
|
|
135
|
+
const indexPath = path.join(projectRoot, '.agents', 'agents', 'README.md');
|
|
136
|
+
results.files.push(indexPath);
|
|
137
|
+
|
|
138
|
+
return results;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function readAgentSource(agent) {
|
|
142
|
+
const src = path.join(SCAFFOLD_DIR, 'agents', agent.module, `${agent.name}.md`);
|
|
143
|
+
if (!fs.existsSync(src)) {
|
|
144
|
+
throw new Error(`Agent source missing: ${path.relative(process.cwd(), src)}`);
|
|
145
|
+
}
|
|
146
|
+
const raw = fs.readFileSync(src, 'utf-8');
|
|
147
|
+
const parsed = parseMarkdownFrontmatter(raw);
|
|
148
|
+
return {
|
|
149
|
+
path: src,
|
|
150
|
+
metadata: parsed.metadata,
|
|
151
|
+
body: parsed.body.trim(),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function parseMarkdownFrontmatter(raw) {
|
|
156
|
+
if (!raw.startsWith('---\n')) return { metadata: {}, body: raw };
|
|
157
|
+
const end = raw.indexOf('\n---', 4);
|
|
158
|
+
if (end === -1) return { metadata: {}, body: raw };
|
|
159
|
+
const metadata = {};
|
|
160
|
+
const frontmatter = raw.slice(4, end).trim();
|
|
161
|
+
for (const line of frontmatter.split('\n')) {
|
|
162
|
+
const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
163
|
+
if (!match) continue;
|
|
164
|
+
metadata[match[1]] = match[2].replace(/^["']|["']$/g, '');
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
metadata,
|
|
168
|
+
body: raw.slice(end + 4).replace(/^\s+/, ''),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function renderClaudeAgent(agent, source) {
|
|
173
|
+
const tools = claudeToolsFor(agent, source);
|
|
174
|
+
const lines = [
|
|
175
|
+
'---',
|
|
176
|
+
`name: ${agent.name}`,
|
|
177
|
+
`description: "${yamlString(agent.description)}"`,
|
|
178
|
+
`tools: ${tools.join(', ')}`,
|
|
179
|
+
`model: ${source.metadata.model || 'sonnet'}`,
|
|
180
|
+
`permissionMode: ${agent.tool_policy === 'read-only' ? 'plan' : 'default'}`,
|
|
181
|
+
`maxTurns: ${agent.max_turns}`,
|
|
182
|
+
'---',
|
|
183
|
+
'',
|
|
184
|
+
renderContract(agent, 'Claude Code project subagent'),
|
|
185
|
+
'',
|
|
186
|
+
source.body,
|
|
187
|
+
'',
|
|
188
|
+
];
|
|
189
|
+
return lines.join('\n');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function renderOpenCodeAgent(agent, source) {
|
|
193
|
+
const canWrite = agent.tool_policy !== 'read-only';
|
|
194
|
+
const lines = [
|
|
195
|
+
'---',
|
|
196
|
+
'mode: subagent',
|
|
197
|
+
`description: "${yamlString(agent.description)}"`,
|
|
198
|
+
`steps: ${agent.max_turns}`,
|
|
199
|
+
'permission:',
|
|
200
|
+
` edit: ${canWrite ? 'allow' : 'deny'}`,
|
|
201
|
+
` write: ${canWrite ? 'allow' : 'deny'}`,
|
|
202
|
+
` bash: ${agent.tool_policy === 'read-only' ? 'deny' : 'allow'}`,
|
|
203
|
+
'---',
|
|
204
|
+
'',
|
|
205
|
+
renderContract(agent, 'OpenCode project subagent'),
|
|
206
|
+
'',
|
|
207
|
+
source.body,
|
|
208
|
+
'',
|
|
209
|
+
];
|
|
210
|
+
return lines.join('\n');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function renderCopilotAgent(agent, source) {
|
|
214
|
+
const tools = copilotToolsFor(agent);
|
|
215
|
+
const lines = [
|
|
216
|
+
'---',
|
|
217
|
+
`name: ${agent.name}`,
|
|
218
|
+
`description: "${yamlString(agent.description)}"`,
|
|
219
|
+
`tools: ${tools.join(', ')}`,
|
|
220
|
+
'---',
|
|
221
|
+
'',
|
|
222
|
+
renderContract(agent, 'GitHub Copilot custom agent'),
|
|
223
|
+
'',
|
|
224
|
+
source.body,
|
|
225
|
+
'',
|
|
226
|
+
];
|
|
227
|
+
return lines.join('\n');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function renderFallbackAgent(agent, source) {
|
|
231
|
+
const lines = [
|
|
232
|
+
'---',
|
|
233
|
+
`name: ${agent.name}`,
|
|
234
|
+
`description: "${yamlString(agent.description)}"`,
|
|
235
|
+
`mode: ${agent.mode}`,
|
|
236
|
+
`context_mode: ${agent.context_mode}`,
|
|
237
|
+
`tool_policy: ${agent.tool_policy}`,
|
|
238
|
+
`max_turns: ${agent.max_turns}`,
|
|
239
|
+
`input_budget_words: ${agent.input_budget_words}`,
|
|
240
|
+
`output_budget_words: ${agent.output_budget_words}`,
|
|
241
|
+
`parallel_safe: ${agent.parallel_safe}`,
|
|
242
|
+
'---',
|
|
243
|
+
'',
|
|
244
|
+
renderContract(agent, 'Fallback prompt profile'),
|
|
245
|
+
'',
|
|
246
|
+
source.body,
|
|
247
|
+
'',
|
|
248
|
+
];
|
|
249
|
+
return lines.join('\n');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function renderContract(agent, targetLabel) {
|
|
253
|
+
return [
|
|
254
|
+
`# ${agent.name}`,
|
|
255
|
+
'',
|
|
256
|
+
`Provider target: ${targetLabel}.`,
|
|
257
|
+
'',
|
|
258
|
+
'## Dispatch Contract',
|
|
259
|
+
'',
|
|
260
|
+
`- Context mode: \`${agent.context_mode}\`.`,
|
|
261
|
+
`- Tool policy: \`${agent.tool_policy}\`.`,
|
|
262
|
+
`- Max turns: ${agent.max_turns}.`,
|
|
263
|
+
`- Input budget: ${agent.input_budget_words} words.`,
|
|
264
|
+
`- Output budget: ${agent.output_budget_words} words.`,
|
|
265
|
+
`- Parallel safe: ${agent.parallel_safe ? 'yes' : 'no'}.`,
|
|
266
|
+
`- Handoff required: ${agent.handoff_required ? 'yes' : 'no'}.`,
|
|
267
|
+
`- Skill policy: \`${agent.skill_policy}\`; do not preload large skills.`,
|
|
268
|
+
'',
|
|
269
|
+
'## Use When',
|
|
270
|
+
...agent.recommended_for.map((item) => `- ${item}.`),
|
|
271
|
+
'',
|
|
272
|
+
'## Do Not Use When',
|
|
273
|
+
...agent.avoid_when.map((item) => `- ${item}.`),
|
|
274
|
+
'',
|
|
275
|
+
'## Input Packet Expected',
|
|
276
|
+
'',
|
|
277
|
+
'- Objective and stop condition.',
|
|
278
|
+
'- Allowed files, folders, commands, and write boundaries.',
|
|
279
|
+
'- Relevant constraints from `.dw/rules/`, `.dw/intel/`, or the parent session.',
|
|
280
|
+
'- Expected return packet shape and verification command, when applicable.',
|
|
281
|
+
'',
|
|
282
|
+
'## Context Rules',
|
|
283
|
+
'',
|
|
284
|
+
'- Do not request or paste the full parent transcript.',
|
|
285
|
+
'- Read only the files needed for the objective.',
|
|
286
|
+
'- Summarize logs; include only failing lines, paths, commands, and decisions.',
|
|
287
|
+
'',
|
|
288
|
+
'## Tool/Write Boundaries',
|
|
289
|
+
'',
|
|
290
|
+
toolBoundary(agent),
|
|
291
|
+
'',
|
|
292
|
+
'## Return Packet',
|
|
293
|
+
'',
|
|
294
|
+
'- Result: pass, findings, changed files, or blocked.',
|
|
295
|
+
'- Files read and files changed.',
|
|
296
|
+
'- Decisions made and risks that remain.',
|
|
297
|
+
'- Verification run, including command and outcome.',
|
|
298
|
+
'- Recommended next step for the parent session.',
|
|
299
|
+
'',
|
|
300
|
+
'## Stop Conditions',
|
|
301
|
+
'',
|
|
302
|
+
'- Stop when the requested packet is complete.',
|
|
303
|
+
'- Stop if required context exceeds the input budget.',
|
|
304
|
+
'- Stop if the task needs broader architecture, product, or permission decisions.',
|
|
305
|
+
].join('\n');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function toolBoundary(agent) {
|
|
309
|
+
if (agent.tool_policy === 'read-only') {
|
|
310
|
+
return '- Read-only. Do not edit, write, delete, or format files.';
|
|
311
|
+
}
|
|
312
|
+
if (agent.tool_policy === 'qa-write') {
|
|
313
|
+
return '- Write only QA artifacts, test scripts, traces, screenshots, and reports unless the parent explicitly assigns a fix.';
|
|
314
|
+
}
|
|
315
|
+
if (agent.tool_policy === 'shell-limited') {
|
|
316
|
+
return '- Shell commands are allowed only for inspection and targeted verification. Do not edit files unless explicitly assigned.';
|
|
317
|
+
}
|
|
318
|
+
return '- Edits are allowed only inside the files or module boundaries named in the input packet.';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function claudeToolsFor(agent, source) {
|
|
322
|
+
if (source.metadata.tools) {
|
|
323
|
+
return source.metadata.tools.split(',').map((tool) => tool.trim()).filter(Boolean);
|
|
324
|
+
}
|
|
325
|
+
return agent.tool_policy === 'read-only'
|
|
326
|
+
? ['Read', 'Grep', 'Glob']
|
|
327
|
+
: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob'];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function copilotToolsFor(agent) {
|
|
331
|
+
return agent.tool_policy === 'read-only'
|
|
332
|
+
? ['read', 'grep']
|
|
333
|
+
: ['read', 'edit', 'terminal'];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function yamlString(value) {
|
|
337
|
+
return String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function writeAgentIndex(projectRoot, agents, force) {
|
|
341
|
+
const lines = [
|
|
342
|
+
'# dev-workflow Agents',
|
|
343
|
+
'',
|
|
344
|
+
'These files are fallback prompt profiles for harnesses that do not expose native project subagents.',
|
|
345
|
+
'Claude Code uses `.claude/agents/`; OpenCode uses `.opencode/agent/`; Copilot receives `.github/agents/*.agent.md`.',
|
|
346
|
+
'Codex should treat this directory as delegable profiles when subagents are available, or as a manual prompt pack otherwise.',
|
|
347
|
+
'',
|
|
348
|
+
'| Agent | Module | Mode | Context | Output Budget | Purpose |',
|
|
349
|
+
'|---|---|---|---|---:|---|',
|
|
350
|
+
];
|
|
351
|
+
|
|
352
|
+
for (const agent of agents) {
|
|
353
|
+
lines.push(`| \`${agent.name}\` | \`${agent.module}\` | \`${agent.mode}\` | \`${agent.context_mode}\` | ${agent.output_budget_words} words | ${agent.description} |`);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const content = lines.join('\n') + '\n';
|
|
357
|
+
writeFile(path.join(projectRoot, '.agents', 'agents', 'README.md'), content, force);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function listExpectedAgentFiles(projectRoot, modules) {
|
|
361
|
+
const files = [];
|
|
362
|
+
for (const agent of selectAgents(modules)) {
|
|
363
|
+
for (const target of Object.values(AGENT_TARGETS)) {
|
|
364
|
+
files.push(path.join(projectRoot, target.dir, target.fileName(agent.name)));
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
files.push(path.join(projectRoot, '.agents', 'agents', 'README.md'));
|
|
368
|
+
return files;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function listLegacyAgentFiles(projectRoot, modules) {
|
|
372
|
+
const files = [];
|
|
373
|
+
for (const agent of selectAgents(modules)) {
|
|
374
|
+
for (const target of Object.values(LEGACY_AGENT_TARGETS)) {
|
|
375
|
+
files.push(path.join(projectRoot, target.dir, target.fileName(agent.name)));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return files;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function ensureAgentDirs(projectRoot) {
|
|
382
|
+
for (const target of Object.values(AGENT_TARGETS)) {
|
|
383
|
+
ensureDir(path.join(projectRoot, target.dir));
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function removeLegacyAgentTargets(projectRoot, agents) {
|
|
388
|
+
for (const target of Object.values(LEGACY_AGENT_TARGETS)) {
|
|
389
|
+
for (const agent of agents) {
|
|
390
|
+
const file = path.join(projectRoot, target.dir, target.fileName(agent.name));
|
|
391
|
+
if (fs.existsSync(file)) fs.rmSync(file);
|
|
392
|
+
}
|
|
393
|
+
const dir = path.join(projectRoot, target.dir);
|
|
394
|
+
if (fs.existsSync(dir) && fs.readdirSync(dir).length === 0) {
|
|
395
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
module.exports = {
|
|
401
|
+
AGENT_TARGETS,
|
|
402
|
+
LEGACY_AGENT_TARGETS,
|
|
403
|
+
readAgentRegistry,
|
|
404
|
+
validateAgentRegistry,
|
|
405
|
+
selectAgents,
|
|
406
|
+
generateAgents,
|
|
407
|
+
listExpectedAgentFiles,
|
|
408
|
+
listLegacyAgentFiles,
|
|
409
|
+
ensureAgentDirs,
|
|
410
|
+
};
|