@open-agent-toolkit/cli 0.1.64 → 0.1.65
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/assets/docs/cli-utilities/backlog-lifecycle.md +2 -2
- package/assets/docs/cli-utilities/config-and-local-state.md +20 -6
- package/assets/docs/cli-utilities/tool-packs.md +1 -0
- package/assets/docs/cli-utilities/workflow-gates.md +3 -1
- package/assets/docs/contributing/code.md +18 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-pjm-add-backlog-item/SKILL.md +17 -72
- package/assets/skills/oat-project-summary/SKILL.md +9 -4
- package/assets/templates/plan.md +2 -0
- package/dist/commands/backlog/archive.d.ts.map +1 -1
- package/dist/commands/backlog/archive.js +5 -5
- package/dist/commands/backlog/index.d.ts +4 -0
- package/dist/commands/backlog/index.d.ts.map +1 -1
- package/dist/commands/backlog/index.js +55 -0
- package/dist/commands/backlog/new.d.ts +27 -0
- package/dist/commands/backlog/new.d.ts.map +1 -0
- package/dist/commands/backlog/new.js +158 -0
- package/dist/commands/backlog/regenerate-index.d.ts.map +1 -1
- package/dist/commands/backlog/regenerate-index.js +42 -3
- package/dist/commands/decision/index.d.ts.map +1 -1
- package/dist/commands/decision/index.js +4 -0
- package/dist/commands/decision/new.d.ts +2 -0
- package/dist/commands/decision/new.d.ts.map +1 -1
- package/dist/commands/decision/new.js +4 -2
- package/dist/commands/doctor/index.d.ts +1 -0
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +3 -0
- package/dist/commands/doctor/stale-invocations.d.ts +3 -0
- package/dist/commands/doctor/stale-invocations.d.ts.map +1 -0
- package/dist/commands/doctor/stale-invocations.js +173 -0
- package/dist/commands/gate/index.d.ts +1 -0
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +5 -1
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +24 -9
- package/dist/commands/tools/update/index.d.ts.map +1 -1
- package/dist/commands/tools/update/index.js +22 -12
- package/package.json +2 -2
|
@@ -42,11 +42,11 @@ oat backlog archive BL-260705-example --wont-do --summary "superseded by BL-2607
|
|
|
42
42
|
A single `oat backlog archive` run performs the whole close-out so its parts cannot drift apart:
|
|
43
43
|
|
|
44
44
|
1. Sets the terminal `status` (`closed` by default, `wont_do` with `--wont-do`) and stamps `updated`.
|
|
45
|
-
2.
|
|
45
|
+
2. Validates and trims a nonblank `--summary` before mutating a `closed` item, then appends its canonical newest-first `completed.md` entry. `wont_do` items may omit the summary and get an entry only when one is provided.
|
|
46
46
|
3. Moves `items/<id>.md` into `archived/` — with `git mv` inside a work tree, or a plain rename outside git.
|
|
47
47
|
4. Regenerates the managed backlog index.
|
|
48
48
|
|
|
49
|
-
The command is safe to re-run: an item already in `archived/` produces a no-op warning with no writes.
|
|
49
|
+
The command is safe to re-run: an item already in `archived/` produces a no-op warning with no writes. A missing closed-item summary or an out-of-enum current status (for example a hand-set `done`) is a hard error before mutation and includes recovery guidance. See the [command reference](config-and-local-state.md#oat-backlog-archive) for exit codes and the `--json` payload.
|
|
50
50
|
|
|
51
51
|
## Catching lifecycle drift
|
|
52
52
|
|
|
@@ -14,6 +14,7 @@ Use these commands when you need operational support around the toolkit rather t
|
|
|
14
14
|
Use the `oat backlog` group when you want direct CLI support for the file-backed backlog under `.oat/repo/pjm/backlog/`.
|
|
15
15
|
|
|
16
16
|
- `oat backlog init` - scaffold `.oat/repo/pjm/backlog/` with starter files and directories for a fresh repo
|
|
17
|
+
- `oat backlog new <title>` - validate and create a file-backed backlog item from the canonical template, then regenerate the managed index
|
|
17
18
|
- `oat backlog generate-id <title>` - generate a deterministic `BL-YYMMDD-slug` backlog ID from a title
|
|
18
19
|
- `oat backlog generate-id <title> --created-at <timestamp>` - generate a reproducible ID for a known creation timestamp
|
|
19
20
|
- `oat backlog archive <id>` - atomic close-out: set a terminal status, record the completion in `completed.md`, move the item into `archived/`, and regenerate the index in one step
|
|
@@ -21,10 +22,18 @@ Use the `oat backlog` group when you want direct CLI support for the file-backed
|
|
|
21
22
|
|
|
22
23
|
Backlog IDs are deterministic date+slug identifiers (`BL-YYMMDD-slug`) derived from the creation date and title, so two machines or worktrees produce the same ID for the same record without scanning the local checkout. The slug is capped at 30 characters at the last whole-word boundary (with trailing stop-words trimmed), so prefer concise, meaningful titles. Index regeneration is deterministic and safe to re-run when resolving an index merge conflict.
|
|
23
24
|
|
|
24
|
-
Run `oat backlog init`
|
|
25
|
+
Run `oat backlog init` directly when you need to create or repair only the backlog scaffold. `oat backlog new` initializes a missing scaffold automatically after validating its inputs. This command group is primarily used by the `oat-pjm-*` project-management skills, but it is also available directly when you need to inspect or repair backlog metadata by hand.
|
|
25
26
|
|
|
26
27
|
For the end-to-end states an item moves through — and how `oat backlog archive` and `oat pjm doctor` keep the backlog honest — see [Backlog Lifecycle](backlog-lifecycle.md).
|
|
27
28
|
|
|
29
|
+
### `oat backlog new`
|
|
30
|
+
|
|
31
|
+
`oat backlog new <title> [--priority <priority>] [--scope <scope>] [--scope-estimate <size>] [--labels <labels>] [--description <text>] [--backlog-root <path>]` creates one active item and refreshes the managed backlog index.
|
|
32
|
+
|
|
33
|
+
Defaults are `priority: medium` and `scope: task`. Valid priorities are `urgent`, `high`, `medium`, `low`, and `none`; valid scopes are `idea`, `task`, `feature`, and `initiative`; scope estimates accept `XS`, `S`, `M`, `L`, `XL`, or `XXL`. Pass labels as a comma-delimited list.
|
|
34
|
+
|
|
35
|
+
The command validates all inputs before creating the scaffold or writing an item. It uses the repo-local canonical backlog template when available, falls back to the CLI's bundled template, writes structured YAML frontmatter, and rejects an ID collision in either `items/` or `archived/` without overwriting the existing record. If managed-index regeneration fails after the item write, OAT removes only the new item and restores the prior index.
|
|
36
|
+
|
|
28
37
|
### `oat backlog archive`
|
|
29
38
|
|
|
30
39
|
`oat backlog archive <id> [--wont-do] [--summary <text>] [--json] [--backlog-root <path>]` performs the full close-out for a backlog item so status flip, completed-log entry, file move, and index regeneration never drift apart.
|
|
@@ -33,22 +42,23 @@ For the end-to-end states an item moves through — and how `oat backlog archive
|
|
|
33
42
|
|
|
34
43
|
- `<id>` (required) - the backlog item id (`BL-YYMMDD-slug`); the item file must live under `items/`.
|
|
35
44
|
- `--wont-do` - close the item as `wont_do` instead of the default terminal status `closed`.
|
|
36
|
-
- `--summary <text>` - one-line outcome summary recorded in `completed.md
|
|
45
|
+
- `--summary <text>` - one-line outcome summary recorded in `completed.md`; required and nonblank for the default `closed` path.
|
|
37
46
|
- `--backlog-root <path>` - override the backlog root (defaults to `.oat/repo/pjm/backlog`).
|
|
38
47
|
- `--json` - emit the machine-readable result payload instead of human log lines.
|
|
39
48
|
|
|
40
49
|
**Behavior:**
|
|
41
50
|
|
|
42
51
|
- Validates the item's current `status` against the enum (`open | in_progress | closed | wont_do`); an out-of-enum value such as `done` is a hard error with a fix hint. Archiving is legal from any valid status — a `closed` item still in `items/` just gets its move finished.
|
|
52
|
+
- For the default `closed` path, validates and trims a nonblank `--summary` before any file or index mutation. The `wont_do` path may omit the summary and completion-ledger entry.
|
|
43
53
|
- Rewrites only the `status:` and `updated:` frontmatter lines (preserving any inline enum comment), then moves the item from `items/` to `archived/` with `git mv` inside a work tree, falling back to a plain rename (with a warning) outside git or if `git mv` fails.
|
|
44
|
-
- `closed` archives
|
|
54
|
+
- `closed` archives append a canonical newest-first `completed.md` entry (`YYYY-MM-DD — <id> — Title — summary`). `wont_do` archives append an entry only when `--summary` is provided. A missing `completed.md` is scaffolded from the starter template; a missing `## Completed Items` heading is scaffolded with a warning.
|
|
45
55
|
- Regenerates the managed backlog index after the move.
|
|
46
56
|
- Idempotent: re-running on an item already in `archived/` is a no-op warning with no writes.
|
|
47
57
|
|
|
48
58
|
**Exit codes:**
|
|
49
59
|
|
|
50
60
|
- `0` - item archived, or already-archived no-op.
|
|
51
|
-
- `1` - actionable error: unknown id
|
|
61
|
+
- `1` - actionable error: unknown id, out-of-enum current status, duplicate active/archived ID, or a missing closed-item summary. The message includes the recovery action.
|
|
52
62
|
- `2` - reserved for unexpected system/runtime failures.
|
|
53
63
|
|
|
54
64
|
**JSON payload (`--json`):**
|
|
@@ -76,10 +86,12 @@ For full project-management repo-reference setup, use [`oat pjm init`](tool-pack
|
|
|
76
86
|
Use the `oat decision` group for file-per-record decisions under `.oat/repo/reference/decisions/`. Each decision is its own file with a deterministic `DR-YYMMDD-slug` ID (the slug is capped at 30 characters at the last whole-word boundary, with trailing stop-words trimmed), and the human-facing index is a committed generated view.
|
|
77
87
|
|
|
78
88
|
- `oat decision init` - scaffold `.oat/repo/reference/decisions/` and the managed decision index
|
|
79
|
-
- `oat decision new <title>` - create a new decision record; supports `--status`, `--context`, and `--created-at`
|
|
89
|
+
- `oat decision new <title>` - create a new decision record; supports `--status`, `--context`, `--decision`, `--consequences`, and `--created-at`
|
|
80
90
|
- `oat decision regenerate-index` - rebuild the managed decision index table from record frontmatter
|
|
81
91
|
- `oat decision migrate` - convert a legacy single `decision-record.md` into file-per-record decisions, preserving each old `ADR-NNN`/`DR-NNN` ID as `legacy_id`; applies by default, so pass `--dry-run` to preview the legacy-to-new mappings without writing, and `--delete-legacy` to remove the source file after a verified migration (unlike `oat pjm migrate`, which defaults to dry-run)
|
|
82
92
|
|
|
93
|
+
Pass `--context`, `--decision`, and `--consequences` together when creating a resolved decision so every substantive template section is complete in the same atomic creation step. Callers that omit them retain the template's placeholder content for later editing.
|
|
94
|
+
|
|
83
95
|
The decision index uses managed marker pairs and is deterministic, so an index merge conflict can be resolved by re-running `oat decision regenerate-index` and staging the result. Decision records replace the legacy single `decision-record.md`; repos still on the old layout migrate with `oat decision migrate` (or the broader `oat pjm migrate`).
|
|
84
96
|
|
|
85
97
|
## `oat local ...`
|
|
@@ -239,4 +251,6 @@ For the full state model, repair semantics, and examples, see [Instruction Sync]
|
|
|
239
251
|
- `oat internal validate-oat-skills` - validate `oat-*` skill contracts and metadata
|
|
240
252
|
- `oat doctor` - run environment and setup diagnostics, including installed-vs-bundled skill version checks
|
|
241
253
|
|
|
242
|
-
`oat doctor` is the quickest way to confirm that your runtime, directory structure, and installed OAT assets are healthy before deeper debugging.
|
|
254
|
+
`oat doctor` is the quickest way to confirm that your runtime, directory structure, and installed OAT assets are healthy before deeper debugging. At project scope it also scans bounded repository script and documentation surfaces for known-stale CLI grammar, such as `oat --scope all sync`, and reports file/line evidence plus the current `oat sync --scope all` form. Generated provider views, OAT lifecycle artifacts, archived content, dependencies, build output, and nested worktrees are excluded.
|
|
255
|
+
|
|
256
|
+
The `/oat-doctor` skill (installed via the core pack) provides richer diagnostics with check and summary modes, including config explanations sourced from bundled documentation.
|
|
@@ -171,6 +171,7 @@ Purpose:
|
|
|
171
171
|
Key behavior:
|
|
172
172
|
|
|
173
173
|
- Accepts a tool name, `--pack <pack>`, or `--all` (mutually exclusive)
|
|
174
|
+
- With no target, exits without mutation and suggests the explicit bulk command `oat tools update --all`; invalid packs and conflicting targets keep their own targeted diagnostics
|
|
174
175
|
- Compares installed versions against bundled versions and copies updated assets
|
|
175
176
|
- For `--pack <pack>` and `--all`, an already-installed pack is reconciled to include newly added bundled skills or agents in that same scope
|
|
176
177
|
- Pack-targeted updates intentionally rewrite bundled template and script companions in place, even when the pack's installed skills are already current
|
|
@@ -451,7 +451,9 @@ By default the dispatcher:
|
|
|
451
451
|
5. Applies `--avoid same-family`.
|
|
452
452
|
6. Checks candidate availability in descending priority order, with target id as
|
|
453
453
|
the tie-breaker.
|
|
454
|
-
7. Runs the chosen `baseCommand` with the selected model and prompt appended.
|
|
454
|
+
7. Runs the chosen `baseCommand` with the selected model and prompt appended. The
|
|
455
|
+
prompt is carried in argv, stdin is closed, and stdout/stderr remain captured
|
|
456
|
+
for diagnostics and liveness tracking.
|
|
455
457
|
8. Exits with the child process status.
|
|
456
458
|
|
|
457
459
|
Use `--target <id>` to pin one target and skip detection/avoidance:
|
|
@@ -96,6 +96,24 @@ not the steady-state path.
|
|
|
96
96
|
- Make verification explicit in commit-adjacent notes or review artifacts.
|
|
97
97
|
- If docs behavior changes, update the docs surface in the same change window.
|
|
98
98
|
|
|
99
|
+
### Breaking CLI grammar changes
|
|
100
|
+
|
|
101
|
+
When a command, option name, or option placement changes, make the migration visible to both reviewers and release-note readers:
|
|
102
|
+
|
|
103
|
+
- Use a `BREAKING:` PR title or prominent callout so generated release notes retain the warning.
|
|
104
|
+
- Include the old and new copy-pasteable commands.
|
|
105
|
+
- State the migration action for scripts, docs, and automation that use the old grammar.
|
|
106
|
+
|
|
107
|
+
For example:
|
|
108
|
+
|
|
109
|
+
**Breaking change title/callout:** `BREAKING: move scope after the sync command`
|
|
110
|
+
|
|
111
|
+
**Before:** `oat --scope all sync` <!-- oat-doctor: allow-stale-invocation -->
|
|
112
|
+
|
|
113
|
+
**After:** `oat sync --scope all`
|
|
114
|
+
|
|
115
|
+
**Migration action:** Update repository scripts and documentation, then run `oat doctor --scope project` to find known-stale invocations.
|
|
116
|
+
|
|
99
117
|
## Related Guides
|
|
100
118
|
|
|
101
119
|
- [Contributing Docs](documentation.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-pjm-add-backlog-item
|
|
3
|
-
version: 1.3.
|
|
3
|
+
version: 1.3.1
|
|
4
4
|
description: Use when the user requests or confirms adding a new repo backlog item — e.g. "add a backlog item for X", "capture that as backlog", "track that follow-up", "file a backlog ticket", or confirms a previously offered backlog capture. Do NOT auto-invoke when a follow-up is mentioned. Creates the item file in the file-per-item backlog structure, regenerates the index, and prompts for curated overview updates.
|
|
5
5
|
disable-model-invocation: false
|
|
6
6
|
user-invocable: true
|
|
@@ -29,8 +29,8 @@ When executing this skill, provide lightweight progress feedback so the user can
|
|
|
29
29
|
|
|
30
30
|
- Before multi-step work, print short step indicators, e.g.:
|
|
31
31
|
- `[1/4] Resolving item details…`
|
|
32
|
-
- `[2/4]
|
|
33
|
-
- `[3/4]
|
|
32
|
+
- `[2/4] Creating the item + managed index atomically…`
|
|
33
|
+
- `[3/4] Enriching acceptance criteria…`
|
|
34
34
|
- `[4/4] Updating curated overview guidance…`
|
|
35
35
|
|
|
36
36
|
## Process
|
|
@@ -47,85 +47,30 @@ Collect the item details from the user or surrounding context:
|
|
|
47
47
|
If the title is missing, ask the user.
|
|
48
48
|
If the description is missing, ask for 1-3 sentences of context.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
Propose an initial scope estimate (`XS`, `S`, `M`, `L`, `XL`, or `XXL`) from the described work, then ask the user to confirm or adjust it before creation.
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
### Step 2: Create the Backlog Item Atomically
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
oat backlog init
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
This command is idempotent. Use it even in existing repos so the canonical backlog scaffold and exact managed index markers are present before `oat backlog regenerate-index` runs.
|
|
59
|
-
|
|
60
|
-
Do not hand-create the managed marker block in `backlog/index.md`. The scaffold writes the exact markers required by the CLI:
|
|
61
|
-
|
|
62
|
-
```md
|
|
63
|
-
<!-- OAT BACKLOG-INDEX -->
|
|
64
|
-
<!-- END OAT BACKLOG-INDEX -->
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Step 3: Generate ID
|
|
68
|
-
|
|
69
|
-
Run:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
oat backlog generate-id "{title}"
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
The CLI returns a deterministic `BL-YYMMDD-slug` value derived from the creation date and the title. It performs no scan, hash, counter, or random allocation.
|
|
76
|
-
|
|
77
|
-
If the command reports a same-day same-slug filename collision against an existing `items/<id>.md` or `archived/<id>.md`, do not overwrite the existing record. Disambiguate by using a more specific title and re-running `oat backlog generate-id`.
|
|
78
|
-
|
|
79
|
-
### Step 4: Prepare Output Path
|
|
80
|
-
|
|
81
|
-
Set the output path using the returned ID so the filename stem equals the ID:
|
|
54
|
+
Run the single creation command with the confirmed values:
|
|
82
55
|
|
|
83
56
|
```bash
|
|
84
|
-
|
|
57
|
+
oat backlog new "{title}" --priority "<priority>" --scope "<scope>" --scope-estimate "<confirmed-scope-estimate>" --labels "<comma-delimited-labels>" --description "<description>"
|
|
85
58
|
```
|
|
86
59
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
1. Use `.oat/templates/backlog-item.md` as the source template.
|
|
90
|
-
2. Fill:
|
|
91
|
-
- `id`
|
|
92
|
-
- `title`
|
|
93
|
-
- `created`
|
|
94
|
-
- `updated`
|
|
95
|
-
- `status` (default `open`)
|
|
96
|
-
- `priority` (default `medium` unless the user says otherwise)
|
|
97
|
-
- `scope` (default `task` unless the user says otherwise)
|
|
98
|
-
- `labels`
|
|
99
|
-
- `assignee`
|
|
100
|
-
- `associated_issues`
|
|
101
|
-
- `external_plans` (initialize to `[]`; `oat-repo-improve` owns later reverse-link additions)
|
|
102
|
-
3. Keep `external_plans` as a YAML string array of repo-relative paths under `.oat/repo/reference/external-plans/`. Do not pre-populate it from discussion or anticipated work.
|
|
103
|
-
4. The agent should propose an initial `scope_estimate` based on the described work, then ask the user to confirm or adjust it.
|
|
104
|
-
5. Write the item body with:
|
|
105
|
-
- `## Description`
|
|
106
|
-
- `## Acceptance Criteria`
|
|
107
|
-
|
|
108
|
-
### Step 6: Write the Backlog Item
|
|
109
|
-
|
|
110
|
-
Write the completed file to the path resolved in Step 4:
|
|
60
|
+
The command validates all inputs, initializes the scaffold when needed, generates and collision-checks the `BL-YYMMDD-slug` ID, renders the canonical template, writes the item, and regenerates the managed index. If it reports a collision, do not overwrite the existing active or archived record; use a more specific title and rerun the same command.
|
|
111
61
|
|
|
112
|
-
|
|
113
|
-
.oat/repo/pjm/backlog/items/{id}.md
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Use the template field order from `.oat/templates/backlog-item.md`.
|
|
62
|
+
Use the item path and ID reported by the command. Do not hand-author frontmatter or edit the managed index block. The command initializes `external_plans: []`; `oat-repo-improve` owns later reverse-link additions.
|
|
117
63
|
|
|
118
|
-
### Step
|
|
64
|
+
### Step 3: Enrich Acceptance Criteria
|
|
119
65
|
|
|
120
|
-
|
|
66
|
+
Read the created item and replace only the placeholder bullets under `## Acceptance Criteria` with the acceptance criteria confirmed in Step 1. Preserve the command-generated frontmatter and description. This post-create enrichment is safe because Acceptance Criteria are not index-visible fields.
|
|
121
67
|
|
|
122
|
-
|
|
123
|
-
oat backlog regenerate-index
|
|
124
|
-
```
|
|
68
|
+
The item must retain both required body sections:
|
|
125
69
|
|
|
126
|
-
|
|
70
|
+
- `## Description`
|
|
71
|
+
- `## Acceptance Criteria`
|
|
127
72
|
|
|
128
|
-
### Step
|
|
73
|
+
### Step 4: Update Curated Overview
|
|
129
74
|
|
|
130
75
|
Read `.oat/repo/pjm/backlog/index.md` and update the `## Curated Overview` section with a brief human-written note when helpful, for example:
|
|
131
76
|
|
|
@@ -135,7 +80,7 @@ Read `.oat/repo/pjm/backlog/index.md` and update the `## Curated Overview` secti
|
|
|
135
80
|
|
|
136
81
|
Do not edit inside the managed marker section.
|
|
137
82
|
|
|
138
|
-
### Step
|
|
83
|
+
### Step 5: Summarize to the User
|
|
139
84
|
|
|
140
85
|
Report:
|
|
141
86
|
|
|
@@ -151,5 +96,5 @@ Report:
|
|
|
151
96
|
- Item includes populated frontmatter and both required body sections
|
|
152
97
|
- Item initializes `external_plans: []` for future reverse links
|
|
153
98
|
- `scope_estimate` was proposed and confirmed
|
|
154
|
-
- `oat backlog
|
|
99
|
+
- `oat backlog new` created the item and regenerated the managed index successfully
|
|
155
100
|
- `.oat/repo/pjm/backlog/index.md` remains valid, with managed section untouched except by regeneration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-summary
|
|
3
|
-
version: 1.3.
|
|
3
|
+
version: 1.3.2
|
|
4
4
|
description: Use when the user requests or confirms summarizing an active OAT project — e.g. "summarize the project", "generate the summary", "run oat-project-summary", or confirms a previously offered summary run. Do NOT auto-invoke when implementation completes. Generates summary.md from project artifacts as institutional memory.
|
|
5
5
|
disable-model-invocation: false
|
|
6
6
|
user-invocable: true
|
|
@@ -278,7 +278,12 @@ test -f .oat/repo/reference/decisions/index.md || oat decision init
|
|
|
278
278
|
|
|
279
279
|
**6.4 — Idempotent, date-independent promotion (critical).** For each decision in `## Key Decisions`:
|
|
280
280
|
|
|
281
|
-
1. **Derive title +
|
|
281
|
+
1. **Derive title + complete sections.** Ground every value in the Key Decision and its project artifacts:
|
|
282
|
+
- The bold lead-in / first clause becomes the **title** (a short noun phrase).
|
|
283
|
+
- The problem, constraint, or motivating rationale becomes **context**.
|
|
284
|
+
- The choice that was made becomes the **decision**.
|
|
285
|
+
- The resulting tradeoffs, follow-on effects, or operational implications become **consequences**.
|
|
286
|
+
Each section must contain concrete grounded prose; do not pass placeholder content.
|
|
282
287
|
2. **Compute the slug the CLI would use.** The CLI generates the record ID as `DR-<YYMMDD>-<slug>`, where `<slug>` is the lowercased, ASCII-folded, hyphen-collapsed form of the title, capped at 30 characters at the last whole-word boundary with trailing stop-words (`a, an, the, of, for, and, to, in, on, as, with`) trimmed (the same slug rule the CLI applies). Compute that `<slug>` for the title.
|
|
283
288
|
3. **Dedup on the exact slug, ignoring only the date prefix.** A record ID is `DR-<YYMMDD>-<slug>`, where the date is exactly six digits. Check whether a record for this slug already exists by stripping that fixed `DR-<6 digits>-` prefix from existing record IDs and comparing the remaining slug for **exact equality**. Anchor the date to exactly six characters so the slug must match in full:
|
|
284
289
|
|
|
@@ -294,10 +299,10 @@ test -f .oat/repo/reference/decisions/index.md || oat decision init
|
|
|
294
299
|
- Otherwise → create it:
|
|
295
300
|
|
|
296
301
|
```bash
|
|
297
|
-
oat decision new "<title>" --status accepted --context "<
|
|
302
|
+
oat decision new "<title>" --status accepted --context "<context>" --decision "<decision>" --consequences "<consequences>"
|
|
298
303
|
```
|
|
299
304
|
|
|
300
|
-
The command generates the deterministic `DR-YYMMDD-slug` ID,
|
|
305
|
+
The command generates the deterministic `DR-YYMMDD-slug` ID, fills every decision body section, and regenerates the managed index automatically — do not hand-edit `index.md`. Optionally pass `--created-at "<project completion date>"` when a project completion date is available, so the record's date reflects when the decision was made.
|
|
301
306
|
|
|
302
307
|
Because of the date-independent slug dedup, this step is **safe to run every time `summary.md` is (re)generated** — including the pr-final refresh and revision re-runs — without ever creating duplicate decision records. Already-promoted decisions are skipped; only genuinely new Key Decisions become new records.
|
|
303
308
|
|
package/assets/templates/plan.md
CHANGED
|
@@ -65,6 +65,8 @@ Codex effort values are preferred controls. `oat-project-implement` caps them wh
|
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
68
|
+
RED/GREEN/Refactor is the recommended default where work is testable, not a validator requirement. Other task-body shapes, including non-TDD shapes, are allowed when appropriate, provided the plan preserves stable `pNN-tNN` IDs, per-task verification, and atomic commits.
|
|
69
|
+
|
|
68
70
|
## Phase 1: {Phase Name}
|
|
69
71
|
|
|
70
72
|
### Task p01-t01: {Task Name}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/archive.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,iBAAiB,EAGvB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/archive.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,iBAAiB,EAGvB,MAAM,sBAAsB,CAAC;AAmB9B,mDAAmD;AACnD,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;IAC5B,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;IACrD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,CAAC,GAAG,CAAK;CAKjD;AAkID;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CAqHnC"}
|
|
@@ -8,7 +8,6 @@ import { regenerateBacklogIndex } from './regenerate-index.js';
|
|
|
8
8
|
import { BACKLOG_ITEM_STATUSES, extractBacklogStatus, isValidBacklogStatus, } from './shared/item-status.js';
|
|
9
9
|
const execFileAsync = promisify(execFile);
|
|
10
10
|
const COMPLETED_HEADING = '## Completed Items';
|
|
11
|
-
const TODO_SUMMARY = 'TODO: summarize outcome';
|
|
12
11
|
const STARTER_COMPLETED = [
|
|
13
12
|
'# OAT Backlog Completed',
|
|
14
13
|
'',
|
|
@@ -178,6 +177,10 @@ export async function archiveBacklogItem(backlogRoot, id, options = {}) {
|
|
|
178
177
|
throw new BacklogArchiveError(`Backlog item ${itemsPath} has invalid status "${currentStatus ?? ''}". Valid statuses: ${BACKLOG_ITEM_STATUSES.join(', ')}. Fix: correct the \`status\` field manually, then re-run \`oat backlog archive ${id}\`.`);
|
|
179
178
|
}
|
|
180
179
|
const targetStatus = options.wontDo ? 'wont_do' : 'closed';
|
|
180
|
+
const summary = options.summary?.trim() ?? '';
|
|
181
|
+
if (targetStatus === 'closed' && summary.length === 0) {
|
|
182
|
+
throw new BacklogArchiveError(`Closing backlog item ${id} requires a non-empty outcome summary. Fix: rerun with \`--summary "<outcome>"\`.`);
|
|
183
|
+
}
|
|
181
184
|
const now = options.now ?? new Date();
|
|
182
185
|
const updatedIso = now.toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
183
186
|
const entryDate = updatedIso.slice(0, 10);
|
|
@@ -188,11 +191,8 @@ export async function archiveBacklogItem(backlogRoot, id, options = {}) {
|
|
|
188
191
|
// 5. completed.md entry — always for `closed`; only with a summary for
|
|
189
192
|
// `wont_do`.
|
|
190
193
|
let completedEntry = 'skipped';
|
|
191
|
-
const shouldWriteEntry = targetStatus === 'closed' ||
|
|
194
|
+
const shouldWriteEntry = targetStatus === 'closed' || summary.length > 0;
|
|
192
195
|
if (shouldWriteEntry) {
|
|
193
|
-
const summary = options.summary?.trim()
|
|
194
|
-
? options.summary.trim()
|
|
195
|
-
: TODO_SUMMARY;
|
|
196
196
|
const entryLine = `- ${entryDate} — ${id} — ${title} — ${summary}`;
|
|
197
197
|
const completedPath = join(backlogRoot, 'completed.md');
|
|
198
198
|
let scaffoldedFile = false;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { buildCommandContext } from '../../app/command-context.js';
|
|
2
|
+
import { resolveAssetsRoot } from '../../fs/assets.js';
|
|
2
3
|
import { resolveProjectRoot } from '../../fs/paths.js';
|
|
3
4
|
import { Command } from 'commander';
|
|
4
5
|
import { archiveBacklogItem } from './archive.js';
|
|
5
6
|
import { initializeBacklog } from './init.js';
|
|
7
|
+
import { createBacklogItem } from './new.js';
|
|
6
8
|
import { regenerateBacklogIndex } from './regenerate-index.js';
|
|
7
9
|
interface BacklogCommandDependencies {
|
|
8
10
|
buildCommandContext: typeof buildCommandContext;
|
|
9
11
|
resolveProjectRoot: typeof resolveProjectRoot;
|
|
12
|
+
resolveAssetsRoot: typeof resolveAssetsRoot;
|
|
10
13
|
initializeBacklog: typeof initializeBacklog;
|
|
11
14
|
regenerateBacklogIndex: typeof regenerateBacklogIndex;
|
|
15
|
+
createBacklogItem: typeof createBacklogItem;
|
|
12
16
|
archiveBacklogItem: typeof archiveBacklogItem;
|
|
13
17
|
pathExists: (path: string) => Promise<boolean>;
|
|
14
18
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAuB,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAuB,MAAM,WAAW,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAuB,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAuB,MAAM,WAAW,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AA8B5D,UAAU,0BAA0B;IAClC,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD;AA4CD,wBAAgB,oBAAoB,CAClC,SAAS,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAClD,OAAO,CAqQT"}
|
|
@@ -2,10 +2,12 @@ import { access } from 'node:fs/promises';
|
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
3
|
import { buildCommandContext } from '../../app/command-context.js';
|
|
4
4
|
import { readGlobalOptions } from '../shared/shared.utils.js';
|
|
5
|
+
import { resolveAssetsRoot } from '../../fs/assets.js';
|
|
5
6
|
import { resolveProjectRoot } from '../../fs/paths.js';
|
|
6
7
|
import { Command } from 'commander';
|
|
7
8
|
import { archiveBacklogItem, BacklogArchiveError } from './archive.js';
|
|
8
9
|
import { initializeBacklog } from './init.js';
|
|
10
|
+
import { createBacklogItem } from './new.js';
|
|
9
11
|
import { regenerateBacklogIndex } from './regenerate-index.js';
|
|
10
12
|
import { generateBacklogId } from './shared/generate-id.js';
|
|
11
13
|
async function pathExistsDefault(path) {
|
|
@@ -26,8 +28,10 @@ async function pathExistsDefault(path) {
|
|
|
26
28
|
const DEFAULT_DEPENDENCIES = {
|
|
27
29
|
buildCommandContext,
|
|
28
30
|
resolveProjectRoot,
|
|
31
|
+
resolveAssetsRoot,
|
|
29
32
|
initializeBacklog,
|
|
30
33
|
regenerateBacklogIndex,
|
|
34
|
+
createBacklogItem,
|
|
31
35
|
archiveBacklogItem,
|
|
32
36
|
pathExists: pathExistsDefault,
|
|
33
37
|
};
|
|
@@ -60,6 +64,57 @@ export function createBacklogCommand(overrides = {}) {
|
|
|
60
64
|
}
|
|
61
65
|
process.exitCode = 0;
|
|
62
66
|
});
|
|
67
|
+
cmd
|
|
68
|
+
.command('new')
|
|
69
|
+
.description('Create a new file-backed backlog item')
|
|
70
|
+
.argument('<title>', 'Backlog item title')
|
|
71
|
+
.option('--priority <priority>', 'Item priority', 'medium')
|
|
72
|
+
.option('--scope <scope>', 'Item scope', 'task')
|
|
73
|
+
.option('--scope-estimate <size>', 'Optional scope estimate (XS|S|M|L|XL|XXL)')
|
|
74
|
+
.option('--labels <labels>', 'Comma-delimited labels', (value) => value.split(','))
|
|
75
|
+
.option('--description <text>', 'Initial description body text')
|
|
76
|
+
.option('--backlog-root <path>', 'Backlog root directory (defaults to .oat/repo/pjm/backlog)')
|
|
77
|
+
.action(async (title, options, command) => {
|
|
78
|
+
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
79
|
+
try {
|
|
80
|
+
const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
81
|
+
const backlogRoot = await resolveBacklogRoot(context, options.backlogRoot, dependencies);
|
|
82
|
+
const assetsRoot = await dependencies.resolveAssetsRoot();
|
|
83
|
+
const result = await dependencies.createBacklogItem({
|
|
84
|
+
backlogRoot,
|
|
85
|
+
assetsRoot,
|
|
86
|
+
templatesRoot: resolve(projectRoot, '.oat', 'templates'),
|
|
87
|
+
title,
|
|
88
|
+
priority: options.priority,
|
|
89
|
+
scope: options.scope,
|
|
90
|
+
scopeEstimate: options.scopeEstimate,
|
|
91
|
+
labels: options.labels,
|
|
92
|
+
description: options.description,
|
|
93
|
+
});
|
|
94
|
+
if (context.json) {
|
|
95
|
+
context.logger.json({ status: 'ok', ...result });
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
for (const warning of result.index.warnings) {
|
|
99
|
+
context.logger.warn(warning);
|
|
100
|
+
}
|
|
101
|
+
context.logger.info(`Created backlog item ${result.id}`);
|
|
102
|
+
context.logger.info(`Wrote ${result.filePath}`);
|
|
103
|
+
context.logger.info(`Regenerated backlog index with ${result.index.itemCount} ${result.index.itemCount === 1 ? 'item' : 'items'}.`);
|
|
104
|
+
}
|
|
105
|
+
process.exitCode = 0;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
109
|
+
if (context.json) {
|
|
110
|
+
context.logger.json({ status: 'error', message });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
context.logger.error(message);
|
|
114
|
+
}
|
|
115
|
+
process.exitCode = 1;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
63
118
|
cmd
|
|
64
119
|
.command('regenerate-index')
|
|
65
120
|
.description('Regenerate the managed backlog index table')
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { initializeBacklog } from './init.js';
|
|
2
|
+
import { regenerateBacklogIndex, type RegenerateBacklogIndexResult } from './regenerate-index.js';
|
|
3
|
+
export interface CreateBacklogItemOptions {
|
|
4
|
+
backlogRoot: string;
|
|
5
|
+
assetsRoot: string;
|
|
6
|
+
templatesRoot?: string;
|
|
7
|
+
title: string;
|
|
8
|
+
priority?: string;
|
|
9
|
+
scope?: string;
|
|
10
|
+
scopeEstimate?: string;
|
|
11
|
+
labels?: string[];
|
|
12
|
+
description?: string;
|
|
13
|
+
createdAt?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CreateBacklogItemResult {
|
|
16
|
+
id: string;
|
|
17
|
+
backlogRoot: string;
|
|
18
|
+
filePath: string;
|
|
19
|
+
templatePath: string;
|
|
20
|
+
index: RegenerateBacklogIndexResult;
|
|
21
|
+
}
|
|
22
|
+
export interface CreateBacklogItemDependencies {
|
|
23
|
+
initializeBacklog: typeof initializeBacklog;
|
|
24
|
+
regenerateBacklogIndex: typeof regenerateBacklogIndex;
|
|
25
|
+
}
|
|
26
|
+
export declare function createBacklogItem(options: CreateBacklogItemOptions, overrides?: Partial<CreateBacklogItemDependencies>): Promise<CreateBacklogItemResult>;
|
|
27
|
+
//# sourceMappingURL=new.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/new.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EACL,sBAAsB,EACtB,KAAK,4BAA4B,EAClC,MAAM,oBAAoB,CAAC;AAS5B,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,4BAA4B,CAAC;CACrC;AAED,MAAM,WAAW,6BAA6B;IAC5C,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;CACvD;AAuLD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,EACjC,SAAS,GAAE,OAAO,CAAC,6BAA6B,CAAM,GACrD,OAAO,CAAC,uBAAuB,CAAC,CAqDlC"}
|