dw-kit 1.3.6 → 1.6.0-rc.1
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/executor.md +80 -80
- package/.claude/hooks/pre-commit-gate.sh +59 -0
- package/.claude/hooks/stop-check.sh +111 -31
- package/.claude/rules/commit-standards.md +48 -37
- package/.claude/rules/dw.md +47 -11
- package/.claude/skills/dw-archive/SKILL.md +14 -0
- package/.claude/skills/dw-commit/SKILL.md +7 -4
- package/.claude/skills/dw-decision/SKILL.md +5 -4
- package/.claude/skills/dw-execute/SKILL.md +18 -5
- package/.claude/skills/dw-handoff/SKILL.md +8 -3
- package/.claude/skills/dw-plan/SKILL.md +15 -2
- package/.claude/skills/dw-research/SKILL.md +7 -5
- package/.claude/skills/dw-retroactive/SKILL.md +75 -63
- package/.claude/skills/dw-review/SKILL.md +33 -2
- package/.claude/skills/dw-task-init/SKILL.md +40 -35
- package/.dw/adapters/generic/AGENT.md +171 -169
- package/.dw/config/config.schema.json +149 -121
- package/.dw/config/dw.config.yml +14 -0
- package/.dw/core/WORKFLOW.md +450 -450
- package/.dw/core/schemas/agent-claim.schema.json +127 -0
- package/.dw/core/schemas/agent-report.schema.json +72 -0
- package/.dw/core/schemas/task-frontmatter.schema.json +78 -0
- package/.dw/core/templates/v3/task.md +188 -0
- package/CLAUDE.md +2 -2
- package/MIGRATION-v1.5.md +330 -0
- package/README.md +18 -0
- package/package.json +4 -2
- package/src/cli.mjs +176 -0
- package/src/commands/agent-claim.mjs +235 -0
- package/src/commands/agent-inspect.mjs +123 -0
- package/src/commands/doctor.mjs +105 -1
- package/src/commands/lint-task.mjs +112 -0
- package/src/commands/review-render.mjs +255 -0
- package/src/commands/task-migrate.mjs +366 -0
- package/src/commands/task-new.mjs +90 -0
- package/src/commands/task-render.mjs +235 -0
- package/src/commands/task-rotate.mjs +168 -0
- package/src/commands/task-show.mjs +137 -0
- package/src/commands/task-view.mjs +386 -0
- package/src/commands/task-watch.mjs +223 -0
- package/src/lib/active-index.mjs +19 -1
- package/src/lib/agent-claim.mjs +173 -0
- package/src/lib/agent-conflict.mjs +137 -0
- package/src/lib/agent-events.mjs +43 -0
- package/src/lib/agent-report.mjs +96 -0
- package/src/lib/config.mjs +120 -104
- package/src/lib/frontmatter.mjs +72 -0
- package/src/lib/lint-rules.mjs +149 -0
- package/src/lib/review/manifest-schema.json +149 -0
- package/src/lib/review/manifest-validator.mjs +93 -0
- package/src/lib/review/scope-slug.mjs +68 -0
- package/src/lib/timeline-parser.mjs +80 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# Migration Guide — dw-kit v1.3/v1.4 → v1.5
|
|
2
|
+
|
|
3
|
+
**Status:** In active development (per ADR-0008)
|
|
4
|
+
**Breaking change:** Task docs format default switches from v2 (2-file) to v3 (1-file `task.md`).
|
|
5
|
+
**Backward compat:** v2 + v1 read paths preserved. Migration is opt-in per task via `dw task migrate`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## At a Glance
|
|
10
|
+
|
|
11
|
+
| Area | Change | Impact |
|
|
12
|
+
|------|--------|--------|
|
|
13
|
+
| Task docs | New v3 single-file `task.md` (replaces v2 `spec.md` + `tracking.md`) | **Default for new tasks** — old tasks read-compat |
|
|
14
|
+
| Frontmatter | JSON-schema validated (ajv) via `.dw/core/schemas/task-frontmatter.schema.json` | Strict on save (per lint) |
|
|
15
|
+
| CLI | New `dw task` family: `show`, `new`, `migrate`, `lint`, `rotate` | New surface |
|
|
16
|
+
| Lint | `dw task lint` default `strict` — blocks drift markers in Section 2, line caps, schema | Opt-out via `task_lint: off` in `dw.config.yml` |
|
|
17
|
+
| Hook | `stop-check` now auto-rotates Section 4 > 400 lines → `timeline-history.md` + nudges `dw task show` | Automatic |
|
|
18
|
+
| Indexer | `active-index.mjs` reads v3 first, falls back to v2 / v1 | Backward compatible |
|
|
19
|
+
| Skills | 7 skills updated for v3 (task-init / execute / handoff / research / plan / decision / retroactive) | Auto-detect format |
|
|
20
|
+
| Migration backups | v2 spec.md / tracking.md preserved as `.v2bak` (gitignored) | Reversible via `--rollback` |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## The Drift Problem (Motivation)
|
|
25
|
+
|
|
26
|
+
Per ADR-0008 evidence:
|
|
27
|
+
|
|
28
|
+
- `dw-kit-v2-lean-optimization` task accumulated **1081 lines** across `spec.md` (227) + `tracking.md` (615) + ad-hoc `baseline.md` (89) + `execution-log.md` (150) — variance crossed beyond what the v2 template was designed for.
|
|
29
|
+
- Status markers leaked into `spec.md` ("✅ COMPLETED 2026-04-21" inline) while `tracking.md` had its own "Subtask Progress" table → **two sources of truth for the same field**.
|
|
30
|
+
- TechLead reviewer reported "rối, lười đọc" (cluttered, skipped) when reviewing v2 layouts.
|
|
31
|
+
|
|
32
|
+
v3 fixes structurally:
|
|
33
|
+
|
|
34
|
+
- **Single source of truth:** `task.md` contains Snapshot + Intent + Tracker + Changelog + Handoff in one file.
|
|
35
|
+
- **No drift surface:** there is no second file to paste status into. Lint enforces "status lives only in Section 3".
|
|
36
|
+
- **Bounded preview:** `timeline.svg` sidecar (when rendered) is fixed composition (~10-20KB) regardless of task lifetime.
|
|
37
|
+
- **Auto-rotation:** Section 4 (Changelog) overflow above 400 lines → `timeline-history.md` via `stop-check` hook.
|
|
38
|
+
|
|
39
|
+
Trade-off: cross-repo migration of existing v2 tasks. Tooling provided.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## New Format — `task.md` v3
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
.dw/tasks/{name}/
|
|
47
|
+
├── task.md # canonical SoT (Sections 1-5 + optional 6 Debate)
|
|
48
|
+
└── (free-form supplements — indexer ignores; lint warns on generic names):
|
|
49
|
+
├── baseline.md # benchmark snapshots
|
|
50
|
+
├── experiment-{id}.md # spike notes
|
|
51
|
+
├── debate-r{N}.md # extended adversarial logs
|
|
52
|
+
└── timeline-history.md # auto-rotated changelog overflow
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Section structure:**
|
|
56
|
+
|
|
57
|
+
| # | Section | Purpose | Lint rule |
|
|
58
|
+
|---|---------|---------|-----------|
|
|
59
|
+
| 1 | Snapshot | Always-visible ≤15-line header for fast scan | — |
|
|
60
|
+
| 2 | Intent & Scope | Stable intent, Subtasks list, Out of Scope, Success Criteria, Dependencies, Risk Register | **No status markers** (✅🟡 trigger error); line cap 200 |
|
|
61
|
+
| 3 | Subtask Tracker | Single source of truth for ST status | Status legend required; line cap 80 |
|
|
62
|
+
| 4 | Timeline / Changelog | Reverse-chronological session log | Auto-rotate > 400 lines |
|
|
63
|
+
| 5 | Handoff & Friction | For-next-session + friction journal | — |
|
|
64
|
+
| 6 | Annexes | List of supplementary files | — |
|
|
65
|
+
| 7 | Debate Log (optional) | Thorough-depth red/blue adversarial output | — |
|
|
66
|
+
|
|
67
|
+
**Frontmatter schema** (`.dw/core/schemas/task-frontmatter.schema.json`):
|
|
68
|
+
|
|
69
|
+
Required: `task_id`, `created`, `last_updated`, `status`, `owner`, `depth`, `schema_version` (= `v3.0`).
|
|
70
|
+
Optional: `phase`, `related_adr`, `target_ship`, `blockers`.
|
|
71
|
+
`status` enum: Draft | Approved | In Progress | Blocked | Paused | Done.
|
|
72
|
+
`depth` enum: quick | standard | thorough.
|
|
73
|
+
`related_adr` pattern: `ADR-NNNN` or `none`.
|
|
74
|
+
|
|
75
|
+
`additionalProperties: false` — typo fields rejected (drift prevention).
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## CLI Reference
|
|
80
|
+
|
|
81
|
+
### `dw task new <name> [options]`
|
|
82
|
+
|
|
83
|
+
Scaffold new v3 task from template.
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
dw task new my-feature --depth standard --title "My feature" --adr ADR-0008
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Writes `.dw/tasks/my-feature/task.md` with filled frontmatter + Section skeletons.
|
|
90
|
+
|
|
91
|
+
### `dw task show [name] [-v]`
|
|
92
|
+
|
|
93
|
+
ANSI terminal snapshot of Section 1 + Section 3.
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
dw task show # auto-pick most recent v3 task
|
|
97
|
+
dw task show my-feature # specific task
|
|
98
|
+
dw task show -v # include Section 1 body
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `dw task lint [name] [-l level]`
|
|
102
|
+
|
|
103
|
+
Schema validate + drift marker scan + line caps + appendage name check.
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
dw task lint # lint all v3 tasks
|
|
107
|
+
dw task lint my-feature # single task
|
|
108
|
+
dw task lint -l warn # downgrade errors to warnings
|
|
109
|
+
DW_NO_TELEMETRY=1 dw task lint # skip telemetry events
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Default level: `strict` (errors → exit 1). Override via `dw.config.yml`:
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
task:
|
|
116
|
+
lint: strict # strict | warn | off
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Or legacy flat key:
|
|
120
|
+
```yaml
|
|
121
|
+
task_lint: strict
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Solo preset → `off`. Enterprise → `strict`.
|
|
125
|
+
|
|
126
|
+
### `dw task migrate [name] [flags]`
|
|
127
|
+
|
|
128
|
+
Migrate v2 `spec.md` + `tracking.md` → v3 `task.md`.
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
dw task migrate my-task --dry-run # preview without writing
|
|
132
|
+
dw task migrate my-task --diff # diff against existing task.md
|
|
133
|
+
dw task migrate my-task # apply (creates .v2bak backups)
|
|
134
|
+
dw task migrate --all --dry-run # preview all v2 tasks
|
|
135
|
+
dw task migrate --all # apply to all v2 tasks
|
|
136
|
+
dw task migrate my-task --rollback # restore from .v2bak
|
|
137
|
+
dw task migrate my-task --force # overwrite existing v3
|
|
138
|
+
dw task migrate my-task --remove-v2 # delete spec.md/tracking.md after migration (default keeps them)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Migration mapping:**
|
|
142
|
+
|
|
143
|
+
| v2 source | v3 destination |
|
|
144
|
+
|-----------|----------------|
|
|
145
|
+
| `spec.md` Intent + Why Now | Section 2 → Intent + Why Now |
|
|
146
|
+
| `spec.md` Scope → In Scope | Section 2 → Subtasks (status markers stripped) |
|
|
147
|
+
| `spec.md` Out of Scope | Section 2 → Out of Scope |
|
|
148
|
+
| `spec.md` Success Criteria | Section 2 → Success Criteria |
|
|
149
|
+
| `spec.md` Risks & Mitigations | Section 2 → Risk Register |
|
|
150
|
+
| `spec.md` Dependencies | Section 2 → Dependencies |
|
|
151
|
+
| `tracking.md` Status Snapshot | Section 1 |
|
|
152
|
+
| `tracking.md` Subtask Progress | Section 3 Subtask Tracker |
|
|
153
|
+
| `tracking.md` Changelog | Section 4 Timeline/Changelog |
|
|
154
|
+
| `tracking.md` Handoff Notes | Section 5 |
|
|
155
|
+
| `tracking.md` Friction Journal | Section 5 (Friction subsection) |
|
|
156
|
+
| `tracking.md` Agent Debate Log | Section 7 (if present) |
|
|
157
|
+
| Merged frontmatter | v3 frontmatter (status auto-normalized to enum) |
|
|
158
|
+
|
|
159
|
+
**Status normalization:** v2 freeform status (e.g., "v1.3.0 Verified Ship-Ready (audit passed)") maps to nearest v3 enum value via keyword priority: Blocked > Done > Paused > In Progress > Approved > Draft.
|
|
160
|
+
|
|
161
|
+
**Backups:** `spec.md` → `spec.md.v2bak`, `tracking.md` → `tracking.md.v2bak`. Both gitignored. Use `--rollback` to restore.
|
|
162
|
+
|
|
163
|
+
### `dw task rotate [name] [-n] [-q]`
|
|
164
|
+
|
|
165
|
+
Auto-rotate Section 4 (Timeline/Changelog) > 400 lines into `timeline-history.md`. Keeps last 8 entries in `task.md`. Idempotent. Invoked automatically by `stop-check` hook.
|
|
166
|
+
|
|
167
|
+
### `dw task render [name] [-n] [-f svg|png|svg,png] [--mermaid-only]`
|
|
168
|
+
|
|
169
|
+
Render `timeline.svg` sidecar from manifest via `dw-kit-render` sub-package. SVG is bounded composition (status card + Subtask Gantt + status transition strip) ~200-465KB per task. Gitignored by default (opt-in commit cho GitHub inline preview). Falls back to Mermaid Gantt block injection in Section 4 if sub-package absent.
|
|
170
|
+
|
|
171
|
+
### `dw task view [name] [--no-open]`
|
|
172
|
+
|
|
173
|
+
Render full interactive HTML preview at `.dw/cache/preview/{task}.html` and open in browser. **Primary surface for human dev orchestrator tracking subtasks.** Self-contained (CSS + JS inlined, no CDN deps). Features:
|
|
174
|
+
|
|
175
|
+
- **Sticky snapshot card** (always visible): status badge + key meta + blocker banner + progress stats (✅/🟡/🔴/⬜ counts + percentage bar).
|
|
176
|
+
- **Sidebar navigation** with section anchors + search box (filter sections by keyword).
|
|
177
|
+
- **Sections rendered as proper HTML**: headings, tables, code blocks (Mermaid blocks render as text but visible), bullet/numbered lists, blockquotes.
|
|
178
|
+
- **Collapsible H2 sections** (click heading to fold).
|
|
179
|
+
- **Dark/light theme** via `prefers-color-scheme`.
|
|
180
|
+
|
|
181
|
+
Gitignored output (`.dw/cache/preview/`). Regenerates on each invocation — no caching.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Migration Steps for Existing Projects
|
|
186
|
+
|
|
187
|
+
### 1. Backup (recommended)
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
git checkout -b task-migrate-v3
|
|
191
|
+
git status # confirm clean
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 2. Preview migration
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
dw task migrate --all --dry-run
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Review proposed v3 output. Status normalization, section mapping, and frontmatter merge are shown.
|
|
201
|
+
|
|
202
|
+
### 3. Apply per-task with diff
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
dw task migrate task-1 --diff # if already migrated, show diff vs existing
|
|
206
|
+
dw task migrate task-1 # apply
|
|
207
|
+
dw task lint task-1 # verify clean
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Repeat for each task. Or batch:
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
dw task migrate --all
|
|
214
|
+
dw task lint # verify all
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 4. Refresh ACTIVE.md
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
dw active
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 5. Commit
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
git add .dw/tasks/
|
|
227
|
+
git commit -m "chore(tasks): migrate v2 spec+tracking to v3 timeline (ADR-0008)"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`.v2bak` files are gitignored — they stay locally for rollback if needed.
|
|
231
|
+
|
|
232
|
+
### 6. Rollback path (if needed)
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
dw task migrate task-1 --rollback
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Restores v2 files from `.v2bak`, deletes v3 `task.md`. ACTIVE.md falls back to reading `tracking.md`.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Breaking Changes
|
|
243
|
+
|
|
244
|
+
### 1. `dw active` v3 precedence
|
|
245
|
+
|
|
246
|
+
If both `task.md` and `tracking.md` exist in a task folder, **v3 wins**. To force v2 read during migration, delete `task.md` temporarily.
|
|
247
|
+
|
|
248
|
+
### 2. Lint default strict
|
|
249
|
+
|
|
250
|
+
`dw task lint` exits non-zero on any error (drift markers, schema violations). To run advisory-only:
|
|
251
|
+
|
|
252
|
+
```yaml
|
|
253
|
+
# .dw/config/dw.config.yml
|
|
254
|
+
task:
|
|
255
|
+
lint: warn # or "off"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### 3. Section 2 drift-marker enforcement
|
|
259
|
+
|
|
260
|
+
Pasting status markers (`✅ COMPLETED 2026-04-21`, `🟡 IN PROGRESS`, `Status: Done`) anywhere in Section 2 → lint error. Status only in Section 3 (Subtask Tracker). Backtick-quoted examples (e.g., discussing drift in docs) are skipped by lint.
|
|
261
|
+
|
|
262
|
+
### 4. Generic appendage names → warning
|
|
263
|
+
|
|
264
|
+
Files named `notes.md`, `extra.md`, `wip.md`, etc. in task folders → lint warning. Prefer specific names: `baseline.md`, `experiment-{id}.md`, `debate-r{N}.md`.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## SVG Preview (Deferred to v1.6+)
|
|
269
|
+
|
|
270
|
+
Per ADR-0008 Option H, `task.md` references an inline `timeline.svg` sidecar that GitHub markdown viewer renders inline for human casual preview. The full render pipeline (extends ADR-0007 `dw-kit-render` sub-package) lands in v1.6 telemetry-gated.
|
|
271
|
+
|
|
272
|
+
For v1.5: the SVG reference is comment-suppressed in templates (`<!--  -->`) so no broken-image icons appear in GitHub PR view. Mermaid Gantt + timeline blocks in Section 4 provide native GitHub-rendered fallback visualization.
|
|
273
|
+
|
|
274
|
+
When v1.6 ships:
|
|
275
|
+
- `dw task render <name>` produces `timeline.svg` (deterministic XML, ~10-20KB).
|
|
276
|
+
- `stop-check` + `pre-commit` hooks auto-regenerate on session end / commit.
|
|
277
|
+
- Template comment markers around the image ref are removed → inline render activates.
|
|
278
|
+
- Optional `dw task view` opens interactive HTML in browser.
|
|
279
|
+
- Optional `dw task watch` daemon for live preview during pair-with-agent dev.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Telemetry
|
|
284
|
+
|
|
285
|
+
New events (under `event: 'task'`):
|
|
286
|
+
|
|
287
|
+
- `task.show.invoke`
|
|
288
|
+
- `task.new`
|
|
289
|
+
- `task.migrate.run` / `task.migrate.rollback`
|
|
290
|
+
- `task.lint.run` / `task.lint.violation`
|
|
291
|
+
- `task.rotate.run`
|
|
292
|
+
|
|
293
|
+
Inspected via `dw metrics show` (under "Task actions" bucket). Local-only, opt-out via `DW_NO_TELEMETRY=1`.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Skills Updated
|
|
298
|
+
|
|
299
|
+
7 skills now v3-aware (task.md preferred, v2 + v1 read-compat):
|
|
300
|
+
|
|
301
|
+
- `/dw:task-init` — defaults to `dw task new`; falls back to template fill.
|
|
302
|
+
- `/dw:execute` — reads task.md Sections 1/2/3; updates Section 3 tracker + Section 4 changelog.
|
|
303
|
+
- `/dw:handoff` — writes to Section 5 (Handoff & Friction).
|
|
304
|
+
- `/dw:research` — appends Research Findings subsection to Section 2.
|
|
305
|
+
- `/dw:plan` — fills Section 2 subsections; promotes status Draft → Approved.
|
|
306
|
+
- `/dw:decision` — cross-links ADR to task.md frontmatter + Changelog.
|
|
307
|
+
- `/dw:retroactive` — generates As-Built task.md from code + git history.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Sunset Plan for v2
|
|
312
|
+
|
|
313
|
+
Per ADR-0008 Open Items:
|
|
314
|
+
|
|
315
|
+
- v2 templates at `.dw/core/templates/v2/` remain for legacy read.
|
|
316
|
+
- 60 days post-v1.5 ship: telemetry review `task.format.read` event distribution.
|
|
317
|
+
- If v2 reads < 5% of v3 reads → propose v2 template removal in v1.7.
|
|
318
|
+
- v2 read code path in `active-index.mjs` and skills stays (cheap to maintain, supports archived tasks).
|
|
319
|
+
|
|
320
|
+
v1 (3-file `context + plan + progress`) read path stays indefinitely (small set of legacy tasks).
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## References
|
|
325
|
+
|
|
326
|
+
- ADR-0008: [.dw/decisions/0008-task-docs-format-one-file-timeline.md](.dw/decisions/0008-task-docs-format-one-file-timeline.md) (full debate, 7 rounds)
|
|
327
|
+
- Bootstrap task: [.dw/tasks/task-docs-v3/task.md](.dw/tasks/task-docs-v3/task.md) (dogfooded v3 format)
|
|
328
|
+
- Template: [.dw/core/templates/v3/task.md](.dw/core/templates/v3/task.md)
|
|
329
|
+
- Schema: [.dw/core/schemas/task-frontmatter.schema.json](.dw/core/schemas/task-frontmatter.schema.json)
|
|
330
|
+
- ADR-0007 (render infrastructure to be reused in v1.6): [.dw/decisions/0007-decoupled-review-render-pipeline.md](.dw/decisions/0007-decoupled-review-render-pipeline.md)
|
package/README.md
CHANGED
|
@@ -36,6 +36,9 @@ It’s designed for collaboration (Dev / Tech Lead / QA / PM) and keeps work aud
|
|
|
36
36
|
|
|
37
37
|
## Release notes
|
|
38
38
|
|
|
39
|
+
- **v1.6.0-rc.1 (current)** — **Agent OS Multi-Agent Orchestration** ([ADR-0009](.dw/decisions/0009-agent-os-multi-agent-orchestration.md)): file-based cooperative protocol for Claude Code / Codex / Gemini / human agents to work from same `task.md` without conflict. 6-command CLI `dw agent *` (claim / release / expire / claims / reports / conflicts). Dual ownership model: `subtasks` (semantic) + `write_scope` (filesystem). Lifecycle states + lease (wall+relative) per Round 2. Audit trail via committed `reports/` + `events.jsonl`; claims gitignored ephemeral. Trust = cooperative, post-hoc conflict detection.
|
|
40
|
+
- **v1.5.0 — Task Docs v3** ([ADR-0008](.dw/decisions/0008-task-docs-format-one-file-timeline.md)): single-file `task.md` replaces v2 `spec.md` + `tracking.md` (drift fixed structurally). 8-command CLI `dw task *` (show / new / view / watch / render / lint / migrate / rotate). Lean HTML dashboard for human dev orchestrator (~10KB, scan-in-5-seconds) + bounded SVG sidecar via `dw-kit-render` v0.2. Live preview server with auto-refresh. Migration script with `--dry-run`, `--diff`, `--rollback`. Lint strict-default blocks drift markers. See [`MIGRATION-v1.5.md`](MIGRATION-v1.5.md).
|
|
41
|
+
- **v1.4 (in progress)** — Optional **Review Render Pipeline** ([ADR-0007](.dw/decisions/0007-decoupled-review-render-pipeline.md)): `/dw:review --visual` plus a separate `dw-kit-render` package turn findings into SVG + PNG cards for PR comments / Slack / stakeholders. Pure JS + WASM, universal `npm install`, no system deps. See [`docs/review-renderer.md`](docs/review-renderer.md).
|
|
39
42
|
- **v1.3.6** (2026-05-14) — Supply-Chain Guard upgraded to 3-pillar architecture: OSV snapshot + curated IoC fixture (version-aware, wired into default scan) + **AI-Native NEW-package heuristic** that catches zero-day-ish risk at the AI-edit boundary. See [`CHANGELOG.md#v136--2026-05-14`](CHANGELOG.md#v136--2026-05-14) and [ADR-0006](.dw/decisions/0006-supply-chain-guard-heuristic.md).
|
|
40
43
|
- v1.3.5 (2026-05-12) — AI-Native Supply-Chain Guard: `dw security-scan` CLI + OSV.dev auto-sync + Edit-lockfile hook + scoped `.gitignore` for end-user projects. See [ADR-0005](.dw/decisions/0005-supply-chain-guard.md). Public 90-day sunset review committed for 2026-08-12.
|
|
41
44
|
- v1.3.4 (2026-04-21) — `/dw:plan` Quick Debate (red/blue self-critique), depth-driven activation
|
|
@@ -45,6 +48,21 @@ It’s designed for collaboration (Dev / Tech Lead / QA / PM) and keeps work aud
|
|
|
45
48
|
- Full changelog: `CHANGELOG.md`
|
|
46
49
|
- Latest release notes: [GitHub Releases](https://github.com/dv-workflow/dv-workflow/releases)
|
|
47
50
|
|
|
51
|
+
### What's in v1.5.0-rc.1 for your team
|
|
52
|
+
|
|
53
|
+
**Drift fix structurally.** v2 split `spec.md` + `tracking.md` was leaking status markers across both files. v3 puts everything in one `task.md` (Sections 1-7: Snapshot · Intent · Tracker · Changelog · Handoff · Annexes · Debate). Status lives ONLY in Section 3 — enforced by `dw task lint` strict default.
|
|
54
|
+
|
|
55
|
+
- **`dw task new <name>`** — scaffold v3 task from template, frontmatter ajv-validated.
|
|
56
|
+
- **`dw task show [name]`** — ANSI terminal snapshot (~30 lines).
|
|
57
|
+
- **`dw task view [name]`** — lean HTML dashboard in browser. 4 cards: snapshot + progress bar + subtask tracker + recent activity + handoff. ~10KB, self-contained (no CDN), scan-in-5-seconds. Trace `task.md` for full details.
|
|
58
|
+
- **`dw task watch [name]`** — live-preview server. fs.watch + 800ms debounce + browser auto-refresh on save. Pair-with-agent workflow.
|
|
59
|
+
- **`dw task render [name]`** — `timeline.svg` sidecar via `dw-kit-render` (satori+resvg). Bounded composition. Mermaid Gantt fallback if sub-package absent.
|
|
60
|
+
- **`dw task lint [name]`** — schema validate + drift-marker detect + line-cap thresholds. Default `strict` (exit 1 on errors). Configurable via `task.lint: warn|off`.
|
|
61
|
+
- **`dw task migrate <name>`** — v2 → v3 with `--dry-run`, `--diff`, `--rollback`, `--all`. `.v2bak` backups preserved (gitignored).
|
|
62
|
+
- **`dw task rotate [name]`** — auto Section-4 overflow > 400 lines → `timeline-history.md`. Invoked by `stop-check` hook.
|
|
63
|
+
- **3-tier auto-sync**: `stop-check` (session end) · `pre-commit-gate` (commit gate) · `dw task watch` (real-time opt-in).
|
|
64
|
+
- **7 skills v3-aware** (task-init / execute / handoff / research / plan / decision / retroactive) — read v3 first, fall back v2/v1.
|
|
65
|
+
|
|
48
66
|
### What's in v1.3.6 for your team
|
|
49
67
|
|
|
50
68
|
Reaction time when a supply-chain incident drops goes from 24-72 hours (wait for OSV index + npm publish cycle) to **~1 hour** (AI edits lockfile → hook fires → heuristic flags BEFORE anyone knows).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dw-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-rc.1",
|
|
4
4
|
"description": "AI development workflow toolkit — structured, quality-assured, team-ready. From requirements to dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -49,13 +49,15 @@
|
|
|
49
49
|
".claude/templates/",
|
|
50
50
|
".claude/settings.json",
|
|
51
51
|
"CLAUDE.md",
|
|
52
|
-
"MIGRATION-v1.3.md"
|
|
52
|
+
"MIGRATION-v1.3.md",
|
|
53
|
+
"MIGRATION-v1.5.md"
|
|
53
54
|
],
|
|
54
55
|
"engines": {
|
|
55
56
|
"node": ">=18"
|
|
56
57
|
},
|
|
57
58
|
"scripts": {
|
|
58
59
|
"test": "node src/smoke-test.mjs",
|
|
60
|
+
"test:renderer": "cd packages/dw-kit-render && npm test",
|
|
59
61
|
"link": "npm link",
|
|
60
62
|
"test:e2e-local": "bash scripts/e2e-local-check.sh"
|
|
61
63
|
},
|
package/src/cli.mjs
CHANGED
|
@@ -93,6 +93,167 @@ export function run(argv) {
|
|
|
93
93
|
console.log(chalk.green('✓') + ` Wrote ${target}`);
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
const taskCmd = program
|
|
97
|
+
.command('task')
|
|
98
|
+
.description('v3 task docs operations (ADR-0008): show · new · migrate · lint');
|
|
99
|
+
|
|
100
|
+
taskCmd
|
|
101
|
+
.command('show [task-name]')
|
|
102
|
+
.description('Print ANSI snapshot (status + subtask tracker) of a v3 task')
|
|
103
|
+
.option('-v, --verbose', 'Include Section 1 Snapshot body')
|
|
104
|
+
.action(async (taskName, opts) => {
|
|
105
|
+
const { taskShowCommand } = await import('./commands/task-show.mjs');
|
|
106
|
+
await taskShowCommand(taskName, opts);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
taskCmd
|
|
110
|
+
.command('new <task-name>')
|
|
111
|
+
.description('Scaffold a new v3 task from template')
|
|
112
|
+
.option('-d, --depth <level>', 'quick | standard | thorough', 'standard')
|
|
113
|
+
.option('-t, --title <title>', 'Human-readable task title')
|
|
114
|
+
.option('-o, --owner <name>', 'Task owner', '')
|
|
115
|
+
.option('-a, --adr <ref>', 'Related ADR (ADR-NNNN or none)', 'none')
|
|
116
|
+
.option('--target <ship>', 'Target ship milestone', 'TBD')
|
|
117
|
+
.action(async (taskName, opts) => {
|
|
118
|
+
const { taskNewCommand } = await import('./commands/task-new.mjs');
|
|
119
|
+
await taskNewCommand(taskName, opts);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
taskCmd
|
|
123
|
+
.command('migrate [task-name]')
|
|
124
|
+
.description('Migrate v2 spec.md + tracking.md → v3 task.md')
|
|
125
|
+
.option('-n, --dry-run', 'Preview without writing')
|
|
126
|
+
.option('--diff', 'Show diff against existing task.md')
|
|
127
|
+
.option('--all', 'Scan and migrate all v2 tasks')
|
|
128
|
+
.option('--force', 'Overwrite existing task.md')
|
|
129
|
+
.option('--remove-v2', 'Delete spec.md/tracking.md after backup (default keeps them)')
|
|
130
|
+
.option('--rollback', 'Restore v2 files from .v2bak backups (requires task name)')
|
|
131
|
+
.action(async (taskName, opts) => {
|
|
132
|
+
const { taskMigrateCommand } = await import('./commands/task-migrate.mjs');
|
|
133
|
+
await taskMigrateCommand(taskName, opts);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
taskCmd
|
|
137
|
+
.command('lint [task-name]')
|
|
138
|
+
.description('Lint v3 task.md: schema validate + drift markers + line caps')
|
|
139
|
+
.option('-l, --level <level>', 'strict | warn | off (overrides config)', '')
|
|
140
|
+
.action(async (taskName, opts) => {
|
|
141
|
+
const { lintTaskCommand } = await import('./commands/lint-task.mjs');
|
|
142
|
+
await lintTaskCommand(taskName, opts);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
taskCmd
|
|
146
|
+
.command('rotate [task-name]')
|
|
147
|
+
.description('Auto-rotate Section 4 (Timeline/Changelog) > 400 lines to timeline-history.md (keeps last 8 entries)')
|
|
148
|
+
.option('-n, --dry-run', 'Preview without writing')
|
|
149
|
+
.option('-q, --quiet', 'Suppress output (hook usage)')
|
|
150
|
+
.action(async (taskName, opts) => {
|
|
151
|
+
const { taskRotateCommand } = await import('./commands/task-rotate.mjs');
|
|
152
|
+
await taskRotateCommand(taskName, opts);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
taskCmd
|
|
156
|
+
.command('render [task-name]')
|
|
157
|
+
.description('Render timeline.svg sidecar via dw-kit-render sub-package; falls back to Mermaid block in Section 4 if absent')
|
|
158
|
+
.option('-n, --dry-run', 'Print manifest without writing files')
|
|
159
|
+
.option('-f, --format <kind>', 'svg | png | svg,png', 'svg')
|
|
160
|
+
.option('--mermaid-only', 'Skip SVG, only inject Mermaid fallback block')
|
|
161
|
+
.option('--always-mermaid', 'Inject Mermaid block AND SVG (both)')
|
|
162
|
+
.action(async (taskName, opts) => {
|
|
163
|
+
const formats = String(opts.format || 'svg').split(',').map((s) => s.trim()).filter(Boolean);
|
|
164
|
+
const { taskRenderCommand } = await import('./commands/task-render.mjs');
|
|
165
|
+
await taskRenderCommand(taskName, { ...opts, formats });
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
taskCmd
|
|
169
|
+
.command('view [task-name]')
|
|
170
|
+
.description('Render lean HTML dashboard (snapshot + tracker + recent activity + handoff) and open in browser')
|
|
171
|
+
.option('--no-open', 'Generate HTML without opening browser (prints path)')
|
|
172
|
+
.action(async (taskName, opts) => {
|
|
173
|
+
const { taskViewCommand } = await import('./commands/task-view.mjs');
|
|
174
|
+
await taskViewCommand(taskName, opts);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
taskCmd
|
|
178
|
+
.command('watch [task-name]')
|
|
179
|
+
.description('Watch task.md for changes and live-reload the HTML preview in browser (local server, debounced)')
|
|
180
|
+
.option('-p, --port <port>', 'Local server port (auto-finds next available if busy)', parseInt)
|
|
181
|
+
.action(async (taskName, opts) => {
|
|
182
|
+
const { taskWatchCommand } = await import('./commands/task-watch.mjs');
|
|
183
|
+
await taskWatchCommand(taskName, opts);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const agentCmd = program
|
|
187
|
+
.command('agent')
|
|
188
|
+
.description('Agent OS multi-agent orchestration (ADR-0009): claim · release · claims · reports · conflicts');
|
|
189
|
+
|
|
190
|
+
agentCmd
|
|
191
|
+
.command('claim <task-id>')
|
|
192
|
+
.description('Create a cooperative claim for a task (subtasks + write_scope)')
|
|
193
|
+
.option('-s, --subtasks <list>', 'Comma-separated subtask IDs (e.g. ST-1,ST-2)')
|
|
194
|
+
.option('-w, --write <paths>', 'Comma-separated write_scope glob paths')
|
|
195
|
+
.option('-r, --read <paths>', 'Comma-separated read_scope hint paths (informational)')
|
|
196
|
+
.option('-a, --agent <id>', 'Agent identifier (default: env DW_AGENT_ID or auto-generated)')
|
|
197
|
+
.option('-v, --vendor <name>', 'Vendor: claude | codex | gemini | human | other', 'claude')
|
|
198
|
+
.option('--role <role>', 'worker | reader | orchestrator | reviewer', 'worker')
|
|
199
|
+
.option('-l, --lease <duration>', 'Lease duration (e.g. 30m, 1h, 4h, 1d)', '1h')
|
|
200
|
+
.option('--worktree <path>', 'Worktree path if agent uses git worktree (R2-3)')
|
|
201
|
+
.option('-f, --force', 'Override conflict detection (use sparingly)')
|
|
202
|
+
.action(async (taskId, opts) => {
|
|
203
|
+
const { agentClaimCommand } = await import('./commands/agent-claim.mjs');
|
|
204
|
+
await agentClaimCommand(taskId, opts);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
agentCmd
|
|
208
|
+
.command('release <claim-id>')
|
|
209
|
+
.description('Release a claim (clean exit; transitions status to "released")')
|
|
210
|
+
.option('-r, --reason <text>', 'Optional reason for release')
|
|
211
|
+
.action(async (claimId, opts) => {
|
|
212
|
+
const { agentReleaseCommand } = await import('./commands/agent-claim.mjs');
|
|
213
|
+
await agentReleaseCommand(claimId, opts);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
agentCmd
|
|
217
|
+
.command('expire <claim-id>')
|
|
218
|
+
.description('Mark a claim as expired or invalidated (orchestrator action)')
|
|
219
|
+
.option('-r, --reason <text>', 'Reason for expiry')
|
|
220
|
+
.option('--invalidate', 'Invalidate instead of expire (orchestrator override)')
|
|
221
|
+
.action(async (claimId, opts) => {
|
|
222
|
+
const { agentExpireCommand } = await import('./commands/agent-claim.mjs');
|
|
223
|
+
await agentExpireCommand(claimId, opts);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
agentCmd
|
|
227
|
+
.command('claims')
|
|
228
|
+
.description('List claims (default: active only). Filter by task / status / --all to include released')
|
|
229
|
+
.option('-t, --task <id>', 'Filter by task ID')
|
|
230
|
+
.option('-s, --status <status>', 'Filter by status: created | active | released | expired | invalidated')
|
|
231
|
+
.option('--all', 'Include released and invalidated claims')
|
|
232
|
+
.action(async (opts) => {
|
|
233
|
+
const { agentClaimsCommand } = await import('./commands/agent-inspect.mjs');
|
|
234
|
+
await agentClaimsCommand(opts);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
agentCmd
|
|
238
|
+
.command('reports')
|
|
239
|
+
.description('List agent reports across tasks (read-only audit view)')
|
|
240
|
+
.option('-t, --task <id>', 'Filter by task ID')
|
|
241
|
+
.option('-a, --agent <id>', 'Filter by agent ID')
|
|
242
|
+
.action(async (opts) => {
|
|
243
|
+
const { agentReportsCommand } = await import('./commands/agent-inspect.mjs');
|
|
244
|
+
await agentReportsCommand(opts);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
agentCmd
|
|
248
|
+
.command('conflicts')
|
|
249
|
+
.description('Detect overlapping active claims (subtask or write_scope). Exits 1 if conflicts found (use --no-strict to suppress).')
|
|
250
|
+
.option('-t, --task <id>', 'Filter by task ID')
|
|
251
|
+
.option('--no-strict', 'Do not exit 1 on conflict (just report)')
|
|
252
|
+
.action(async (opts) => {
|
|
253
|
+
const { agentConflictsCommand } = await import('./commands/agent-inspect.mjs');
|
|
254
|
+
await agentConflictsCommand(opts);
|
|
255
|
+
});
|
|
256
|
+
|
|
96
257
|
program
|
|
97
258
|
.command('dashboard')
|
|
98
259
|
.description('Show team dashboard — active tasks, ADRs, telemetry summary, health')
|
|
@@ -131,6 +292,21 @@ export function run(argv) {
|
|
|
131
292
|
await securityScanCommand(opts);
|
|
132
293
|
});
|
|
133
294
|
|
|
295
|
+
const reviewCmd = program
|
|
296
|
+
.command('review')
|
|
297
|
+
.description('Review subcommands (ADR-0007)');
|
|
298
|
+
|
|
299
|
+
reviewCmd
|
|
300
|
+
.command('render <manifest>')
|
|
301
|
+
.description('Render a /dw:review --visual manifest into SVG/PNG (requires dw-kit-render) or markdown summary fallback')
|
|
302
|
+
.option('-f, --format <kind>', 'Override output formats: svg | png | both', null)
|
|
303
|
+
.option('-s, --strategy <name>', 'Override strategy: auto | plugin | markdown-only', null)
|
|
304
|
+
.option('-q, --quiet', 'Suppress info logs (still exits non-zero on hard errors)')
|
|
305
|
+
.action(async (manifest, opts) => {
|
|
306
|
+
const { reviewRenderCommand } = await import('./commands/review-render.mjs');
|
|
307
|
+
await reviewRenderCommand(manifest, opts);
|
|
308
|
+
});
|
|
309
|
+
|
|
134
310
|
program
|
|
135
311
|
.command('claude-vn-fix')
|
|
136
312
|
.description('Patch Claude CLI to fix Vietnamese IME (local, with backup/restore)')
|