@unbrained/pm-cli 2026.3.9 → 2026.3.12
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/AGENTS.md +16 -2
- package/PRD.md +11 -10
- package/README.md +77 -627
- package/dist/cli/commands/beads.d.ts +1 -0
- package/dist/cli/commands/beads.js +138 -37
- package/dist/cli/commands/beads.js.map +1 -1
- package/dist/cli/commands/completion.js +58 -58
- package/dist/cli/commands/list.js +4 -4
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/search.js +4 -4
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/main.js +29 -28
- package/dist/cli/main.js.map +1 -1
- package/dist/core/item/id.d.ts +1 -0
- package/dist/core/item/id.js +6 -2
- package/dist/core/item/id.js.map +1 -1
- package/dist/core/item/item-format.js +25 -4
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/shared/constants.js +5 -0
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/time.d.ts +2 -0
- package/dist/core/shared/time.js +11 -0
- package/dist/core/shared/time.js.map +1 -1
- package/dist/core/store/item-store.js +13 -9
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/extensions/builtins/beads/index.js +4 -0
- package/dist/extensions/builtins/beads/index.js.map +1 -1
- package/dist/types.d.ts +7 -1
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -1
- package/docs/ARCHITECTURE.md +1 -1
- package/package.json +1 -1
- package/scripts/install.ps1 +2 -1
- package/scripts/install.sh +2 -1
package/README.md
CHANGED
|
@@ -5,651 +5,101 @@
|
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
`pm` is a git-native project management CLI for humans and coding agents. It stores work as plain Markdown files with JSON front matter, keeps append-only history, and supports safe collaboration.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Highlights
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
- Git-native items that stay reviewable in diffs
|
|
13
|
+
- Safe multi-agent workflows with claims, locks, and restore
|
|
14
|
+
- Deterministic output with TOON by default and `--json` when needed
|
|
15
|
+
- Optional search and extension support for more advanced setups
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
- Deterministic: stable output schema, key ordering, and filtering behavior.
|
|
16
|
-
- Agent-optimized: claim/release ownership, append-only history, restore by version/timestamp.
|
|
17
|
-
- Extensible: project + global extension loading with predictable precedence.
|
|
18
|
-
- Search-ready: keyword search built-in, semantic/hybrid search optional.
|
|
17
|
+
## Install
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`pm-cli` targets Node.js 20+ and ships a `pm` executable via npm `bin`.
|
|
23
|
-
|
|
24
|
-
### npm (recommended)
|
|
19
|
+
`pm-cli` requires Node.js 20 or newer.
|
|
25
20
|
|
|
26
21
|
```bash
|
|
27
|
-
npm
|
|
28
|
-
pm --help
|
|
22
|
+
npm install -g @unbrained/pm-cli
|
|
29
23
|
pm --version
|
|
24
|
+
pm --help
|
|
30
25
|
```
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npm i -g @unbrained/pm-cli@latest
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Project-local invocation
|
|
27
|
+
For project-local use:
|
|
39
28
|
|
|
40
29
|
```bash
|
|
41
30
|
npx @unbrained/pm-cli --help
|
|
42
31
|
```
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
# Linux/macOS
|
|
48
|
-
bash scripts/install.sh
|
|
49
|
-
|
|
50
|
-
# Windows PowerShell
|
|
51
|
-
pwsh scripts/install.ps1
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Both installers are idempotent for update flows; rerun them to move to a newer version.
|
|
55
|
-
Each installer verifies post-install CLI availability by resolving `pm` and running `pm --version` before reporting success.
|
|
56
|
-
Installer default package target is `@unbrained/pm-cli`.
|
|
57
|
-
Set `PM_CLI_PACKAGE` to override the package source when smoke-testing installer flows.
|
|
58
|
-
Scoped package names such as `@scope/pkg` still honor `--version`, while literal specs (`file:`, URLs, local paths/tarballs, or already versioned package specs) are passed to npm unchanged.
|
|
59
|
-
|
|
60
|
-
One-line bootstrap patterns (use with normal script-review caution):
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
curl -fsSL https://raw.githubusercontent.com/unbraind/pm-cli/main/scripts/install.sh | bash
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
```powershell
|
|
67
|
-
# safer PowerShell flow: download, inspect, then execute
|
|
68
|
-
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/unbraind/pm-cli/main/scripts/install.ps1" -OutFile "install.ps1"
|
|
69
|
-
pwsh -File .\install.ps1
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
During development in this repo:
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
pnpm install
|
|
76
|
-
pnpm build
|
|
77
|
-
node dist/cli.js --help
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Maintainer Bootstrap (Dogfooding Runs)
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
# maintainer identity for mutation history
|
|
84
|
-
export PM_AUTHOR="maintainer-agent"
|
|
85
|
-
|
|
86
|
-
# refresh global pm from this repository and verify availability
|
|
87
|
-
npm install -g .
|
|
88
|
-
pm --version
|
|
89
|
-
|
|
90
|
-
# choose invocation based on whether global pm resolves to this build
|
|
91
|
-
export PM_CMD="pm"
|
|
92
|
-
# export PM_CMD="node dist/cli.js"
|
|
93
|
-
|
|
94
|
-
# verify command surface before mutation work
|
|
95
|
-
$PM_CMD --version
|
|
96
|
-
$PM_CMD --help
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Use repository-default tracking for maintainer runs (do not set `PM_PATH`).
|
|
100
|
-
For test runs only, always use sandboxed paths via `node scripts/run-tests.mjs <test|coverage>` so both `PM_PATH` and `PM_GLOBAL_PATH` are isolated.
|
|
101
|
-
|
|
102
|
-
## Quickstart
|
|
33
|
+
## Quick Start
|
|
103
34
|
|
|
104
35
|
```bash
|
|
105
|
-
# 1) initialize project tracker storage
|
|
106
36
|
pm init
|
|
107
37
|
|
|
108
|
-
# 2) create work item
|
|
109
38
|
pm create \
|
|
110
|
-
--title "
|
|
111
|
-
--description "
|
|
112
|
-
--type
|
|
39
|
+
--title "Fix Windows restore failure after stale lock cleanup" \
|
|
40
|
+
--description "Restore can fail on Windows when a stale lock is cleaned up during retry." \
|
|
41
|
+
--type Issue \
|
|
113
42
|
--status open \
|
|
114
43
|
--priority 1 \
|
|
115
|
-
--tags "
|
|
116
|
-
--body "" \
|
|
117
|
-
--deadline +
|
|
118
|
-
--estimate
|
|
119
|
-
--acceptance-criteria "Restore
|
|
120
|
-
--
|
|
121
|
-
--
|
|
122
|
-
--
|
|
123
|
-
--
|
|
124
|
-
--
|
|
125
|
-
--
|
|
126
|
-
--
|
|
127
|
-
--
|
|
128
|
-
--
|
|
129
|
-
--
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
core/
|
|
178
|
-
fs/
|
|
179
|
-
history/
|
|
180
|
-
item/
|
|
181
|
-
lock/
|
|
182
|
-
output/
|
|
183
|
-
store/
|
|
184
|
-
types/
|
|
185
|
-
tests/
|
|
186
|
-
unit/
|
|
187
|
-
integration/
|
|
188
|
-
scripts/
|
|
189
|
-
install.sh
|
|
190
|
-
install.ps1
|
|
191
|
-
run-tests.mjs
|
|
192
|
-
docs/
|
|
193
|
-
ARCHITECTURE.md
|
|
194
|
-
EXTENSIONS.md
|
|
195
|
-
.pi/
|
|
196
|
-
extensions/
|
|
197
|
-
pm-cli/
|
|
198
|
-
.github/workflows/
|
|
199
|
-
ci.yml
|
|
200
|
-
nightly.yml
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
## Developer Docs
|
|
204
|
-
|
|
205
|
-
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — Internal architecture, source layout, mutation contract, history/restore, search, and testing.
|
|
206
|
-
- [docs/EXTENSIONS.md](docs/EXTENSIONS.md) — Extension development guide: manifest format, API reference, hook lifecycle, built-in extensions.
|
|
207
|
-
- [docs/RELEASING.md](docs/RELEASING.md) — Maintainer release runbook for calendar versioning, CI gates, npm publish, and GitHub Releases.
|
|
208
|
-
|
|
209
|
-
## Item File Format
|
|
210
|
-
|
|
211
|
-
Each item is stored as `<id>.md` under the folder matching its type:
|
|
212
|
-
|
|
213
|
-
- `Epic` -> `epics/`
|
|
214
|
-
- `Feature` -> `features/`
|
|
215
|
-
- `Task` -> `tasks/`
|
|
216
|
-
- `Chore` -> `chores/`
|
|
217
|
-
- `Issue` -> `issues/`
|
|
218
|
-
|
|
219
|
-
Format:
|
|
220
|
-
|
|
221
|
-
1. JSON front-matter object (not YAML)
|
|
222
|
-
2. blank line
|
|
223
|
-
3. optional markdown body
|
|
224
|
-
|
|
225
|
-
## Commands
|
|
226
|
-
|
|
227
|
-
### Core (implemented in v0.1)
|
|
228
|
-
|
|
229
|
-
- `pm init [PREFIX]`
|
|
230
|
-
- `pm install pi [--project|--global]` (install bundled Pi extension to `<project-root>/.pi/extensions/pm-cli/index.ts`, where `project-root` is derived from `--path` when provided, otherwise current working directory; global scope uses `PI_CODING_AGENT_DIR/extensions/pm-cli/index.ts`)
|
|
231
|
-
- `pm list` (excludes terminal statuses `closed`/`canceled` by default — the active working-set view), `pm list-all` (all statuses including terminal)
|
|
232
|
-
- `pm list-draft`, `pm list-open`, `pm list-in-progress`, `pm list-blocked`, `pm list-closed`, `pm list-canceled`
|
|
233
|
-
- `pm get <ID>`
|
|
234
|
-
- `pm search <keywords>` (keyword + semantic + hybrid modes; `--include-linked` expands keyword/hybrid lexical scoring with linked content)
|
|
235
|
-
- `pm search` shared filters enforce canonical values: `--type` must be `Epic|Feature|Task|Chore|Issue` and `--priority` must be an integer `0..4`
|
|
236
|
-
- `pm search --limit 0` returns a deterministic empty result set (after mode/config validation) without embedding/vector query execution
|
|
237
|
-
- `pm reindex` (keyword/semantic/hybrid cache artifact rebuild; semantic/hybrid perform provider embedding generation + vector upsert)
|
|
238
|
-
- `pm history <ID>`, `pm activity [--limit]`
|
|
239
|
-
- `pm restore <ID> <TIMESTAMP|VERSION>`
|
|
240
|
-
- `pm config <project|global> set definition-of-done --criterion <text>`
|
|
241
|
-
- `pm config <project|global> get definition-of-done`
|
|
242
|
-
- `pm create`, `pm update <ID>`, `pm append <ID>`, `pm close <ID> <TEXT>`, `pm delete <ID>`
|
|
243
|
-
- `pm claim <ID>`, `pm release <ID>`
|
|
244
|
-
- `pm comments <ID>`
|
|
245
|
-
- `pm files <ID>`, `pm test <ID>`, `pm docs <ID>`
|
|
246
|
-
- `pm test-all`
|
|
247
|
-
- `pm stats`
|
|
248
|
-
- `pm health`
|
|
249
|
-
- `pm gc`
|
|
250
|
-
- `pm beads import [--file <path>]` (built-in Beads extension command, import-only)
|
|
251
|
-
- `pm todos import [--folder <path>]` (built-in todos extension command)
|
|
252
|
-
- `pm todos export [--folder <path>]` (built-in todos extension command)
|
|
253
|
-
- `pm completion <bash|zsh|fish>` (generate shell tab-completion script)
|
|
254
|
-
- extension-only command paths return not-found when no handler is registered, and generic failure when a matched handler throws; profile diagnostics include deterministic warning codes like `extension_command_handler_failed:<layer>:<name>:<command>`
|
|
255
|
-
- extension command names are canonicalized (trimmed, lowercased, repeated internal whitespace collapsed) before registration and dispatch so equivalent command paths resolve deterministically
|
|
256
|
-
- `pm test <ID> --add` rejects linked commands that invoke `pm test-all` (including global-flag and package-spec launcher forms like `pm --json test-all`, `npx @unbrained/pm-cli@latest --json test-all`, `pnpm dlx @unbrained/pm-cli@latest --json test-all`, and `npm exec -- @unbrained/pm-cli@latest --json test-all`) to prevent recursive orchestration
|
|
257
|
-
- `pm test <ID> --run` skips legacy linked commands that invoke `pm test-all` (including global-flag and package-spec launcher forms such as `npx`, `pnpm dlx`, and `npm exec` launcher variants) and reports deterministic skip diagnostics
|
|
258
|
-
- `pm test <ID> --add` rejects sandbox-unsafe test-runner commands (for example `pnpm test`, `pnpm test:coverage`, `npm test`, `npm run test`, `pnpm run test`, `yarn run test`, `bun run test`, `vitest`) unless they use `node scripts/run-tests.mjs ...` or explicitly set both `PM_PATH` and `PM_GLOBAL_PATH`; chained direct test-runner segments are validated independently, so each direct runner segment must be explicitly sandboxed
|
|
259
|
-
- `pm test-all` deduplicates identical linked command/path entries per invocation (keyed by scope+normalized command or scope+path), reports duplicates as skipped, and uses the maximum `timeout_seconds` when duplicate keys disagree on timeout metadata
|
|
260
|
-
|
|
261
|
-
### `pm list` vs `pm list-all`
|
|
262
|
-
|
|
263
|
-
- `pm list` — active working-set view: excludes `closed` and `canceled` items by default. Useful for day-to-day use to see what needs attention.
|
|
264
|
-
- `pm list-all` — full inventory: includes all items regardless of status. Useful for auditing and historical review.
|
|
265
|
-
|
|
266
|
-
Both commands accept the same filter flags; `pm list` applies the terminal-status exclusion before any other filters.
|
|
267
|
-
|
|
268
|
-
### `pm list` filters
|
|
269
|
-
|
|
270
|
-
All `list*` commands accept these filter flags:
|
|
271
|
-
|
|
272
|
-
- `--type <value>` — `Epic|Feature|Task|Chore|Issue`
|
|
273
|
-
- `--tag <value>` — exact tag match (case-insensitive)
|
|
274
|
-
- `--priority <value>` — integer `0..4`
|
|
275
|
-
- `--deadline-before <value>` — ISO or relative deadline upper bound
|
|
276
|
-
- `--deadline-after <value>` — ISO or relative deadline lower bound
|
|
277
|
-
- `--assignee <value>` — exact match on `assignee` field; use `none` to filter for unassigned items
|
|
278
|
-
- `--sprint <value>` — exact match on `sprint` field
|
|
279
|
-
- `--release <value>` — exact match on `release` field
|
|
280
|
-
- `--limit <n>` — max items returned
|
|
281
|
-
|
|
282
|
-
### Roadmap (post-v0.1 / partial areas)
|
|
283
|
-
|
|
284
|
-
- semantic/hybrid search enhancements (advanced hybrid relevance tuning, incremental embedding refresh, adapter optimizations)
|
|
285
|
-
- Pi agent extension advanced ergonomics (higher-level workflow presets and additional tooling integrations)
|
|
286
|
-
|
|
287
|
-
### Global flags
|
|
288
|
-
|
|
289
|
-
- `--json` output JSON instead of TOON
|
|
290
|
-
- `--quiet` suppress stdout (errors still on stderr)
|
|
291
|
-
- `--path <dir>` override PM path for invocation
|
|
292
|
-
- `--no-extensions` disable extension loading
|
|
293
|
-
- `--profile` print timing diagnostics
|
|
294
|
-
- `--version` print CLI version
|
|
295
|
-
|
|
296
|
-
### `pm create` explicit-field contract
|
|
297
|
-
|
|
298
|
-
`pm create` accepts explicit flags for all schema fields (including optional ones) so callers can always pass complete intent:
|
|
299
|
-
|
|
300
|
-
- required scalar flags:
|
|
301
|
-
- `--title/-t`
|
|
302
|
-
- `--description/-d` (explicit empty allowed)
|
|
303
|
-
- `--type`
|
|
304
|
-
- `--status/-s`
|
|
305
|
-
- `--priority/-p` (`0..4`)
|
|
306
|
-
- `--tags` (explicit empty allowed)
|
|
307
|
-
- `--body/-b` (explicit empty allowed)
|
|
308
|
-
- `--deadline` (ISO, relative, or none)
|
|
309
|
-
- `--estimate/--estimated-minutes/--estimated_minutes` (supports `0`)
|
|
310
|
-
- `--acceptance-criteria`, `--acceptance_criteria`, `--ac` (explicit empty allowed)
|
|
311
|
-
- `--author` (fallbacks still exist, but explicit is recommended)
|
|
312
|
-
- `--message`
|
|
313
|
-
- `--assignee` (explicit; use `none` to clear)
|
|
314
|
-
- optional scalar flags (use `none` to unset):
|
|
315
|
-
- `--parent` (item ID reference)
|
|
316
|
-
- `--reviewer`
|
|
317
|
-
- `--risk` (`low|med|medium|high|critical`; `med` persists as `medium`)
|
|
318
|
-
- `--confidence` (`0..100|low|med|medium|high`; `med` persists as `medium`)
|
|
319
|
-
- `--sprint`
|
|
320
|
-
- `--release`
|
|
321
|
-
- `--blocked-by/--blocked_by` (item ID or free-text)
|
|
322
|
-
- `--blocked-reason/--blocked_reason`
|
|
323
|
-
- `--unblock-note/--unblock_note` (unblock rationale note)
|
|
324
|
-
- `--reporter`
|
|
325
|
-
- `--severity` (`low|med|medium|high|critical`; `med` persists as `medium`)
|
|
326
|
-
- `--environment`
|
|
327
|
-
- `--repro-steps/--repro_steps`
|
|
328
|
-
- `--resolution`
|
|
329
|
-
- `--expected-result/--expected_result`
|
|
330
|
-
- `--actual-result/--actual_result`
|
|
331
|
-
- `--affected-version/--affected_version`
|
|
332
|
-
- `--fixed-version/--fixed_version`
|
|
333
|
-
- `--component`
|
|
334
|
-
- `--regression` (`true|false|1|0`)
|
|
335
|
-
- `--customer-impact/--customer_impact`
|
|
336
|
-
- `--definition-of-ready/--definition_of_ready` (explicit empty allowed)
|
|
337
|
-
- `--order/--rank` (integer rank/order)
|
|
338
|
-
- `--goal`
|
|
339
|
-
- `--objective`
|
|
340
|
-
- `--value`
|
|
341
|
-
- `--impact`
|
|
342
|
-
- `--outcome`
|
|
343
|
-
- `--why-now/--why_now`
|
|
344
|
-
- required repeatable seed flags (pass each at least once; use `none` for explicit empty intent):
|
|
345
|
-
- `--dep`
|
|
346
|
-
- `--comment`
|
|
347
|
-
- `--note`
|
|
348
|
-
- `--learning`
|
|
349
|
-
- `--file`
|
|
350
|
-
- `--test`
|
|
351
|
-
- `--doc`
|
|
352
|
-
|
|
353
|
-
Explicit unset behavior:
|
|
354
|
-
|
|
355
|
-
- scalar `none` means unset/omit that optional field
|
|
356
|
-
- repeatable seed value `none` means explicit empty list intent
|
|
357
|
-
- explicit unset intent is recorded in mutation history message metadata
|
|
358
|
-
|
|
359
|
-
### `pm update` explicit-field contract
|
|
360
|
-
|
|
361
|
-
`pm update <ID>` accepts explicit mutation flags for canonical front-matter fields:
|
|
362
|
-
|
|
363
|
-
- `--title/-t`
|
|
364
|
-
- `--description/-d`
|
|
365
|
-
- `--status/-s` (supports non-terminal values and `canceled`; use `pm close <ID> <TEXT>` for closure)
|
|
366
|
-
- `--priority/-p`
|
|
367
|
-
- `--type`
|
|
368
|
-
- `--tags`
|
|
369
|
-
- `--deadline`
|
|
370
|
-
- `--estimate/--estimated-minutes/--estimated_minutes`
|
|
371
|
-
- `--acceptance-criteria`, `--acceptance_criteria`, `--ac`
|
|
372
|
-
- `--assignee`
|
|
373
|
-
- `--parent`
|
|
374
|
-
- `--reviewer`
|
|
375
|
-
- `--risk` (`low|med|medium|high|critical`; `med` persists as `medium`)
|
|
376
|
-
- `--confidence` (`0..100|low|med|medium|high`; `med` persists as `medium`)
|
|
377
|
-
- `--sprint`
|
|
378
|
-
- `--release`
|
|
379
|
-
- `--blocked-by/--blocked_by`
|
|
380
|
-
- `--blocked-reason/--blocked_reason`
|
|
381
|
-
- `--unblock-note/--unblock_note`
|
|
382
|
-
- `--reporter`
|
|
383
|
-
- `--severity` (`low|med|medium|high|critical`; `med` persists as `medium`)
|
|
384
|
-
- `--environment`
|
|
385
|
-
- `--repro-steps/--repro_steps`
|
|
386
|
-
- `--resolution`
|
|
387
|
-
- `--expected-result/--expected_result`
|
|
388
|
-
- `--actual-result/--actual_result`
|
|
389
|
-
- `--affected-version/--affected_version`
|
|
390
|
-
- `--fixed-version/--fixed_version`
|
|
391
|
-
- `--component`
|
|
392
|
-
- `--regression` (`true|false|1|0`)
|
|
393
|
-
- `--customer-impact/--customer_impact`
|
|
394
|
-
- `--definition-of-ready/--definition_of_ready`
|
|
395
|
-
- `--order/--rank`
|
|
396
|
-
- `--goal`
|
|
397
|
-
- `--objective`
|
|
398
|
-
- `--value`
|
|
399
|
-
- `--impact`
|
|
400
|
-
- `--outcome`
|
|
401
|
-
- `--why-now/--why_now`
|
|
402
|
-
- `--author`
|
|
403
|
-
- `--message`
|
|
404
|
-
- `--force`
|
|
405
|
-
|
|
406
|
-
### Exit codes
|
|
407
|
-
|
|
408
|
-
- `0` success
|
|
409
|
-
- `1` generic failure
|
|
410
|
-
- `2` invalid usage/arguments
|
|
411
|
-
- `3` not found
|
|
412
|
-
- `4` conflict (lock/claim)
|
|
413
|
-
- `5` dependency failed (e.g. test-all failure)
|
|
414
|
-
|
|
415
|
-
## Output Modes
|
|
416
|
-
|
|
417
|
-
Default output is TOON (token-efficient, deterministic).
|
|
418
|
-
Use `--json` for machine pipelines expecting JSON.
|
|
419
|
-
|
|
420
|
-
Examples:
|
|
421
|
-
|
|
422
|
-
```bash
|
|
423
|
-
pm list-open --limit 5
|
|
424
|
-
pm list-open --limit 5 --json
|
|
425
|
-
pm get pm-a1b2 --quiet; echo $?
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
## Configuration
|
|
429
|
-
|
|
430
|
-
Primary config: `.agents/pm/settings.json`
|
|
431
|
-
|
|
432
|
-
Typical keys:
|
|
433
|
-
|
|
434
|
-
- `id_prefix`
|
|
435
|
-
- `author_default`
|
|
436
|
-
- `locks.ttl_seconds`
|
|
437
|
-
- `output.default_format`
|
|
438
|
-
- `workflow.definition_of_done`
|
|
439
|
-
- `extensions.enabled / disabled`
|
|
440
|
-
- `search.score_threshold`
|
|
441
|
-
- `search.hybrid_semantic_weight`
|
|
442
|
-
- `search.max_results`
|
|
443
|
-
- `search.embedding_model`
|
|
444
|
-
- `search.embedding_batch_size`
|
|
445
|
-
- `search.scanner_max_batch_retries`
|
|
446
|
-
- `search.tuning` (optional object)
|
|
447
|
-
- provider + vector-store blocks
|
|
448
|
-
|
|
449
|
-
`search.score_threshold` defaults to `0` and applies mode-specific minimum-score filtering (`keyword` raw lexical score, `semantic` vector score, `hybrid` normalized blended score).
|
|
450
|
-
`search.hybrid_semantic_weight` defaults to `0.7` and controls hybrid semantic-vs-lexical blending (`0..1`).
|
|
451
|
-
`search.tuning` optionally overrides deterministic lexical weighting (`title_exact_bonus`, `title_weight`, `description_weight`, `tags_weight`, `status_weight`, `body_weight`, `comments_weight`, `notes_weight`, `learnings_weight`, `dependencies_weight`, `linked_content_weight`) for keyword mode and the hybrid lexical component; invalid/negative values fall back to defaults.
|
|
452
|
-
`workflow.definition_of_done` defaults to `[]` and stores deterministic team-level close-readiness criteria strings. The baseline config command surface is:
|
|
453
|
-
|
|
454
|
-
```bash
|
|
455
|
-
pm config project set definition-of-done \
|
|
456
|
-
--criterion "tests pass" \
|
|
457
|
-
--criterion "linked files/tests/docs present"
|
|
458
|
-
|
|
459
|
-
pm config project get definition-of-done
|
|
460
|
-
pm config global get definition-of-done --json
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
### Environment variables
|
|
464
|
-
|
|
465
|
-
- `PM_PATH` - project storage override
|
|
466
|
-
- `PM_GLOBAL_PATH` - global extension root override
|
|
467
|
-
- `PM_AUTHOR` - default mutation author
|
|
468
|
-
|
|
469
|
-
Precedence:
|
|
470
|
-
|
|
471
|
-
1. CLI flags
|
|
472
|
-
2. env vars
|
|
473
|
-
3. settings.json
|
|
474
|
-
4. defaults
|
|
475
|
-
|
|
476
|
-
## Search and Extension System
|
|
477
|
-
|
|
478
|
-
Keyword search is part of the implemented command surface, `pm search --include-linked` expands keyword scoring across readable linked docs/files/tests content while enforcing scope-root containment (`scope=project` and `scope=global` paths must stay within their allowed roots after both resolve-path and symlink-resolved-realpath checks; out-of-scope or realpath-escape paths are skipped), and `pm reindex` rebuilds deterministic keyword cache artifacts (`index/manifest.json` and `search/embeddings.jsonl`). Provider abstraction baseline is also in place for deterministic OpenAI/Ollama configuration resolution, request-target resolution (including OpenAI-compatible `base_url` normalization for root, `/v1`, and explicit `/embeddings` forms), provider-specific request payload/response normalization (including deterministic OpenAI data-entry index ordering), deterministic request-execution helper behavior, deterministic per-request normalized-input deduplication with output fan-out back to original input cardinality/order, and deterministic embedding cardinality validation (normalized input count must match returned vector count after dedupe expansion). Vector-store abstraction baseline is also in place for deterministic Qdrant/LanceDB configuration resolution, request-target planning, request payload/response normalization, deterministic Qdrant request-execution helper behavior, deterministic LanceDB local query/upsert/delete helper behavior, deterministic local snapshot persistence + reload across process boundaries, and deterministic query-hit ordering normalization (score descending with id ascending tie-break).
|
|
479
|
-
|
|
480
|
-
Command-path semantic/hybrid baseline is now implemented: `pm reindex --mode semantic|hybrid` generates provider embeddings for canonical item corpus records and upserts vectors to the active store, while `pm search --mode semantic|hybrid` executes vector-query ranking with deterministic hybrid lexical+semantic blending in hybrid mode. Semantic embedding generation runs in deterministic batches using `settings.search.embedding_batch_size`, and each embedding batch retries failures up to `settings.search.scanner_max_batch_retries` before surfacing deterministic warnings/errors. Keyword/hybrid lexical scoring includes a deterministic exact-title token boost (full-token title matches receive additive lexical bonus weight) plus configurable multi-factor lexical tuning through `settings.search.tuning` (`title_exact_bonus`, `title_weight`, `description_weight`, `tags_weight`, `status_weight`, `body_weight`, `comments_weight`, `notes_weight`, `learnings_weight`, `dependencies_weight`, `linked_content_weight`; invalid/negative values fall back to defaults). Search scoring also honors `settings.search.score_threshold` as a mode-aware minimum score filter (`keyword` raw lexical score, `semantic` vector score, `hybrid` normalized blended score), and hybrid blending weight is configurable with `settings.search.hybrid_semantic_weight` (`0..1`, default `0.7`). Successful item-mutation command paths now invalidate stale keyword cache artifacts (`index/manifest.json` and `search/embeddings.jsonl`) and perform best-effort semantic embedding refresh for affected item IDs when embedding-provider and vector-store configuration are available; missing/deleted affected IDs trigger best-effort vector pruning from the active store. Refresh failures degrade to deterministic warnings. Broader advanced semantic/hybrid relevance tuning remains roadmap work.
|
|
481
|
-
|
|
482
|
-
Built-in extension command handlers now provide import/export adapters: `pm beads import [--file <path>]` (import-only) ingests Beads JSONL records into PM items with deterministic defaults and `op: "import"` history entries, while `pm todos import|export [--folder <path>]` maps todos markdown files (JSON front-matter + body) to and from PM items using deterministic defaults for missing PM fields, preserves explicit imported IDs verbatim including hierarchical suffixes such as `pm-legacy.1.2`, and preserves canonical optional `ItemFrontMatter` metadata when present, including planning/workflow fields (`definition_of_ready`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `why_now`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blocked_by`, `blocked_reason`, `unblock_note`) and issue fields (`reporter`, `severity`, `environment`, `repro_steps`, `resolution`, `expected_result`, `actual_result`, `affected_version`, `fixed_version`, `component`, `regression`, `customer_impact`). `confidence`, `risk`, and `severity` aliases normalize deterministically (`med` -> `medium`). The Pi integration contract is provided as a Pi agent extension module at `.pi/extensions/pm-cli/index.ts`, which registers a `pm` tool for action-based invocations and returns `content` + `details` envelopes. Current Pi wrapper action coverage includes the v0.1 command-aligned set (`init`, `config`, `create`, `list`, `list-all`, `list-draft`, `list-open`, `list-in-progress`, `list-blocked`, `list-closed`, `list-canceled`, `get`, `search`, `reindex`, `history`, `activity`, `restore`, `update`, `close`, `delete`, `append`, `comments`, `files`, `docs`, `test`, `test-all`, `stats`, `health`, `gc`, `completion`, `claim`, `release`) plus extension aliases (`beads-import`, `todos-import`, `todos-export`) and workflow presets (`start-task`, `pause-task`, `close-task`). For create/update parity, the wrapper accepts camelCase counterparts for the canonical CLI scalar metadata surface, completion parity field `shell` (`action=completion` -> `pm completion <shell>`), workflow/planning fields (`parent`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blockedBy`, `blockedReason`, `unblockNote`, `definitionOfReady`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `whyNow`) and issue fields (`reporter`, `severity`, `environment`, `reproSteps`, `resolution`, `expectedResult`, `actualResult`, `affectedVersion`, `fixedVersion`, `component`, `regression`, `customerImpact`), and forwards them deterministically to the corresponding `pm create`/`pm update` flags. Runtime extension loading includes deterministic manifest discovery, settings-aware enable/disable filtering, global-to-project precedence, extension-entry sandbox enforcement (entry paths and resolved symlink targets must remain inside their extension directory), and failure-isolated imports. `pm health` extension checks run the same load/activation probe used at runtime, including enabled built-in extensions, and surface deterministic diagnostics for manifest/entry warnings plus load and activation failures (for example `extension_entry_outside_extension:<layer>:<name>`, `extension_load_failed:<layer>:<name>`, and `extension_activate_failed:<layer>:<name>`).
|
|
483
|
-
|
|
484
|
-
Hook lifecycle baseline includes `activate(api)` registration with deterministic ordering, registration-time hook handler validation (non-function payloads fail extension activation deterministically), per-hook context snapshot isolation so hook-side mutation cannot leak across callbacks or back into caller state, command-lifecycle `beforeCommand`/`afterCommand` execution with failure containment (including `afterCommand` dispatch on failed commands with `ok=false` and error context), and runtime read/write/index hook dispatch for core item-store reads/writes, create/restore item and history writes, settings read/write operations, history/activity history-directory scans and history-stream reads, health history-directory scans plus history-stream path dispatch, search item/linked reads, reindex flows, stats/health/gc command file-system paths (including `pm gc` onIndex dispatch with mode `gc` and deterministic cache-target totals), lock file read/write/unlink operations, init directory bootstrap ensure-write dispatch, and built-in beads/todos import-export source/item/history file operations.
|
|
485
|
-
|
|
486
|
-
Extension API baseline now includes deterministic command result override registration for existing core commands, command-handler registration for declared command paths (including built-in `beads import` and `todos import|export` paths plus extension-defined non-core command paths surfaced at runtime), command-handler execution with cloned `args`/`options`/`global` snapshots to prevent mutation leakage back into caller command state, command-override execution with cloned command `args`/`options`/`global` snapshots plus `pm_root` metadata and isolated prior-result snapshots, renderer execution with the same cloned command-context snapshots plus isolated result snapshots, renderer override registration for `toon`/`json` output formatting with safe fallback to built-in rendering on failures, and registration-time validation plus metadata capture for `registerFlags`, `registerItemFields`, `registerMigration`, `registerImporter`, `registerExporter`, `registerSearchProvider`, and `registerVectorStoreAdapter`. `registerImporter`/`registerExporter` registrations now also wire deterministic extension command-handler paths `<name> import` and `<name> export` (canonicalized with trim + lowercase + internal-whitespace collapse), and those handlers execute with the same isolated command-context snapshots as explicit `registerCommand` handlers. Dynamically surfaced extension command paths now include deterministic help sections derived from `registerFlags` metadata while preserving loose option parsing for runtime dispatch, with parser hardening that ignores unsafe prototype keys (`__proto__`, `constructor`, `prototype`) and uses null-prototype option maps before handing parsed options to extension handlers. Extension API and hook registration calls now enforce manifest capability declarations (`commands`, `renderers`, `hooks`, `schema`, `importers`, `search`) and fail activation deterministically when registrations exceed declared capabilities. Unknown capability names are ignored for registration gating and emit deterministic discovery diagnostics `extension_capability_unknown:<layer>:<name>:<capability>`. Activation diagnostics now include deterministic registration summaries for these registries, and health diagnostics include deterministic migration status summaries derived from registered migration definitions (`status=\"failed\"` -> failed, `status=\"applied\"` -> applied, otherwise pending). Core write command paths now enforce deterministic mandatory-migration blocking when registered migration definitions declare `mandatory=true` and status is not `applied` (case-insensitive), with explicit `--force` bypass support on force-capable write commands. Broader runtime wiring for other newly registered definitions remains tracked in `PRD.md`.
|
|
487
|
-
|
|
488
|
-
## Pi Agent Extension
|
|
489
|
-
|
|
490
|
-
`pm-cli` ships a Pi agent extension source module at `.pi/extensions/pm-cli/index.ts`.
|
|
491
|
-
|
|
492
|
-
Install it via `pm` (recommended):
|
|
493
|
-
|
|
494
|
-
```bash
|
|
495
|
-
# current project scope (default)
|
|
496
|
-
pm install pi
|
|
497
|
-
|
|
498
|
-
# explicit project scope
|
|
499
|
-
pm install pi --project
|
|
500
|
-
|
|
501
|
-
# global Pi scope (~/.pi/agent unless PI_CODING_AGENT_DIR is set)
|
|
502
|
-
pm install pi --global
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
Load it in Pi:
|
|
506
|
-
|
|
507
|
-
```bash
|
|
508
|
-
pi -e ./.pi/extensions/pm-cli/index.ts
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
Or place/copy it into a Pi auto-discovery folder such as `.pi/extensions/`.
|
|
512
|
-
|
|
513
|
-
The extension registers one tool, `pm`, with action-based parameters and returns:
|
|
514
|
-
|
|
515
|
-
- `content: [{ type: "text", text: "..." }]`
|
|
516
|
-
- `details: { ... }`
|
|
517
|
-
|
|
518
|
-
For search parity, wrapper parameters support `includeLinked` and map it to `pm search --include-linked`.
|
|
519
|
-
For project tracking access in Pi TUI, run Pi from the project root (so `pm` resolves the repo `.agents/pm`), or pass wrapper `path` to target another PM store.
|
|
520
|
-
For command-shape parity, explicit empty-string values are forwarded for empty-allowed flags (for example `--description ""` and `--body ""`) instead of being dropped.
|
|
521
|
-
For numeric-flag parity, wrapper parameters accept either JSON numbers or strings for `priority`, `estimate`, `limit`, and `timeout`, and stringify them before CLI invocation.
|
|
522
|
-
For claim/release parity, wrapper parameters `author`, `message`, and `force` are forwarded to `pm claim|release --author/--message/--force`.
|
|
523
|
-
For packaging resilience (implemented), the wrapper attempts `pm` first and falls back to `node <package-root>/dist/cli.js` when `pm` is unavailable.
|
|
524
|
-
|
|
525
|
-
## Shell Completion
|
|
526
|
-
|
|
527
|
-
`pm` supports tab-completion for bash, zsh, and fish shells.
|
|
528
|
-
|
|
529
|
-
### Bash
|
|
530
|
-
|
|
531
|
-
```bash
|
|
532
|
-
# Add to ~/.bashrc or ~/.bash_profile
|
|
533
|
-
eval "$(pm completion bash)"
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
### Zsh
|
|
537
|
-
|
|
538
|
-
```bash
|
|
539
|
-
# Add to ~/.zshrc
|
|
540
|
-
eval "$(pm completion zsh)"
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
### Fish
|
|
544
|
-
|
|
545
|
-
```bash
|
|
546
|
-
# Generate and save the completion file
|
|
547
|
-
pm completion fish > ~/.config/fish/completions/pm.fish
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
### JSON output
|
|
551
|
-
|
|
552
|
-
```bash
|
|
553
|
-
pm completion bash --json
|
|
554
|
-
# => { "shell": "bash", "script": "...", "setup_hint": "..." }
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
Completion covers all `pm` subcommands, their flags, and common argument values (item types, statuses, priorities, search modes, shell names).
|
|
558
|
-
|
|
559
|
-
## FAQ
|
|
560
|
-
|
|
561
|
-
### Why JSON front-matter instead of YAML?
|
|
562
|
-
|
|
563
|
-
Deterministic parsing/serialization and fewer parser ambiguities for agent tooling.
|
|
564
|
-
|
|
565
|
-
### Why TOON by default?
|
|
566
|
-
|
|
567
|
-
TOON reduces token usage and keeps structure predictable for LLM workflows.
|
|
568
|
-
|
|
569
|
-
### Can I use `pm` without semantic search?
|
|
570
|
-
|
|
571
|
-
Yes. Keyword mode is always available.
|
|
572
|
-
|
|
573
|
-
### Is a database required?
|
|
574
|
-
|
|
575
|
-
No for core tracking. Core is file-backed. Vector DB is optional for semantic search.
|
|
576
|
-
|
|
577
|
-
### Can I restore previous versions?
|
|
578
|
-
|
|
579
|
-
Yes. `pm` supports restoring an item to a prior state by timestamp or history version:
|
|
580
|
-
|
|
581
|
-
```bash
|
|
582
|
-
pm restore <ID> <TIMESTAMP|VERSION>
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
Restore replays append-only history to the target point, rewrites the item atomically, and appends a new `restore` history event.
|
|
586
|
-
|
|
587
|
-
## Troubleshooting
|
|
588
|
-
|
|
589
|
-
### Item not found
|
|
590
|
-
|
|
591
|
-
- Use normalized id and check:
|
|
592
|
-
- `pm list-all --limit 100 --json`
|
|
593
|
-
|
|
594
|
-
### Command appears missing
|
|
595
|
-
|
|
596
|
-
- Check `pm --help` for the implemented command surface in this version.
|
|
597
|
-
- Confirm whether the command is listed under "Roadmap (post-v0.1 / partial areas)".
|
|
598
|
-
|
|
599
|
-
## Testing and Coverage Policy
|
|
600
|
-
|
|
601
|
-
- All tests must run with a sandbox `PM_PATH` (never the repository's real `.agents/pm`).
|
|
602
|
-
- PM-linked test execution should use `node scripts/run-tests.mjs <test|coverage> [-- <vitest args...>]` so both `PM_PATH` and `PM_GLOBAL_PATH` are sandboxed per run; forwarded args target Vitest directly (for example: `node scripts/run-tests.mjs test -- tests/unit/health-command.spec.ts`).
|
|
603
|
-
- `pm test <ID>` linked command entries must not invoke `pm test-all` (including global-flag and package-spec launcher forms like `pm --json test-all`, `npx @unbrained/pm-cli@latest --json test-all`, `pnpm dlx @unbrained/pm-cli@latest --json test-all`, and `npm exec -- @unbrained/pm-cli@latest --json test-all`); the CLI rejects recursive orchestration entries at add-time.
|
|
604
|
-
- `pm test <ID> --run` defensively skips legacy linked command entries that invoke `pm test-all` (including global-flag and package-spec launcher forms such as `npx`, `pnpm dlx`, and `npm exec` launcher variants) and reports deterministic skipped results.
|
|
605
|
-
- `pm test <ID>` linked test-runner command entries must use `node scripts/run-tests.mjs ...` or explicitly set both `PM_PATH` and `PM_GLOBAL_PATH`; the CLI rejects sandbox-unsafe variants at add-time, including unsandboxed package-manager run-script forms like `npm run test` / `pnpm run test` and chained direct test-runner segments that are not explicitly sandboxed.
|
|
606
|
-
- `pm test-all` runs each unique linked command/path key once per invocation and marks duplicates as skipped for deterministic orchestration output; duplicate-key timeout conflicts resolve to the maximum `timeout_seconds` for that key.
|
|
607
|
-
- Integration tests spawn the built CLI (`node dist/cli.js ...`) with test-specific `PM_PATH`, `PM_GLOBAL_PATH`, and `PM_AUTHOR`.
|
|
608
|
-
- Coverage thresholds are enforced at `100%` for lines, branches, functions, and statements.
|
|
609
|
-
- `pm` project data in `.agents/pm` is reserved for living planning/logging only.
|
|
610
|
-
|
|
611
|
-
## Community and Governance Files
|
|
612
|
-
|
|
613
|
-
Release-ready repository baseline includes:
|
|
614
|
-
|
|
615
|
-
- `LICENSE` (MIT)
|
|
616
|
-
- `CHANGELOG.md` (Keep a Changelog + SemVer note + `[Unreleased]`)
|
|
617
|
-
- `CONTRIBUTING.md` (development and contribution workflow)
|
|
618
|
-
- `SECURITY.md` (security reporting policy)
|
|
619
|
-
- `CODE_OF_CONDUCT.md` (contributor behavior baseline)
|
|
620
|
-
|
|
621
|
-
## Release Readiness Checklist
|
|
622
|
-
|
|
623
|
-
```bash
|
|
624
|
-
pnpm install
|
|
625
|
-
pnpm build
|
|
626
|
-
pnpm typecheck
|
|
627
|
-
pnpm test
|
|
628
|
-
pnpm test:coverage
|
|
629
|
-
pnpm version:check
|
|
630
|
-
pnpm security:scan
|
|
631
|
-
node scripts/run-tests.mjs coverage
|
|
632
|
-
pnpm smoke:npx
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
Manual smoke checks:
|
|
636
|
-
|
|
637
|
-
- install packed tarball globally and run `pm --help`
|
|
638
|
-
- run `bash scripts/install.sh`
|
|
639
|
-
- run `pwsh scripts/install.ps1`
|
|
640
|
-
|
|
641
|
-
### Automated Release
|
|
642
|
-
|
|
643
|
-
Pushing a version tag triggers the automated npm publish workflow:
|
|
644
|
-
|
|
645
|
-
```bash
|
|
646
|
-
git tag v2026.3.9
|
|
647
|
-
git push origin v2026.3.9
|
|
648
|
-
```
|
|
649
|
-
|
|
650
|
-
The `.github/workflows/release.yml` workflow runs full validation, enforces calendar version policy, and publishes `@unbrained/pm-cli` to npm only when all checks pass. It uses the `release` GitHub Environment and requires the `NPM_TOKEN` environment secret.
|
|
651
|
-
|
|
652
|
-
## Project Status
|
|
653
|
-
|
|
654
|
-
Release-hardening is active.
|
|
655
|
-
`PRD.md`, `AGENTS.md`, and this README define the current public and contributor contracts.
|
|
44
|
+
--tags "windows,locks,restore,release" \
|
|
45
|
+
--body "Users can reproduce this on Windows after an interrupted restore. Add retry logging and verify restore succeeds after stale lock cleanup." \
|
|
46
|
+
--deadline +3d \
|
|
47
|
+
--estimate 180 \
|
|
48
|
+
--acceptance-criteria "Restore succeeds after stale lock cleanup on Windows and regression coverage is added." \
|
|
49
|
+
--definition-of-ready "Owner, reproduction steps, and affected files are identified." \
|
|
50
|
+
--order 7 \
|
|
51
|
+
--goal "Release readiness" \
|
|
52
|
+
--objective "Stabilize restore under lock contention" \
|
|
53
|
+
--value "Reduces failed recovery workflows during real incidents" \
|
|
54
|
+
--impact "Fewer blocked releases and clearer operator recovery steps" \
|
|
55
|
+
--outcome "Restore completes reliably after stale lock cleanup" \
|
|
56
|
+
--why-now "The bug affects recovery flows and can block release work." \
|
|
57
|
+
--author "alex-maintainer" \
|
|
58
|
+
--message "Create restore failure issue with full metadata" \
|
|
59
|
+
--assignee "alex-maintainer" \
|
|
60
|
+
--parent "pm-release" \
|
|
61
|
+
--reviewer "sam-reviewer" \
|
|
62
|
+
--risk high \
|
|
63
|
+
--confidence medium \
|
|
64
|
+
--sprint "2026-W11" \
|
|
65
|
+
--release "v2026.3" \
|
|
66
|
+
--blocked-by "pm-locks" \
|
|
67
|
+
--blocked-reason "Need the lock cleanup refactor merged first" \
|
|
68
|
+
--unblock-note "Rebase once the lock cleanup patch lands" \
|
|
69
|
+
--reporter "qa-bot" \
|
|
70
|
+
--severity high \
|
|
71
|
+
--environment "windows-11 node-25 npm-global-install" \
|
|
72
|
+
--repro-steps "1) Interrupt restore after lock creation 2) Retry restore 3) Observe stale-lock cleanup fail on Windows" \
|
|
73
|
+
--resolution "Add a retry after stale-lock cleanup and log the recovery path" \
|
|
74
|
+
--expected-result "Restore retries cleanly and completes after stale-lock cleanup." \
|
|
75
|
+
--actual-result "Restore exits with a lock error after cleanup on Windows." \
|
|
76
|
+
--affected-version "2026.3.9" \
|
|
77
|
+
--fixed-version "2026.3.10" \
|
|
78
|
+
--component "core/locks" \
|
|
79
|
+
--regression true \
|
|
80
|
+
--customer-impact "Maintainers can be blocked from recovering work during release prep." \
|
|
81
|
+
--dep "id=pm-locks,kind=blocks,author=alex-maintainer,created_at=now" \
|
|
82
|
+
--comment "author=alex-maintainer,created_at=now,text=Initial triage confirms the Windows-only stale-lock recovery failure." \
|
|
83
|
+
--note "author=alex-maintainer,created_at=now,text=Investigate lock cleanup timing in the restore retry path." \
|
|
84
|
+
--learning "author=alex-maintainer,created_at=now,text=Windows file-handle timing needs a retry window after stale-lock cleanup." \
|
|
85
|
+
--file "path=src/core/lock/lock-store.ts,scope=project,note=likely stale-lock retry fix" \
|
|
86
|
+
--test "command=node scripts/run-tests.mjs test -- tests/integration/cli.integration.spec.ts,scope=project,timeout_seconds=900,note=restore lock regression coverage" \
|
|
87
|
+
--doc "path=docs/ARCHITECTURE.md,scope=project,note=lock and restore design context"
|
|
88
|
+
|
|
89
|
+
pm list-open --limit 10
|
|
90
|
+
pm claim <item-id>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
From there, use `pm update`, `pm comments`, `pm files`, `pm test`, `pm search`, and `pm close` as work progresses.
|
|
94
|
+
|
|
95
|
+
## Documentation
|
|
96
|
+
|
|
97
|
+
- [Architecture](docs/ARCHITECTURE.md)
|
|
98
|
+
- [Extensions](docs/EXTENSIONS.md)
|
|
99
|
+
- [Contributing](CONTRIBUTING.md)
|
|
100
|
+
- [Security Policy](SECURITY.md)
|
|
101
|
+
- [Changelog](CHANGELOG.md)
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT. See [LICENSE](LICENSE).
|