ex-workflow 0.2.0-stage → 0.4.0-stage
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/CHANGELOG.md +20 -1
- package/README.md +54 -12
- package/dist/adapters/index.cjs +1 -1
- package/dist/adapters/index.mjs +1 -1
- package/dist/chunk-36M6OVUJ.mjs +2 -0
- package/dist/chunk-36M6OVUJ.mjs.map +1 -0
- package/dist/{chunk-472WEDPJ.cjs → chunk-7KF5K3L7.cjs} +2 -2
- package/dist/{chunk-472WEDPJ.cjs.map → chunk-7KF5K3L7.cjs.map} +1 -1
- package/dist/chunk-CWBH7H52.cjs +2 -0
- package/dist/chunk-CWBH7H52.cjs.map +1 -0
- package/dist/chunk-DXC2RSN5.cjs +3 -0
- package/dist/chunk-DXC2RSN5.cjs.map +1 -0
- package/dist/{chunk-XSXHEEJX.mjs → chunk-GATJZYTB.mjs} +2 -2
- package/dist/{chunk-XSXHEEJX.mjs.map → chunk-GATJZYTB.mjs.map} +1 -1
- package/dist/chunk-GFH2FEZH.mjs +2 -0
- package/dist/chunk-GFH2FEZH.mjs.map +1 -0
- package/dist/{chunk-DBR24RTX.cjs → chunk-HHC5EZ54.cjs} +2 -2
- package/dist/{chunk-DBR24RTX.cjs.map → chunk-HHC5EZ54.cjs.map} +1 -1
- package/dist/chunk-KSKEFYY7.cjs +2 -0
- package/dist/chunk-KSKEFYY7.cjs.map +1 -0
- package/dist/chunk-KUUIAKEJ.cjs +2 -0
- package/dist/chunk-KUUIAKEJ.cjs.map +1 -0
- package/dist/{chunk-IBRC36PE.mjs → chunk-L2ZN6HEL.mjs} +2 -2
- package/dist/{chunk-IBRC36PE.mjs.map → chunk-L2ZN6HEL.mjs.map} +1 -1
- package/dist/chunk-NDORREWR.mjs +2 -0
- package/dist/chunk-NDORREWR.mjs.map +1 -0
- package/dist/{chunk-VN2UYV2O.mjs → chunk-NZ2DIDOD.mjs} +2 -2
- package/dist/{chunk-VN2UYV2O.mjs.map → chunk-NZ2DIDOD.mjs.map} +1 -1
- package/dist/chunk-OHSQ52DW.mjs +6 -0
- package/dist/chunk-OHSQ52DW.mjs.map +1 -0
- package/dist/chunk-RSKZVOYC.cjs +6 -0
- package/dist/chunk-RSKZVOYC.cjs.map +1 -0
- package/dist/chunk-S22CPYXJ.mjs +3 -0
- package/dist/chunk-S22CPYXJ.mjs.map +1 -0
- package/dist/chunk-SHAPFMVP.mjs +2 -0
- package/dist/chunk-SHAPFMVP.mjs.map +1 -0
- package/dist/chunk-SJRRQZ3R.cjs +2 -0
- package/dist/chunk-SJRRQZ3R.cjs.map +1 -0
- package/dist/{chunk-D4HNETUL.cjs → chunk-UM5X2JHB.cjs} +2 -2
- package/dist/{chunk-D4HNETUL.cjs.map → chunk-UM5X2JHB.cjs.map} +1 -1
- package/dist/cli/bin.cjs +1 -1
- package/dist/cli/bin.cjs.map +1 -1
- package/dist/cli/bin.mjs +1 -1
- package/dist/cli/bin.mjs.map +1 -1
- package/dist/cli/index.cjs +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/kanban/index.cjs +1 -1
- package/dist/kanban/index.mjs +1 -1
- package/dist/schema/index.cjs +2 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.cts +57 -0
- package/dist/schema/index.d.ts +57 -0
- package/dist/schema/index.mjs +2 -0
- package/dist/schema/index.mjs.map +1 -0
- package/dist/scrum/index.cjs +1 -1
- package/dist/scrum/index.mjs +1 -1
- package/dist/types.d.cts +38 -2
- package/dist/types.d.ts +38 -2
- package/dist/waterfall/index.cjs +2 -0
- package/dist/waterfall/index.cjs.map +1 -0
- package/dist/waterfall/index.d.cts +148 -0
- package/dist/waterfall/index.d.ts +148 -0
- package/dist/waterfall/index.mjs +2 -0
- package/dist/waterfall/index.mjs.map +1 -0
- package/package.json +31 -2
- package/dist/chunk-6R3YFUUV.cjs +0 -6
- package/dist/chunk-6R3YFUUV.cjs.map +0 -1
- package/dist/chunk-JDVE7DQR.cjs +0 -2
- package/dist/chunk-JDVE7DQR.cjs.map +0 -1
- package/dist/chunk-NQU5TH3A.mjs +0 -2
- package/dist/chunk-NQU5TH3A.mjs.map +0 -1
- package/dist/chunk-NRAPI3GV.cjs +0 -2
- package/dist/chunk-NRAPI3GV.cjs.map +0 -1
- package/dist/chunk-PD5FBDN7.mjs +0 -2
- package/dist/chunk-PD5FBDN7.mjs.map +0 -1
- package/dist/chunk-QDT35LXB.cjs +0 -2
- package/dist/chunk-QDT35LXB.cjs.map +0 -1
- package/dist/chunk-VGD4V5BA.mjs +0 -6
- package/dist/chunk-VGD4V5BA.mjs.map +0 -1
- package/dist/chunk-YJNDBKIG.mjs +0 -2
- package/dist/chunk-YJNDBKIG.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.4.0-stage (unreleased)
|
|
4
|
+
|
|
5
|
+
Pre-release under the `stage` dist-tag.
|
|
6
|
+
|
|
7
|
+
- Schema entry (`ex-workflow/schema`): JSON Schema (draft-07) documents generated from the TypeScript types for `WorkflowState`, `Role` (manifest), `NewItem`, `Handoff`, `ScrumConfig`, `KanbanConfig`, `WaterfallConfig`, plus a dependency-free `validate` / `assertValid` for the subset the generator emits. `pnpm schema:check` fails the build when the types and the committed schema drift.
|
|
8
|
+
- Adapters: `loadState` validates `.workflow/state.json` and every `roles/*.json` manifest against the schema after the version check; a state that fails is never returned.
|
|
9
|
+
- CLI: `exwf add`, `exwf complete` and `exwf role add` validate their input file before the engine sees it; errors name the file, the JSON pointer and the expected shape.
|
|
10
|
+
- Compatibility: a `.workflow/state.json` written by any earlier stage loads unchanged (every field added since 0.1.0-stage is optional). Two inputs that used to be accepted are now refused, with the file and JSON pointer named: extra keys in `state.json` or in an item (every object is closed), and `roles/*.json` manifests that carry only an `id` (a manifest is a full `Role`). `saveState` refuses to write a state the loader would reject, and `exwf edit` / `exwf init --roles` validate their files.
|
|
11
|
+
- Size: `dist/schema/index.mjs` and `schema` budgeted at measured size; `core+scrum`, `core+kanban`, `core+waterfall` unchanged.
|
|
12
|
+
|
|
13
|
+
## 0.3.0-stage (2026-10-23)
|
|
14
|
+
|
|
15
|
+
Pre-release under the `stage` dist-tag.
|
|
16
|
+
|
|
17
|
+
- Waterfall module (`ex-workflow/waterfall`): ordered phases with deliverables and gates, kickoff / gateReview / changeControlBoard / phaseRetrospective ceremonies, human-approved baselines with versions (`state.baselines`), change-requests with impact analysis that reopen exactly the listed phases (and suspend a later open phase), bidirectional traceability with an engine-generated `traceability-matrix`, seven rules, and phase metrics from events (completion, budget variance, requirement coverage, defects per phase, change-request counts, rework weight).
|
|
18
|
+
- Core: `WorkItem.phase` / `impactAnalysis`, `Phase.budget` / `produced`, `WorkflowState.baselines`, planner hook `roleFor`, `Methodology.afterDecide` with `decide(..., methodology?)`, `item.added` payload carries `phase` and `parent`.
|
|
19
|
+
- CLI: `exwf init waterfall`; `add` and `edit` run through the methodology rules; `decide` runs the methodology's `afterDecide`; `status` prints the phase report.
|
|
20
|
+
- Size: `core+waterfall` measured and budgeted next to `core+scrum` and `core+kanban` (set at measured size; see size-budget.json).
|
|
21
|
+
|
|
22
|
+
## 0.2.0-stage (2026-10-22)
|
|
4
23
|
|
|
5
24
|
Pre-release under the `stage` dist-tag.
|
|
6
25
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ex-workflow
|
|
2
2
|
|
|
3
|
-
Methodology engine for AI teams. Scrum, Kanban and Waterfall
|
|
3
|
+
Methodology engine for AI teams. Scrum, Kanban and Waterfall are modelled as data (stages, roles, policies, gates, ceremonies) and driven by a pure state machine on top of the [`ex-flow`](https://www.npmjs.com/package/ex-flow) DAG planner. The program decides, the LLM executes: which item may move, who may approve, whether a sprint may close is enforced by the engine, not by a prompt.
|
|
4
4
|
|
|
5
5
|
State is plain JSON, every operation is `(state, action) -> state`, and every error names the rule, the item and a concrete fix. Core performs no I/O; a small file adapter and the `exwf` CLI sit on top. Runtime dependencies are exactly `ex-flow` and `exsorted`.
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ State is plain JSON, every operation is `(state, action) -> state`, and every er
|
|
|
10
10
|
pnpm add ex-workflow@stage
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Pre-releases are published under the `stage` dist-tag (currently `0.
|
|
13
|
+
Pre-releases are published under the `stage` dist-tag (currently `0.3.0-stage`); `latest` is reserved for 0.1.0.
|
|
14
14
|
|
|
15
15
|
Node >= 18. Runs on macOS, Linux and Windows.
|
|
16
16
|
|
|
@@ -65,20 +65,45 @@ Cadences are ceremonies: `replenishment`, `delivery-planning`, `service-delivery
|
|
|
65
65
|
|
|
66
66
|
`next()` also returns `skipped`: each ready card it did not pull, with `reason` (`entry-policy`, `wip`, `resource-cap` or `budget`) and a `detail`; the commitment column's policies gate the pull out of it (escalation `question` cards are exempt, as from exit policies and gates). Ordering is by class band (question, expedite, fixed-date, standard, intangible) and, with `fairness.aging` on (the default), priority stays primary inside a window of `fairness.maxDeferralRounds` passes (default 5); each full window a card is passed over promotes it one step above any priority difference, and an intangible card reaching the first window is ranked as standard, so nothing is starved.
|
|
67
67
|
|
|
68
|
+
### Waterfall
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { init, addItem, applyAction, next, complete, decide } from "ex-workflow";
|
|
72
|
+
import { waterfall } from "ex-workflow/waterfall";
|
|
73
|
+
|
|
74
|
+
const m = waterfall();
|
|
75
|
+
let { state } = init({ methodology: m, config: {} }); // six classic phases, every gate human-approved
|
|
76
|
+
const r1 = { id: "R1", title: "login", phase: "requirements", acceptance: ["user can log in"] };
|
|
77
|
+
state = applyAction(state, m, { type: "item.add", by: "business-analyst", payload: { item: r1 } }, (s) =>
|
|
78
|
+
addItem(s, r1, "business-analyst"),
|
|
79
|
+
).state;
|
|
80
|
+
state = m.ceremonies["kickoff"]!(state, { by: "project-manager", phase: "requirements" }).state;
|
|
81
|
+
// next() → complete() as with any methodology; items go work → review → done
|
|
82
|
+
state = m.ceremonies["gateReview"]!(state, { by: "project-manager", phase: "requirements" }).state; // pending decision
|
|
83
|
+
state = decide(state, state.pending[0]!.id, "approve", "human", "ok", undefined, m); // baselines the phase
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Phases open one at a time (`kickoff`), close through a gate (`gateReview`, human-approved by default) that
|
|
87
|
+
baselines their items, and reopen only through an approved change-request (`changeControlBoard`, with an
|
|
88
|
+
impact analysis). Requirements must trace to design and verification items before those gates; the engine
|
|
89
|
+
generates the `traceability-matrix` deliverable. Edits to baselined items are refused by the rules when
|
|
90
|
+
they go through `applyAction` or the CLI. `test/waterfall.e2e.test.ts` is a full project with a
|
|
91
|
+
change-request that reopens two baselined phases.
|
|
92
|
+
|
|
68
93
|
## CLI
|
|
69
94
|
|
|
70
95
|
State lives in `.workflow/`. Every command prints JSON; errors exit 1, bad usage exits 2.
|
|
71
96
|
|
|
72
97
|
| Command | Returns |
|
|
73
98
|
|---|---|
|
|
74
|
-
| `init <scrum\|kanban> --config <file> [--roles <file>]` | `{ ok, state: { methodology, stages, roles } }` |
|
|
75
|
-
| `add <item.json>` | `{ ok, item }` |
|
|
76
|
-
| `edit <id> <patch.json>` | `{ ok, item }` |
|
|
99
|
+
| `init <scrum\|kanban\|waterfall> --config <file> [--roles <file>]` | `{ ok, state: { methodology, stages, roles } }` |
|
|
100
|
+
| `add <item.json>` | `{ ok, warnings, item }` (checked by the methodology rules) |
|
|
101
|
+
| `edit <id> <patch.json>` | `{ ok, warnings, item }` (checked by the methodology rules) |
|
|
77
102
|
| `next [--max n]` | `{ ok, reason, skipped, briefs }`; writes `.workflow/briefs/<id>.json` |
|
|
78
103
|
| `complete <id> <handoff.json> --tokens-in n --tokens-out n --duration-ms n --model m [--role r]` | `{ ok, item, warnings }` |
|
|
79
104
|
| `ceremony <name> [input.json] [--by who]` | `{ ok, warnings, lastEvent }` |
|
|
80
|
-
| `decide <pendingId> approve\|reject --by who [--note text]` | `{ ok, item }` |
|
|
81
|
-
| `status` | `{ ok, methodology, openIteration, counts, pending, lastEvent, report }` (`report` is the methodology's own status
|
|
105
|
+
| `decide <pendingId> approve\|reject --by who [--note text]` | `{ ok, item }` (runs the methodology's `afterDecide`, e.g. a Waterfall phase baseline) |
|
|
106
|
+
| `status` | `{ ok, methodology, openIteration, counts, pending, lastEvent, report }` (`report` is the methodology's own status: Kanban's cadences due, Waterfall's phases, pending gates and traceability coverage; `null` for Scrum) |
|
|
82
107
|
| `board` | `{ ok, columns }` |
|
|
83
108
|
| `metrics` | `{ ok, metrics }` |
|
|
84
109
|
| `pending` / `lessons` | the arrays |
|
|
@@ -91,6 +116,19 @@ State lives in `.workflow/`. Every command prints JSON; errors exit 1, bad usage
|
|
|
91
116
|
|
|
92
117
|
One writer at a time per `.workflow/`: `exwf` serialises writers with `.workflow/state.lock` (created exclusively, retried for about two seconds, taken over when older than 60 s). If a crashed process left the lock behind and a command reports that another `exwf` holds it, delete the file. Read-only commands do not lock. Use `withStateLock` from `ex-workflow/adapters` when you write state yourself.
|
|
93
118
|
|
|
119
|
+
### Schema
|
|
120
|
+
|
|
121
|
+
`ex-workflow/schema` exports JSON Schema (draft-07) documents generated from the TypeScript types — `workflowStateSchema`, `roleSchema`, `newItemSchema`, `itemPatchSchema`, `handoffSchema`, `scrumConfigSchema`, `kanbanConfigSchema`, `waterfallConfigSchema` — and a small validator with no runtime dependencies:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { assertValid, validate, workflowStateSchema } from "ex-workflow/schema";
|
|
125
|
+
|
|
126
|
+
const errors = validate(workflowStateSchema, JSON.parse(raw)); // SchemaError[] with JSON-pointer paths
|
|
127
|
+
assertValid(workflowStateSchema, JSON.parse(raw), ".workflow/state.json"); // throws WorkflowError("invalid-input")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`exwf` validates `state.json`, role manifests, item files, `exwf edit` patches, `--roles` files and handoff files with these schemas before acting on them, and `saveState` validates a state before writing it, so the CLI cannot write a file the loader would refuse. The documents are standard JSON Schema, so editors and ajv read them too. They are regenerated with `pnpm schema:gen`; `pnpm schema:check` (in `ci` and the pre-commit hook) fails when they drift from the types.
|
|
131
|
+
|
|
94
132
|
## Layers
|
|
95
133
|
|
|
96
134
|
```
|
|
@@ -104,11 +142,11 @@ This package is L0. All layers read and write the same `.workflow/` files.
|
|
|
104
142
|
|
|
105
143
|
## Status
|
|
106
144
|
|
|
107
|
-
0.
|
|
145
|
+
0.4.0-stage adds `ex-workflow/schema` (JSON Schema documents and a validator, checked by `exwf` on load and on input). 0.3.0-stage added the Waterfall module; all three methodologies ship. Design: [docs/superpowers/specs/2026-10-19-ex-workflow-design.md](docs/superpowers/specs/2026-10-19-ex-workflow-design.md).
|
|
108
146
|
|
|
109
147
|
## Known backlog
|
|
110
148
|
|
|
111
|
-
Minor items deferred past 0.
|
|
149
|
+
Minor items deferred past 0.3.0-stage:
|
|
112
150
|
|
|
113
151
|
- Stale-lock takeover can race when a lock is older than 60 s.
|
|
114
152
|
- `decide(approve)` ignores a `needs-review` verdict.
|
|
@@ -122,15 +160,19 @@ Minor items deferred past 0.2.0-stage:
|
|
|
122
160
|
- Kanban `wipBypass` is the total number of extra slots a column grants while any expedite is active, not one per expedite.
|
|
123
161
|
- Kanban cadences use `item.completed` counts as turns; a wall-clock cadence schedule is the host's job.
|
|
124
162
|
- Minor test gaps: retro duplicate-ref rejection, `writeAtomic` failure path, thin CLI usage and `decide` tests.
|
|
163
|
+
- Waterfall traceability is keyed by phase ids, not item types (spec §10 wording); links are read in both directions.
|
|
164
|
+
- Waterfall `editItem`/`addItem` called directly (not through `applyAction` or the CLI) bypass `baseline-immutable`.
|
|
165
|
+
- Waterfall phase budgets reuse `Iteration`; `exwf status` shows the open phase as `openIteration`. With no accounting history the planner estimates 20000 tokens per weight unit, so a small phase budget dispatches nothing until `next({ fallbackTokensPerWeight })` is passed or history exists.
|
|
166
|
+
- Phase retrospective applies `agreement` lessons only; other suggested changes are stored for the host.
|
|
125
167
|
|
|
126
168
|
## Development gate
|
|
127
169
|
|
|
128
170
|
There is no hosted CI. A husky pre-commit hook runs the local gate on every commit
|
|
129
|
-
(`pnpm format:check && pnpm lint && pnpm typecheck && pnpm test`); `pnpm run ci` adds the
|
|
171
|
+
(`pnpm format:check && pnpm lint && pnpm typecheck && pnpm schema:check && pnpm test`); `pnpm run ci` adds the
|
|
130
172
|
minified build, the dist identity check and the size ratchet, and `prepublishOnly` runs it
|
|
131
173
|
before any publish. oxfmt and oxlint need Node ^20.19 or >=22.12 on the developer machine; the
|
|
132
174
|
package itself supports Node >=18 (verified on ubuntu, macOS and Windows x Node 18/20/22
|
|
133
|
-
before the hosted workflow was removed).
|
|
175
|
+
before the hosted workflow was removed). Schema drift is guarded by `pnpm schema:check` alone, not by a test, because the generator needs Node >=22 and the test suite must run on >=18.
|
|
134
176
|
|
|
135
177
|
## Publishing
|
|
136
178
|
|
|
@@ -142,7 +184,7 @@ pnpm run ci && npm publish --tag stage
|
|
|
142
184
|
|
|
143
185
|
## Design principles
|
|
144
186
|
|
|
145
|
-
1. One engine, three methodologies
|
|
187
|
+
1. One engine, three methodologies, modelled as completely as the canonical texts describe them (Scrum Guide 2020; the Kanban Method's six practices, cadences, classes of service and flow metrics; classic phase-gate Waterfall with change control and traceability).
|
|
146
188
|
2. The program decides, the LLM executes. Which item may move, who may approve, whether a stage may start: engine, not prompt.
|
|
147
189
|
3. Roles are data. Methodologies reference capabilities, never role names.
|
|
148
190
|
4. Pure, serialisable state. Every operation is `(state, action) -> state` or `(state) -> view`. No I/O in core.
|
package/dist/adapters/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunkRSKZVOYC_cjs=require('../chunk-RSKZVOYC.cjs');require('../chunk-DXC2RSN5.cjs'),require('../chunk-S3BXVHO7.cjs');Object.defineProperty(exports,"WORKFLOW_DIR",{enumerable:true,get:function(){return chunkRSKZVOYC_cjs.a}});Object.defineProperty(exports,"loadState",{enumerable:true,get:function(){return chunkRSKZVOYC_cjs.e}});Object.defineProperty(exports,"saveBrief",{enumerable:true,get:function(){return chunkRSKZVOYC_cjs.f}});Object.defineProperty(exports,"saveHandoff",{enumerable:true,get:function(){return chunkRSKZVOYC_cjs.g}});Object.defineProperty(exports,"saveState",{enumerable:true,get:function(){return chunkRSKZVOYC_cjs.d}});Object.defineProperty(exports,"statePath",{enumerable:true,get:function(){return chunkRSKZVOYC_cjs.b}});Object.defineProperty(exports,"withStateLock",{enumerable:true,get:function(){return chunkRSKZVOYC_cjs.c}});//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/adapters/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{a as WORKFLOW_DIR,e as loadState,f as saveBrief,g as saveHandoff,d as saveState,b as statePath,c as withStateLock}from'../chunk-
|
|
1
|
+
export{a as WORKFLOW_DIR,e as loadState,f as saveBrief,g as saveHandoff,d as saveState,b as statePath,c as withStateLock}from'../chunk-OHSQ52DW.mjs';import'../chunk-S22CPYXJ.mjs';import'../chunk-2FRRD6A3.mjs';//# sourceMappingURL=index.mjs.map
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {c as c$1,b as b$2}from'./chunk-NZ2DIDOD.mjs';import {k as k$1}from'./chunk-L2ZN6HEL.mjs';import {I}from'./chunk-GATJZYTB.mjs';import {N as N$1}from'./chunk-NDORREWR.mjs';import {f as f$1}from'./chunk-GFH2FEZH.mjs';import {f,L,d as d$1,J,u,M,w,v,N}from'./chunk-SHAPFMVP.mjs';import {c,e,d,g as g$1,f as f$2,b as b$3}from'./chunk-OHSQ52DW.mjs';import {b,e as e$1,h as h$1,g as g$2,f as f$3}from'./chunk-S22CPYXJ.mjs';import {a,b as b$1}from'./chunk-2FRRD6A3.mjs';import {stat,readFile}from'fs/promises';import x from'path';var O={scrum:k$1,kanban:I,waterfall:N$1},g=["exwf init <scrum|kanban|waterfall> --config <file> [--roles <file>]","exwf add <item.json> [--by who] exwf edit <id> <patch.json> [--by who]","exwf next [--max n] exwf complete <id> <handoff.json> --tokens-in n --tokens-out n --duration-ms n --model m","exwf ceremony <name> [input.json] [--by who]","exwf decide <pendingId> approve|reject [--by who] [--note text]","exwf status | board | metrics | pending | lessons","exwf validate <action.json> exwf role add <manifest.json> | role list"];function K(r){let t=[],d={};for(let i=0;i<r.length;i++){let y=r[i];if(y.startsWith("--")){let e=y.slice(2),m=r[i+1];m!==void 0&&!m.startsWith("--")?(d[e]=m,i++):d[e]="true";}else t.push(y);}return {positional:t,flags:d}}async function k(r){try{return JSON.parse(await readFile(r,"utf8"))}catch(t){return b$1("invalid-input",`cannot read JSON from ${r}: ${t.message}`,"check the path and that the file is valid JSON")}}function h(r){let t=Object.hasOwn(O,r.methodology)?O[r.methodology]:void 0;return t||b$1("config-invalid",`methodology "${r.methodology}" is not available in this build`,`available: ${Object.keys(O).join(", ")}`),t()}function S(r,t){let d=Number(r[t]);return Number.isFinite(d)||b$1("invalid-input",`--${t} must be a number (got ${JSON.stringify(r[t])})`,`pass --${t} <n>`),d}var Y=new Set(["init","add","edit","next","complete","ceremony","decide"]);async function gt(r,t){let[d,i]=K(r).positional,y=d!==void 0&&(Y.has(d)||d==="role"&&i==="add");try{return y?await c(t,()=>z(r,t)):await z(r,t)}catch(e){if(e instanceof a)return {exit:1,out:{ok:false,error:e.toJSON()}};throw e}}async function z(r,t){let{positional:d$2,flags:i}=K(r),[y,...e$2]=d$2,m=i.by??"human",u$1=new Date().toISOString();switch(y){case "init":{let[o]=e$2,n=o&&Object.hasOwn(O,o)?O[o]:void 0;if(!n||!i.config)return {exit:2,out:{ok:false,usage:g}};try{await stat(b$3(t)),b$1("invalid-input",`${b$3(t)} already exists`,"delete .workflow/state.json to start over");}catch(f){if(f instanceof a||f.code!=="ENOENT")throw f}let s=await k(x.resolve(t,i.config)),a$1=i.roles?await k(x.resolve(t,i.roles)):void 0;if(a$1!==void 0){Array.isArray(a$1)||b$1("invalid-input",`roles file ${i.roles} must contain an array of role manifests`,"wrap the manifests in [ ... ]");for(let f of a$1)b(e$1,f,`roles file ${i.roles}`);}let c=N(a$1?{methodology:n(),config:s,roles:a$1,by:m,now:u$1}:{methodology:n(),config:s,by:m,now:u$1});return await d(t,c.state),{exit:0,out:{ok:true,warnings:c.warnings,state:{methodology:c.state.methodology,stages:c.state.stages.map(f=>f.id),roles:Object.keys(c.state.roles)}}}}case "add":{if(!e$2[0])return {exit:2,out:{ok:false,usage:g}};let o=await e(t),n=await k(x.resolve(t,e$2[0]));b(f$3,n,`item file ${e$2[0]}`);let s=M(o,h(o),{type:"item.add",by:m,payload:{item:n}},a=>v(a,n,m,u$1));return await d(t,s.state),{exit:0,out:{ok:true,warnings:s.warnings,item:u(s.state,n.id)}}}case "edit":{if(!e$2[0]||!e$2[1])return {exit:2,out:{ok:false,usage:g}};let o=await e(t),n=e$2[0],s=await k(x.resolve(t,e$2[1]));b(g$2,s,`patch file ${e$2[1]}`);let a=M(o,h(o),{type:"item.edit",by:m,payload:{id:n,patch:s}},c=>w(c,n,s,m,u$1));return await d(t,a.state),{exit:0,out:{ok:true,warnings:a.warnings,item:u(a.state,n)}}}case "next":{let o=await e(t),n=i.max?{max:S(i,"max"),now:u$1}:{now:u$1},s=b$2(o,h(o),n);await d(t,s.state);for(let a of s.briefs)await f$2(t,a);return {exit:0,out:{ok:true,reason:s.reason??null,skipped:s.skipped,briefs:s.briefs}}}case "complete":{if(!e$2[0]||!e$2[1])return {exit:2,out:{ok:false,usage:g}};let o=await e(t),n=await k(x.resolve(t,e$2[1]));b(h$1,n,`handoff file ${e$2[1]}`),n.item!==e$2[0]&&b$1("handoff-invalid",`handoff.item "${n.item}" differs from the command's item "${e$2[0]}"`,"make them match");let s=i.role??n.role,a=S(i,"duration-ms"),c={item:e$2[0],role:s,model:i.model??"",tokensIn:S(i,"tokens-in"),tokensOut:S(i,"tokens-out"),durationMs:a,startedAt:new Date(Date.parse(u$1)-a).toISOString(),endedAt:u$1},f=c$1(o,h(o),{...n,role:s},c,u$1);return await d(t,f.state),await g$1(t,n,f.state.events.length),{exit:0,out:{ok:true,warnings:f.warnings,item:u(f.state,e$2[0])}}}case "ceremony":{if(!e$2[0])return {exit:2,out:{ok:false,usage:g}};let o=await e(t),n=h(o),s=Object.hasOwn(n.ceremonies,e$2[0])?n.ceremonies[e$2[0]]:void 0;s||b$1("unknown-ceremony",`"${e$2[0]}" is not a ${n.name} ceremony`,`available: ${Object.keys(n.ceremonies).join(", ")}`);let a=e$2[1]?await k(x.resolve(t,e$2[1])):{},c=s(o,{...a,by:m,now:u$1});return await d(t,c.state),{exit:0,out:{ok:true,warnings:c.warnings,lastEvent:d$1(c.state)}}}case "decide":{if(!e$2[0]||e$2[1]!=="approve"&&e$2[1]!=="reject")return {exit:2,out:{ok:false,usage:g}};let o=await e(t),n=o.pending.find(a=>a.id===e$2[0]),s=J(o,e$2[0],e$2[1],m,i.note??"",u$1,h(o));return await d(t,s),{exit:0,out:{ok:true,item:n?.item?u(s,n.item):null}}}case "status":{let o=await e(t),n=h(o),s={todo:0,in_progress:0,blocked:0,review:0,awaiting_human:0,done:0,dropped:0};for(let a of Object.values(o.items))s[a.status]+=1;return {exit:0,out:{ok:true,methodology:o.methodology,openIteration:f$1(o)??null,counts:s,pending:o.pending,lastEvent:d$1(o),report:n.report?n.report(o):null}}}case "board":{let o=await e(t);return {exit:0,out:{ok:true,columns:o.stages.map(s=>({stage:s.id,wipLimit:s.wipLimit??null,items:Object.values(o.items).filter(a=>a.stage===s.id&&a.status!=="dropped").map(a=>({id:a.id,title:a.title,status:a.status,role:a.role??null,age:a.transitions.length?Date.parse(u$1)-Date.parse(a.transitions[a.transitions.length-1].at):null}))}))}}}case "metrics":{let o=await e(t);return {exit:0,out:{ok:true,metrics:h(o).metrics(o)}}}case "pending":return {exit:0,out:{ok:true,pending:(await e(t)).pending}};case "lessons":return {exit:0,out:{ok:true,lessons:(await e(t)).lessons}};case "validate":{if(!e$2[0])return {exit:2,out:{ok:false,usage:g}};let o=await e(t),n=await k(x.resolve(t,e$2[0]));return {exit:0,out:{ok:true,violations:L(o,h(o),n)}}}case "role":{let o=await e(t);if(e$2[0]==="list")return {exit:0,out:{ok:true,roles:Object.keys(o.roles),detail:o.roles}};if(e$2[0]==="add"&&e$2[1]){let n=await k(x.resolve(t,e$2[1]));b(e$1,n,`role manifest ${e$2[1]}`);let s=f(o,n,m,u$1);return await d(t,s),{exit:0,out:{ok:true,roles:Object.keys(s.roles)}}}return {exit:2,out:{ok:false,usage:g}}}default:return {exit:2,out:{ok:false,usage:g}}}}export{g as a,K as b,gt as c};//# sourceMappingURL=chunk-36M6OVUJ.mjs.map
|
|
2
|
+
//# sourceMappingURL=chunk-36M6OVUJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands.ts"],"names":["METHODOLOGIES","scrum","kanban","waterfall","USAGE","parseArgs","argv","positional","flags","a","key","val","readJson","file","readFile","e","fail","methodologyOf","state","f","num","v","WRITERS","runCommand","cwd","cmd","sub","writes","withStateLock","execute","WorkflowError","rest","by","now","name","stat","statePath","config","path","roles","r","assertValid","roleSchema","res","init","saveState","s","loadState","item","newItemSchema","applyAction","addItem","getItem","id","patch","itemPatchSchema","editItem","opts","next","b","saveBrief","handoff","handoffSchema","role","durationMs","acc","complete","saveHandoff","m","c","input","lastEvent","entry","p","s2","decide","counts","i","openIteration","st","action","validateAction","manifest","registerRole"],"mappings":"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","file":"chunk-36M6OVUJ.mjs","sourcesContent":["import { readFile, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n loadState,\n saveBrief,\n saveHandoff,\n saveState,\n statePath,\n withStateLock,\n} from \"../adapters/file.ts\";\nimport { next as planNext } from \"../brief.ts\";\nimport { complete } from \"../complete.ts\";\nimport { WorkflowError, fail } from \"../errors.ts\";\nimport { decide } from \"../gates.ts\";\nimport { addItem, editItem, getItem, type ItemPatch } from \"../items.ts\";\nimport { applyAction, init, validateAction } from \"../methodology.ts\";\nimport { openIteration } from \"../planner.ts\";\nimport { registerRole } from \"../roles.ts\";\nimport {\n assertValid,\n handoffSchema,\n itemPatchSchema,\n newItemSchema,\n roleSchema,\n} from \"../schema/index.ts\";\nimport { lastEvent } from \"../state.ts\";\nimport { scrum } from \"../scrum/index.ts\";\nimport { kanban } from \"../kanban/index.ts\";\nimport { waterfall } from \"../waterfall/index.ts\";\nimport type {\n Accounting,\n Action,\n Handoff,\n ItemStatus,\n Methodology,\n NewItem,\n Role,\n WorkflowState,\n} from \"../types.ts\";\n\nconst METHODOLOGIES: Record<string, () => Methodology> = {\n scrum: scrum as () => Methodology,\n kanban: kanban as () => Methodology,\n waterfall: waterfall as () => Methodology,\n};\n\nexport const USAGE = [\n \"exwf init <scrum|kanban|waterfall> --config <file> [--roles <file>]\",\n \"exwf add <item.json> [--by who] exwf edit <id> <patch.json> [--by who]\",\n \"exwf next [--max n] exwf complete <id> <handoff.json> --tokens-in n --tokens-out n --duration-ms n --model m\",\n \"exwf ceremony <name> [input.json] [--by who]\",\n \"exwf decide <pendingId> approve|reject [--by who] [--note text]\",\n \"exwf status | board | metrics | pending | lessons\",\n \"exwf validate <action.json> exwf role add <manifest.json> | role list\",\n];\n\nexport interface Parsed {\n positional: string[];\n flags: Record<string, string>;\n}\nexport function parseArgs(argv: string[]): Parsed {\n const positional: string[] = [];\n const flags: Record<string, string> = {};\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a.startsWith(\"--\")) {\n const key = a.slice(2);\n const val = argv[i + 1];\n if (val !== undefined && !val.startsWith(\"--\")) {\n flags[key] = val;\n i++;\n } else flags[key] = \"true\";\n } else positional.push(a);\n }\n return { positional, flags };\n}\n\nasync function readJson<T>(file: string): Promise<T> {\n try {\n return JSON.parse(await readFile(file, \"utf8\")) as T;\n } catch (e) {\n return fail(\n \"invalid-input\",\n `cannot read JSON from ${file}: ${(e as Error).message}`,\n \"check the path and that the file is valid JSON\",\n );\n }\n}\n\nfunction methodologyOf(state: WorkflowState): Methodology {\n const f = Object.hasOwn(METHODOLOGIES, state.methodology)\n ? METHODOLOGIES[state.methodology]\n : undefined;\n if (!f)\n fail(\n \"config-invalid\",\n `methodology \"${state.methodology}\" is not available in this build`,\n `available: ${Object.keys(METHODOLOGIES).join(\", \")}`,\n );\n return f();\n}\n\nfunction num(flags: Record<string, string>, key: string): number {\n const v = Number(flags[key]);\n if (!Number.isFinite(v))\n fail(\n \"invalid-input\",\n `--${key} must be a number (got ${JSON.stringify(flags[key])})`,\n `pass --${key} <n>`,\n );\n return v;\n}\n\nexport interface CommandResult {\n exit: 0 | 1 | 2;\n out: unknown;\n}\n\n/** Commands that load, change and save the state: they run under .workflow/state.lock. */\nconst WRITERS = new Set([\"init\", \"add\", \"edit\", \"next\", \"complete\", \"ceremony\", \"decide\"]);\n\nexport async function runCommand(argv: string[], cwd: string): Promise<CommandResult> {\n const [cmd, sub] = parseArgs(argv).positional;\n const writes = cmd !== undefined && (WRITERS.has(cmd) || (cmd === \"role\" && sub === \"add\"));\n try {\n return writes ? await withStateLock(cwd, () => execute(argv, cwd)) : await execute(argv, cwd);\n } catch (e) {\n if (e instanceof WorkflowError) return { exit: 1, out: { ok: false, error: e.toJSON() } };\n throw e;\n }\n}\n\nasync function execute(argv: string[], cwd: string): Promise<CommandResult> {\n const { positional, flags } = parseArgs(argv);\n const [cmd, ...rest] = positional;\n const by = flags[\"by\"] ?? \"human\";\n const now = new Date().toISOString();\n switch (cmd) {\n case \"init\": {\n const [name] = rest;\n const f = name && Object.hasOwn(METHODOLOGIES, name) ? METHODOLOGIES[name] : undefined;\n if (!f || !flags[\"config\"]) return { exit: 2, out: { ok: false, usage: USAGE } };\n try {\n await stat(statePath(cwd));\n fail(\n \"invalid-input\",\n `${statePath(cwd)} already exists`,\n \"delete .workflow/state.json to start over\",\n );\n } catch (e) {\n if (e instanceof WorkflowError) throw e;\n if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e;\n }\n const config = await readJson<unknown>(path.resolve(cwd, flags[\"config\"]));\n const roles = flags[\"roles\"]\n ? await readJson<Role[]>(path.resolve(cwd, flags[\"roles\"]))\n : undefined;\n if (roles !== undefined) {\n if (!Array.isArray(roles))\n fail(\n \"invalid-input\",\n `roles file ${flags[\"roles\"]} must contain an array of role manifests`,\n \"wrap the manifests in [ ... ]\",\n );\n for (const r of roles) assertValid(roleSchema, r, `roles file ${flags[\"roles\"]}`);\n }\n const res = init(\n roles\n ? { methodology: f(), config, roles, by, now }\n : { methodology: f(), config, by, now },\n );\n await saveState(cwd, res.state);\n return {\n exit: 0,\n out: {\n ok: true,\n warnings: res.warnings,\n state: {\n methodology: res.state.methodology,\n stages: res.state.stages.map((s) => s.id),\n roles: Object.keys(res.state.roles),\n },\n },\n };\n }\n case \"add\": {\n if (!rest[0]) return { exit: 2, out: { ok: false, usage: USAGE } };\n const state = await loadState(cwd);\n const item = await readJson<NewItem>(path.resolve(cwd, rest[0]));\n assertValid(newItemSchema, item, `item file ${rest[0]}`);\n const res = applyAction(\n state,\n methodologyOf(state),\n { type: \"item.add\", by, payload: { item } },\n (s) => addItem(s, item, by, now),\n );\n await saveState(cwd, res.state);\n return {\n exit: 0,\n out: { ok: true, warnings: res.warnings, item: getItem(res.state, item.id) },\n };\n }\n case \"edit\": {\n if (!rest[0] || !rest[1]) return { exit: 2, out: { ok: false, usage: USAGE } };\n const state = await loadState(cwd);\n const id = rest[0];\n const patch = await readJson<ItemPatch>(path.resolve(cwd, rest[1]));\n assertValid(itemPatchSchema, patch, `patch file ${rest[1]}`);\n const res = applyAction(\n state,\n methodologyOf(state),\n { type: \"item.edit\", by, payload: { id, patch } },\n (s) => editItem(s, id, patch, by, now),\n );\n await saveState(cwd, res.state);\n return { exit: 0, out: { ok: true, warnings: res.warnings, item: getItem(res.state, id) } };\n }\n case \"next\": {\n const state = await loadState(cwd);\n const opts = flags[\"max\"] ? { max: num(flags, \"max\"), now } : { now };\n const res = planNext(state, methodologyOf(state), opts);\n await saveState(cwd, res.state);\n for (const b of res.briefs) await saveBrief(cwd, b);\n return {\n exit: 0,\n out: { ok: true, reason: res.reason ?? null, skipped: res.skipped, briefs: res.briefs },\n };\n }\n case \"complete\": {\n if (!rest[0] || !rest[1]) return { exit: 2, out: { ok: false, usage: USAGE } };\n const state = await loadState(cwd);\n const handoff = await readJson<Handoff>(path.resolve(cwd, rest[1]));\n assertValid(handoffSchema, handoff, `handoff file ${rest[1]}`);\n if (handoff.item !== rest[0])\n fail(\n \"handoff-invalid\",\n `handoff.item \"${handoff.item}\" differs from the command's item \"${rest[0]}\"`,\n \"make them match\",\n );\n const role = flags[\"role\"] ?? handoff.role;\n const durationMs = num(flags, \"duration-ms\");\n const acc: Accounting = {\n item: rest[0],\n role,\n model: flags[\"model\"] ?? \"\",\n tokensIn: num(flags, \"tokens-in\"),\n tokensOut: num(flags, \"tokens-out\"),\n durationMs,\n startedAt: new Date(Date.parse(now) - durationMs).toISOString(),\n endedAt: now,\n };\n const res = complete(state, methodologyOf(state), { ...handoff, role }, acc, now);\n await saveState(cwd, res.state);\n await saveHandoff(cwd, handoff, res.state.events.length);\n return {\n exit: 0,\n out: { ok: true, warnings: res.warnings, item: getItem(res.state, rest[0]) },\n };\n }\n case \"ceremony\": {\n if (!rest[0]) return { exit: 2, out: { ok: false, usage: USAGE } };\n const state = await loadState(cwd);\n const m = methodologyOf(state);\n const c = Object.hasOwn(m.ceremonies, rest[0]) ? m.ceremonies[rest[0]] : undefined;\n if (!c)\n fail(\n \"unknown-ceremony\",\n `\"${rest[0]}\" is not a ${m.name} ceremony`,\n `available: ${Object.keys(m.ceremonies).join(\", \")}`,\n );\n const input = rest[1]\n ? await readJson<Record<string, unknown>>(path.resolve(cwd, rest[1]))\n : {};\n const res = c(state, { ...input, by, now });\n await saveState(cwd, res.state);\n return {\n exit: 0,\n out: { ok: true, warnings: res.warnings, lastEvent: lastEvent(res.state) },\n };\n }\n case \"decide\": {\n if (!rest[0] || (rest[1] !== \"approve\" && rest[1] !== \"reject\"))\n return { exit: 2, out: { ok: false, usage: USAGE } };\n const state = await loadState(cwd);\n const entry = state.pending.find((p) => p.id === rest[0]);\n const s2 = decide(\n state,\n rest[0],\n rest[1],\n by,\n flags[\"note\"] ?? \"\",\n now,\n methodologyOf(state),\n );\n await saveState(cwd, s2);\n return { exit: 0, out: { ok: true, item: entry?.item ? getItem(s2, entry.item) : null } };\n }\n case \"status\": {\n const state = await loadState(cwd);\n const m = methodologyOf(state);\n const counts: Record<ItemStatus, number> = {\n todo: 0,\n in_progress: 0,\n blocked: 0,\n review: 0,\n awaiting_human: 0,\n done: 0,\n dropped: 0,\n };\n for (const i of Object.values(state.items)) counts[i.status] += 1;\n return {\n exit: 0,\n out: {\n ok: true,\n methodology: state.methodology,\n openIteration: openIteration(state) ?? null,\n counts,\n pending: state.pending,\n lastEvent: lastEvent(state),\n report: m.report ? m.report(state) : null,\n },\n };\n }\n case \"board\": {\n const state = await loadState(cwd);\n const columns = state.stages.map((st) => ({\n stage: st.id,\n wipLimit: st.wipLimit ?? null,\n items: Object.values(state.items)\n .filter((i) => i.stage === st.id && i.status !== \"dropped\")\n .map((i) => ({\n id: i.id,\n title: i.title,\n status: i.status,\n role: i.role ?? null,\n age: i.transitions.length\n ? Date.parse(now) - Date.parse(i.transitions[i.transitions.length - 1]!.at)\n : null,\n })),\n }));\n return { exit: 0, out: { ok: true, columns } };\n }\n case \"metrics\": {\n const state = await loadState(cwd);\n return { exit: 0, out: { ok: true, metrics: methodologyOf(state).metrics(state) } };\n }\n case \"pending\":\n return { exit: 0, out: { ok: true, pending: (await loadState(cwd)).pending } };\n case \"lessons\":\n return { exit: 0, out: { ok: true, lessons: (await loadState(cwd)).lessons } };\n case \"validate\": {\n if (!rest[0]) return { exit: 2, out: { ok: false, usage: USAGE } };\n const state = await loadState(cwd);\n const action = await readJson<Action>(path.resolve(cwd, rest[0]));\n return {\n exit: 0,\n out: { ok: true, violations: validateAction(state, methodologyOf(state), action) },\n };\n }\n case \"role\": {\n const state = await loadState(cwd);\n if (rest[0] === \"list\")\n return {\n exit: 0,\n out: { ok: true, roles: Object.keys(state.roles), detail: state.roles },\n };\n if (rest[0] === \"add\" && rest[1]) {\n const manifest = await readJson<Role>(path.resolve(cwd, rest[1]));\n assertValid(roleSchema, manifest, `role manifest ${rest[1]}`);\n const s2 = registerRole(state, manifest, by, now);\n await saveState(cwd, s2);\n return { exit: 0, out: { ok: true, roles: Object.keys(s2.roles) } };\n }\n return { exit: 2, out: { ok: false, usage: USAGE } };\n }\n default:\n return { exit: 2, out: { ok: false, usage: USAGE } };\n }\n}\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var chunkQDT35LXB_cjs=require('./chunk-QDT35LXB.cjs'),chunkJDVE7DQR_cjs=require('./chunk-JDVE7DQR.cjs'),chunkS3BXVHO7_cjs=require('./chunk-S3BXVHO7.cjs'),exsorted=require('exsorted');var ue=["todo","in_progress","blocked","review","awaiting_human","done","dropped"];function fe(o){let t=o.events.filter(r=>r.type==="sprint.closed"&&r.payload.reason!=="cancel");return t.length===0?null:t.reduce((r,i)=>r+i.payload.doneWeight,0)/t.length}function ie(o){let t=chunkQDT35LXB_cjs.f(o),r=Object.fromEntries(ue.map(n=>[n,0])),i=[],y=0;for(let n of t?.committed??[]){let e=o.items[n];if(e){r[e.status]+=1,e.status!=="done"&&(y+=e.weight??0);for(let a of e.blockers)a.clearedAt||i.push({item:n,blocker:a.id,owner:a.owner,reason:a.reason});}}let u=t?.spent??{tokens:0,turns:0,wallclockMs:0},g=t?chunkQDT35LXB_cjs.c(t.budget,t.spent):{},m=fe(o),h="unknown";if(t&&m!==null&&t.budget.tokens){let n=(g.tokens??0)/t.budget.tokens;h=y<=m*n?"on-track":"at-risk";}let s=o.lessons.filter(n=>n.status==="raised").length;return {sprint:t?.id??null,goal:t?.goal??null,byStatus:r,blockers:i,spent:u,remaining:g,remainingWeight:y,raisedLessons:s,velocity:m,forecast:h}}function V(o){for(let t=o.iterations.length-1;t>=0;t--){let r=o.iterations[t];if(r.endedAt!==void 0)return r}}function F(o,t){return o.events.find(r=>r.type==="sprint.closed"&&r.payload.id===t)?.seq??Number.POSITIVE_INFINITY}function ge(o){let t=new Set(V(o)?.carryover??[]),r=Object.values(o.items).filter(i=>i.stage==="backlog"&&i.status==="todo"&&i.type!=="question");return exsorted.timSort([...r],(i,y)=>{let u=t.has(i.id)?1:0,g=t.has(y.id)?1:0;return u!==g?g-u:(y.priority??0)-(i.priority??0)})}function ne(o,t){let r=chunkJDVE7DQR_cjs.u(o,t);(r.stage!=="backlog"||r.status!=="todo")&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${t}" is not in the Product Backlog (${r.stage}/${r.status})`,"only backlog items can be committed",{items:[t]}),chunkJDVE7DQR_cjs.E(o,r,chunkJDVE7DQR_cjs.p(o,"backlog").exitPolicy,"enter the Sprint Backlog");}function oe(o,t,r,i,y){let u=o;for(let g of Object.values(o.items))g.type!=="question"||g.parent===void 0||!t.includes(g.parent)||g.status==="done"||g.status==="dropped"||((g.stage!=="sprint"||g.status!=="todo")&&(u=chunkJDVE7DQR_cjs.x(u,g.id,{stage:"sprint",status:"todo"},i,y)),u=chunkJDVE7DQR_cjs.s(u,g.id,m=>({...m,iteration:r})));return u}function re(o,t){return {...o,config:{...O(o),definitionOfDone:t},stages:o.stages.map(r=>r.id==="review"?{...r,exitPolicy:t}:r)}}function ye(o,t){let r=[],i=0;for(let y of ge(o)){if(t.tokens!==void 0){let u=chunkQDT35LXB_cjs.e(o,y.weight);if(i+u>t.tokens)break;i+=u;}else if(t.turns!==void 0&&r.length>=t.turns)break;r.push(y.id);}return r}function J(o){let t=(n,e,a,l)=>chunkJDVE7DQR_cjs.M(n,o(),{type:e,by:a.by,payload:a},p=>l(p,chunkJDVE7DQR_cjs.a(a.now)));return {refine:(n,e)=>{chunkJDVE7DQR_cjs.o(n,e.by,"define-acceptance","deliver");let a=e.items??[],l=e.split??[];return a.length===0&&l.length===0&&chunkS3BXVHO7_cjs.b("invalid-input","refine needs items[] or split[]","pass at least one patch or split"),t(n,"ceremony.refine",e,(p,c)=>{for(let{id:d,patch:v}of a)p=chunkJDVE7DQR_cjs.w(p,d,v,e.by,c);for(let d of l){chunkJDVE7DQR_cjs.u(p,d.from);for(let v of d.into)p=chunkJDVE7DQR_cjs.v(p,{...v,parent:d.from},e.by,c);p=chunkJDVE7DQR_cjs.x(p,d.from,{status:"dropped"},e.by,c);}return chunkJDVE7DQR_cjs.c(p,"ceremony.refine",e.by,{edited:a.map(d=>d.id),split:l.map(d=>({from:d.from,into:d.into.map(v=>v.id)}))},c)})},plan:(n,e)=>{chunkJDVE7DQR_cjs.o(n,e.by,"facilitate");let a=e.goal;(typeof a!="string"||a.trim()==="")&&chunkS3BXVHO7_cjs.b("invalid-input","sprint planning needs a non-empty goal","state the Sprint Goal in one sentence");let l=O(n),p=e.budget??l.sprintBudget,c=e.items==="auto"?ye(n,p):e.items;Array.isArray(c)||chunkS3BXVHO7_cjs.b("invalid-input",'sprint planning needs items: string[] or "auto"','pass ["A","B"] or "auto"'),c.length===0&&chunkS3BXVHO7_cjs.b("invalid-input","no backlog items fit the sprint","refine the backlog (acceptance + estimates) or raise the budget in config");for(let d of c)ne(n,d);return t(n,"ceremony.plan",e,(d,v)=>{let w=`S${d.iterations.length+1}`,q=V(d),f=c.filter(S=>q?.carryover.includes(S));for(let S of c)d=chunkJDVE7DQR_cjs.x(d,S,{stage:"sprint",status:"todo"},e.by,v),d=chunkJDVE7DQR_cjs.s(d,S,B=>({...B,iteration:w}));d=oe(d,c,w,e.by,v);let W=c.reduce((S,B)=>S+(d.items[B]?.weight??0),0);return d={...d,iterations:[...d.iterations,{id:w,goal:a,budget:p,spent:{tokens:0,turns:0,wallclockMs:0},startedAt:v,committed:[...c],carryover:f}]},chunkJDVE7DQR_cjs.c(d,"sprint.opened",e.by,{id:w,goal:a,committed:c,committedWeight:W,budget:p},v)})},commit:(n,e)=>{let a=chunkQDT35LXB_cjs.f(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint to commit into","run the plan ceremony first");let l=e.items;(!Array.isArray(l)||l.length===0)&&chunkS3BXVHO7_cjs.b("invalid-input","commit needs items[]",'pass ["A"]');let p=new Set;for(let c of l)p.has(c)&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${c}" appears twice in items[]`,"list each item once",{items:[c]}),p.add(c),chunkJDVE7DQR_cjs.u(n,c),a.committed.includes(c)&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${c}" is already committed to ${a.id}`,"nothing to do",{items:[c]}),ne(n,c);return t(n,"ceremony.commit",e,(c,d)=>{for(let v of l)c=chunkJDVE7DQR_cjs.x(c,v,{stage:"sprint",status:"todo"},e.by,d),c=chunkJDVE7DQR_cjs.s(c,v,w=>({...w,iteration:a.id}));return c=oe(c,l,a.id,e.by,d),c={...c,iterations:c.iterations.map(v=>v.id===a.id?{...v,committed:[...v.committed,...l]}:v)},chunkJDVE7DQR_cjs.c(c,"sprint.committed",e.by,{id:a.id,items:l,goalImpact:e.goalImpact??null},d)})},uncommit:(n,e)=>{chunkJDVE7DQR_cjs.o(n,e.by,"order-backlog");let a=chunkQDT35LXB_cjs.f(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint","nothing to uncommit from");let l=e.items;(!Array.isArray(l)||l.length===0)&&chunkS3BXVHO7_cjs.b("invalid-input","uncommit needs items[]",'pass ["A"]');for(let p of l)chunkJDVE7DQR_cjs.u(n,p).status==="done"&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${p}" is done`,"finished work cannot be uncommitted",{items:[p]});for(let p of l)a.committed.includes(p)||chunkS3BXVHO7_cjs.b("invalid-input",`item "${p}" is not committed to ${a.id}`,`committed: ${a.committed.join(", ")}`,{items:[p]});return t(n,"ceremony.uncommit",e,(p,c)=>{for(let d of l)p=chunkJDVE7DQR_cjs.x(p,d,{stage:"backlog",status:"todo"},e.by,c),p=chunkJDVE7DQR_cjs.t(p,d,["iteration","role"]);return p={...p,iterations:p.iterations.map(d=>d.id===a.id?{...d,committed:d.committed.filter(v=>!l.includes(v))}:d)},chunkJDVE7DQR_cjs.c(p,"sprint.uncommitted",e.by,{id:a.id,items:l,reason:e.reason??""},c)})},daily:(n,e)=>t(n,"ceremony.daily",e,(a,l)=>chunkJDVE7DQR_cjs.c(a,"daily",e.by,ie(a),l)),review:(n,e)=>{let a=chunkQDT35LXB_cjs.f(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint to review","run the plan ceremony first");let l=chunkJDVE7DQR_cjs.j(n,"sprint-review");e.by!=="human"&&!l.includes(e.by)&&chunkS3BXVHO7_cjs.b("gate-unmet",`"${e.by}" may not accept the Sprint Review`,`run review as "human" or as ${l.join(", ")||"a role with canApprove sprint-review"}`,{rule:"sprint-review"});let p=e.feedback??[];return t(n,"ceremony.review",e,(c,d)=>{for(let w of p)c=chunkJDVE7DQR_cjs.v(c,{...w,stage:"backlog"},e.by,d);let v=a.committed.filter(w=>c.items[w]?.status==="done");return c=chunkJDVE7DQR_cjs.c(c,"increment",e.by,{sprint:a.id,done:v,goalMet:e.goalMet===true,accepted:e.accepted===true,feedback:p.map(w=>w.id)},d),T(c,"review",d)})},retro:(n,e)=>{chunkJDVE7DQR_cjs.o(n,e.by,"facilitate");let a=V(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no closed sprint to retrospect","close the sprint (review or cancel) first"),chunkQDT35LXB_cjs.f(n)&&chunkS3BXVHO7_cjs.b("invalid-input","a sprint is still open","retro runs between sprints; review or cancel the open one");let l=F(n,a.id);n.events.some(f=>f.type==="retro"&&f.seq>l)&&chunkS3BXVHO7_cjs.b("invalid-input",`sprint ${a.id} already has a retrospective`,"plan the next sprint");let p=e.lessons??[],c=e.adopt??[],d=e.dismiss??[],v=e.dodChanges,w=[...c.map(f=>f.id),...d],q=w.find((f,W)=>w.indexOf(f)!==W);q&&chunkS3BXVHO7_cjs.b("invalid-input",`lesson "${q}" is referenced more than once`,"adopt or dismiss each lesson once");for(let f of w){let W=n.lessons.find(S=>S.id===f);W||chunkS3BXVHO7_cjs.b("invalid-input",`no lesson "${f}"`,`raised lessons: ${n.lessons.filter(S=>S.status==="raised").map(S=>S.id).join(", ")||"(none)"}`),W.status!=="raised"&&chunkS3BXVHO7_cjs.b("invalid-input",`lesson "${f}" is already ${W.status}`,"only raised lessons can be adopted or dismissed");}return t(n,"ceremony.retro",e,(f,W)=>{let S=[],B=[],U=[],E=false,H=k=>{if(k)if(k.kind==="agreement")f.agreements.includes(k.text)||(f={...f,agreements:[...f.agreements,k.text]}),B.push(k.text);else if(k.kind==="dod"){let I=O(f).definitionOfDone;I.some(_=>JSON.stringify(_)===JSON.stringify(k.policy))||(E=true,f=re(f,[...I,k.policy]));}else k.kind==="backlog"&&(f=chunkJDVE7DQR_cjs.v(f,{...k.item,stage:"backlog",tags:[...k.item.tags??[],"retro"]},e.by,W),U.push(k.item.id));};for(let k of p){let I=`L${f.lessons.length+1}`,_={id:I,at:W,text:k.text,scope:k.scope,status:"adopted",from:e.by};k.suggestedChange&&(_.suggestedChange=k.suggestedChange),f={...f,lessons:[...f.lessons,_]},S.push(I),H(k.suggestedChange);}for(let k of c)f={...f,lessons:f.lessons.map(I=>I.id===k.id?{...I,status:"adopted",...k.suggestedChange?{suggestedChange:k.suggestedChange}:{}}:I)},S.push(k.id),H(k.suggestedChange??f.lessons.find(I=>I.id===k.id)?.suggestedChange);for(let k of d)f={...f,lessons:f.lessons.map(I=>I.id===k?{...I,status:"dismissed"}:I)};return v&&(E=true,f=re(f,v)),chunkJDVE7DQR_cjs.c(f,"retro",e.by,{sprint:a.id,adopted:S,dismissed:d,agreements:B,dodChanged:E,backlogAdded:U},W)})},cancel:(n,e)=>{chunkJDVE7DQR_cjs.o(n,e.by,"order-backlog");let a=chunkQDT35LXB_cjs.f(n);return a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint to cancel","nothing to do"),t(n,"ceremony.cancel",e,(l,p)=>(l=chunkJDVE7DQR_cjs.c(l,"sprint.cancelled",e.by,{id:a.id,reason:e.reason??""},p),T(l,"cancel",p)))}}}var he=new Set(["never","po-only","any"]);function se(o){let t=o??{},r=t.sprintBudget;(!r||typeof r!="object"||r.tokens===void 0&&r.turns===void 0&&r.wallclockMs===void 0)&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.sprintBudget must define tokens, turns or wallclockMs",'e.g. { "sprintBudget": { "tokens": 400000, "turns": 60 } }'),(typeof t.productGoal!="string"||t.productGoal.trim()==="")&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.productGoal must be a non-empty string","state the Product Goal in one sentence"),Array.isArray(t.definitionOfDone)||chunkS3BXVHO7_cjs.b("config-invalid","scrum config.definitionOfDone must be a Policy[]",'e.g. [{ "kind": "evidence", "evidenceKind": "test-output" }]');let i=t.refinementSharePct??10;(typeof i!="number"||i<0||i>100)&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.refinementSharePct must be 0..100","omit it for the default 10");let y=t.allowMidSprintAdd??"po-only";(typeof y!="string"||!he.has(y))&&chunkS3BXVHO7_cjs.b("config-invalid",`scrum config.allowMidSprintAdd must be never | po-only | any (got ${JSON.stringify(y)})`,'use "po-only" unless you have a reason');let u=t.inProgressWipLimit;u!==void 0&&(typeof u!="number"||u<1)&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.inProgressWipLimit must be a positive number","omit it for no limit");let g={sprintBudget:r,productGoal:t.productGoal,definitionOfDone:t.definitionOfDone,refinementSharePct:i,allowMidSprintAdd:y};return u!==void 0&&(g.inProgressWipLimit=u),g}var D=(o,t)=>t===0?0:o/t;function ae(o){let t=o.events.filter(s=>s.type==="sprint.closed").map(s=>s.payload),r=t.filter(s=>s.reason!=="cancel"),i=r.map(s=>s.doneWeight),y=r.reduce((s,n)=>s+n.doneWeight,0),u=r.reduce((s,n)=>s+n.committedWeight,0),g=o.events.filter(s=>s.type==="increment").map(s=>s.payload),m=t.filter(s=>s.budget.tokens!==void 0),h=r.reduce((s,n)=>s+n.spent.tokens,0);return {velocity:i,meanVelocity:D(i.reduce((s,n)=>s+n,0),i.length),burndown:o.events.filter(s=>s.type==="daily").map(s=>s.payload.remainingWeight),commitmentReliability:D(y,u),sprintGoalHitRate:D(g.filter(s=>s.goalMet).length,g.length),carryoverRatio:D(t.reduce((s,n)=>s+n.carryover.length,0),t.reduce((s,n)=>s+n.done.length+n.carryover.length,0)),budgetUtilisation:D(m.reduce((s,n)=>s+n.spent.tokens,0),m.reduce((s,n)=>s+(n.budget.tokens??0),0)),costPerPoint:D(h,y)}}function ce(){return [{id:"product-owner",name:"Product Owner",modelTier:"large",capabilities:["order-backlog","define-acceptance","escalate"],canApprove:["sprint-review"],inputs:["stakeholder-needs","product-goal"],outputs:["ordered-backlog","acceptance-criteria"],do_not:["do not implement items yourself"]},{id:"scrum-master",name:"Scrum Master",modelTier:"large",capabilities:["facilitate","escalate"],canApprove:[],inputs:["board","blockers"],outputs:["ceremony-records","lessons"],do_not:["do not reorder the Product Backlog","do not assign work; the planner pulls"]},{id:"developer",name:"Developer",modelTier:"small",capabilities:["deliver","review","verify"],canApprove:[],inputs:["brief"],outputs:["code","test-output"],do_not:["do not change acceptance criteria","do not touch items outside your brief"]}]}var R=(o,t,r,i,y)=>y?{rule:o,severity:t,item:y,message:r,fix:i}:{rule:o,severity:t,message:r,fix:i};function de(o){for(let t=o.iterations.length-1;t>=0;t--){let r=o.iterations[t];if(r.endedAt!==void 0)return r}}function le(){return [{id:"one-open-sprint",severity:"error",check:(m,h)=>h.type==="ceremony.plan"&&chunkQDT35LXB_cjs.f(m)?[R("one-open-sprint","error",`sprint ${chunkQDT35LXB_cjs.f(m).id} is still open`,"review or cancel it before planning the next sprint")]:[]},{id:"retro-before-plan",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.plan")return [];let s=de(m);if(!s)return [];let n=F(m,s.id);if(m.events.some(a=>a.type==="retro"&&a.seq>n))return [];let e=s.outcome==="cancelled"?"warning":"error";return [R("retro-before-plan",e,`sprint ${s.id} has no retrospective yet`,"run the retro ceremony first (lessons may be empty)")]}},{id:"sprint-budget-fixed",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.plan")return [];let s=h.payload?.budget;return s===void 0||JSON.stringify(s)===JSON.stringify(O(m).sprintBudget)?[]:[R("sprint-budget-fixed","error","sprint length is fixed by config.sprintBudget","change sprintBudget in the config between sprints instead of per plan")]}},{id:"scope-protects-goal",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.commit")return [];let s=O(m),n=h.payload??{};return s.allowMidSprintAdd==="never"?[R("scope-protects-goal","error","mid-sprint additions are disabled",'set allowMidSprintAdd to "po-only" or wait for the next sprint')]:s.allowMidSprintAdd==="po-only"&&!chunkJDVE7DQR_cjs.n(m,h.by,"order-backlog")?[R("scope-protects-goal","error",`"${h.by}" may not add work mid-sprint`,"ask the Product Owner (order-backlog) to commit it")]:n.goalImpact!=="none"?[R("scope-protects-goal","error",`adding work with goalImpact "${n.goalImpact??"unset"}" endangers the Sprint Goal`,'only commit items with goalImpact: "none"; otherwise cancel and re-plan')]:[]}},{id:"po-orders-backlog",severity:"error",check:(m,h)=>h.type!=="ceremony.refine"||chunkJDVE7DQR_cjs.n(m,h.by,"order-backlog")?[]:((h.payload??{}).items??[]).filter(n=>n.patch.priority!==void 0).map(n=>R("po-orders-backlog","error",`"${h.by}" may not change the priority of "${n.id}"`,"only the Product Owner orders the backlog; drop priority from the patch",n.id))},{id:"dod-not-weakened",severity:"error",check:(m,h)=>h.type==="ceremony.retro"&&h.payload?.dodChanges!==void 0&&chunkQDT35LXB_cjs.f(m)?[R("dod-not-weakened","error","Definition of Done cannot change while a sprint is open","close the sprint first; DoD changes apply to the next sprint")]:[]},{id:"carryover-reestimated",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.plan")return [];let s=h.payload?.items;if(!Array.isArray(s))return [];let n=de(m);if(!n)return [];let e=F(m,n.id);return s.filter(a=>n.carryover.includes(a)&&!m.events.some(l=>l.type==="item.edited"&&l.seq>e&&l.payload.id===a&&l.payload.changed.includes("weight"))).map(a=>R("carryover-reestimated","error",`carried-over item "${a}" was not re-estimated after ${n.id}`,"refine it with a new weight before committing",a))}}]}function me(o){let t={id:"in_progress",name:"In progress",entryPolicy:[{kind:"dependencies-done"}],exitPolicy:[]};return o.inProgressWipLimit!==void 0&&(t.wipLimit=o.inProgressWipLimit),[{id:"backlog",name:"Product Backlog",entryPolicy:[],exitPolicy:[{kind:"acceptance-written"},{kind:"estimate-present"}]},{id:"sprint",name:"Sprint Backlog",entryPolicy:[],exitPolicy:[]},t,{id:"review",name:"Review",entryPolicy:[],exitPolicy:o.definitionOfDone,review:true},{id:"done",name:"Increment",entryPolicy:[],exitPolicy:[]}]}var be={backlog:"Product Backlog",item:"Product Backlog Item",stage:"Column",iteration:"Sprint",increment:"Increment",ceremony:"Scrum Event",gate:"Sprint Review"};function O(o){return o.config}function ke(o,t,r){let i=o,y=chunkJDVE7DQR_cjs.u(i,t).blockers.filter(g=>!g.clearedAt);if(y.length){i=chunkJDVE7DQR_cjs.s(i,t,g=>({...g,blockers:g.blockers.map(m=>m.clearedAt?m:{...m,clearedAt:r})}));for(let g of y)i=chunkJDVE7DQR_cjs.c(i,"blocker.cleared","system",{id:t,blocker:g.id,reason:"sprint closed"},r);}for(let g of i.pending.filter(m=>m.item===t))i={...i,pending:i.pending.filter(m=>m.id!==g.id)},i=chunkJDVE7DQR_cjs.c(i,"pending.dropped","system",{id:g.id,item:t,reason:"sprint closed"},r);let u=chunkJDVE7DQR_cjs.u(i,t);return (u.stage!=="backlog"||u.status!=="todo")&&(i=chunkJDVE7DQR_cjs.x(i,t,{stage:"backlog",status:"todo"},"system",r)),chunkJDVE7DQR_cjs.t(i,t,u.type==="question"?["iteration"]:["iteration","role"])}function T(o,t,r){let i=chunkQDT35LXB_cjs.f(o);if(!i)return o;let y=i.committed.map(e=>chunkJDVE7DQR_cjs.u(o,e)),u=y.filter(e=>e.status==="done").map(e=>e.id),g=y.filter(e=>e.status==="dropped").map(e=>e.id),m=y.filter(e=>e.status!=="done"&&e.status!=="dropped").map(e=>e.id),h=Object.values(o.items).filter(e=>e.type==="question"&&e.parent!==void 0&&m.includes(e.parent)&&e.status!=="done"&&e.status!=="dropped").map(e=>e.id),s=o;for(let e of [...m,...h])s=ke(s,e,r);let n=e=>e.reduce((a,l)=>a+(o.items[l]?.weight??0),0);return s={...s,iterations:s.iterations.map(e=>{if(e.id!==i.id)return e;let{closing:a,...l}=e;return {...l,endedAt:r,outcome:t==="cancel"?"cancelled":"completed",carryover:m}})},chunkJDVE7DQR_cjs.c(s,"sprint.closed","system",{id:i.id,reason:t,done:u,carryover:m,carriedQuestions:h,dropped:g,doneWeight:n(u),committedWeight:n(i.committed),spent:i.spent,budget:i.budget},r)}function ve(){return {name:"scrum",vocabulary:be,validateConfig:se,defaultStages:me,defaultRoles:ce,requiredCapabilities:["order-backlog","facilitate","deliver"],exclusiveCapabilities:["order-backlog"],plannerOptions(o){let t=O(o).inProgressWipLimit;return t===void 0?{schedulerMode:"level",dispatchStage:"in_progress"}:{schedulerMode:"level",dispatchStage:"in_progress",concurrencyCap:t}},candidates(o){let t=chunkQDT35LXB_cjs.f(o);return !t||t.closing?[]:Object.values(o.items).filter(r=>r.iteration===t.id&&(r.status==="todo"||r.status==="review")&&(r.stage==="sprint"||r.stage==="review"))},invariants(o,t){let r=chunkQDT35LXB_cjs.f(o),i=O(o),y=r?chunkQDT35LXB_cjs.c(r.budget,r.spent):{};return [`Sprint Goal: ${r?.goal??"(no open sprint)"}; Product Goal: ${i.productGoal}`,`Budget remaining: ${JSON.stringify(y)}; stop and hand off when it is gone`,`Definition of Done: ${i.definitionOfDone.map(u=>u.kind==="evidence"?`evidence ${u.evidenceKind}`:u.kind).join(", ")||"(none)"}`,`Do not change the scope of "${t.id}" or its acceptance criteria; raise open_questions instead`]},ceremonies:J(ve),rules:le(),metrics:o=>({...ae(o)}),humanDefaults:{gates:["sprint-review"]},afterComplete(o,t,r){let i=chunkQDT35LXB_cjs.f(o);return !i||!i.closing&&!chunkQDT35LXB_cjs.d(i.budget,i.spent)?o:Object.values(o.items).some(u=>u.iteration===i.id&&u.status==="in_progress")?i.closing?o:chunkJDVE7DQR_cjs.c({...o,iterations:o.iterations.map(u=>u.id===i.id?{...u,closing:true}:u)},"sprint.closing","system",{id:i.id},r):T(o,"budget",r)}}}exports.a=ie;exports.b=J;exports.c=se;exports.d=ae;exports.e=ce;exports.f=le;exports.g=me;exports.h=be;exports.i=O;exports.j=T;exports.k=ve;//# sourceMappingURL=chunk-472WEDPJ.cjs.map
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
'use strict';var chunkCWBH7H52_cjs=require('./chunk-CWBH7H52.cjs'),chunkSJRRQZ3R_cjs=require('./chunk-SJRRQZ3R.cjs'),chunkS3BXVHO7_cjs=require('./chunk-S3BXVHO7.cjs'),exsorted=require('exsorted');var ue=["todo","in_progress","blocked","review","awaiting_human","done","dropped"];function fe(o){let t=o.events.filter(r=>r.type==="sprint.closed"&&r.payload.reason!=="cancel");return t.length===0?null:t.reduce((r,i)=>r+i.payload.doneWeight,0)/t.length}function ie(o){let t=chunkCWBH7H52_cjs.f(o),r=Object.fromEntries(ue.map(n=>[n,0])),i=[],y=0;for(let n of t?.committed??[]){let e=o.items[n];if(e){r[e.status]+=1,e.status!=="done"&&(y+=e.weight??0);for(let a of e.blockers)a.clearedAt||i.push({item:n,blocker:a.id,owner:a.owner,reason:a.reason});}}let u=t?.spent??{tokens:0,turns:0,wallclockMs:0},g=t?chunkCWBH7H52_cjs.c(t.budget,t.spent):{},m=fe(o),h="unknown";if(t&&m!==null&&t.budget.tokens){let n=(g.tokens??0)/t.budget.tokens;h=y<=m*n?"on-track":"at-risk";}let s=o.lessons.filter(n=>n.status==="raised").length;return {sprint:t?.id??null,goal:t?.goal??null,byStatus:r,blockers:i,spent:u,remaining:g,remainingWeight:y,raisedLessons:s,velocity:m,forecast:h}}function V(o){for(let t=o.iterations.length-1;t>=0;t--){let r=o.iterations[t];if(r.endedAt!==void 0)return r}}function F(o,t){return o.events.find(r=>r.type==="sprint.closed"&&r.payload.id===t)?.seq??Number.POSITIVE_INFINITY}function ge(o){let t=new Set(V(o)?.carryover??[]),r=Object.values(o.items).filter(i=>i.stage==="backlog"&&i.status==="todo"&&i.type!=="question");return exsorted.timSort([...r],(i,y)=>{let u=t.has(i.id)?1:0,g=t.has(y.id)?1:0;return u!==g?g-u:(y.priority??0)-(i.priority??0)})}function ne(o,t){let r=chunkSJRRQZ3R_cjs.u(o,t);(r.stage!=="backlog"||r.status!=="todo")&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${t}" is not in the Product Backlog (${r.stage}/${r.status})`,"only backlog items can be committed",{items:[t]}),chunkSJRRQZ3R_cjs.E(o,r,chunkSJRRQZ3R_cjs.p(o,"backlog").exitPolicy,"enter the Sprint Backlog");}function oe(o,t,r,i,y){let u=o;for(let g of Object.values(o.items))g.type!=="question"||g.parent===void 0||!t.includes(g.parent)||g.status==="done"||g.status==="dropped"||((g.stage!=="sprint"||g.status!=="todo")&&(u=chunkSJRRQZ3R_cjs.x(u,g.id,{stage:"sprint",status:"todo"},i,y)),u=chunkSJRRQZ3R_cjs.s(u,g.id,m=>({...m,iteration:r})));return u}function re(o,t){return {...o,config:{...O(o),definitionOfDone:t},stages:o.stages.map(r=>r.id==="review"?{...r,exitPolicy:t}:r)}}function ye(o,t){let r=[],i=0;for(let y of ge(o)){if(t.tokens!==void 0){let u=chunkCWBH7H52_cjs.e(o,y.weight);if(i+u>t.tokens)break;i+=u;}else if(t.turns!==void 0&&r.length>=t.turns)break;r.push(y.id);}return r}function J(o){let t=(n,e,a,l)=>chunkSJRRQZ3R_cjs.M(n,o(),{type:e,by:a.by,payload:a},p=>l(p,chunkSJRRQZ3R_cjs.a(a.now)));return {refine:(n,e)=>{chunkSJRRQZ3R_cjs.o(n,e.by,"define-acceptance","deliver");let a=e.items??[],l=e.split??[];return a.length===0&&l.length===0&&chunkS3BXVHO7_cjs.b("invalid-input","refine needs items[] or split[]","pass at least one patch or split"),t(n,"ceremony.refine",e,(p,c)=>{for(let{id:d,patch:v}of a)p=chunkSJRRQZ3R_cjs.w(p,d,v,e.by,c);for(let d of l){chunkSJRRQZ3R_cjs.u(p,d.from);for(let v of d.into)p=chunkSJRRQZ3R_cjs.v(p,{...v,parent:d.from},e.by,c);p=chunkSJRRQZ3R_cjs.x(p,d.from,{status:"dropped"},e.by,c);}return chunkSJRRQZ3R_cjs.c(p,"ceremony.refine",e.by,{edited:a.map(d=>d.id),split:l.map(d=>({from:d.from,into:d.into.map(v=>v.id)}))},c)})},plan:(n,e)=>{chunkSJRRQZ3R_cjs.o(n,e.by,"facilitate");let a=e.goal;(typeof a!="string"||a.trim()==="")&&chunkS3BXVHO7_cjs.b("invalid-input","sprint planning needs a non-empty goal","state the Sprint Goal in one sentence");let l=O(n),p=e.budget??l.sprintBudget,c=e.items==="auto"?ye(n,p):e.items;Array.isArray(c)||chunkS3BXVHO7_cjs.b("invalid-input",'sprint planning needs items: string[] or "auto"','pass ["A","B"] or "auto"'),c.length===0&&chunkS3BXVHO7_cjs.b("invalid-input","no backlog items fit the sprint","refine the backlog (acceptance + estimates) or raise the budget in config");for(let d of c)ne(n,d);return t(n,"ceremony.plan",e,(d,v)=>{let w=`S${d.iterations.length+1}`,q=V(d),f=c.filter(S=>q?.carryover.includes(S));for(let S of c)d=chunkSJRRQZ3R_cjs.x(d,S,{stage:"sprint",status:"todo"},e.by,v),d=chunkSJRRQZ3R_cjs.s(d,S,B=>({...B,iteration:w}));d=oe(d,c,w,e.by,v);let W=c.reduce((S,B)=>S+(d.items[B]?.weight??0),0);return d={...d,iterations:[...d.iterations,{id:w,goal:a,budget:p,spent:{tokens:0,turns:0,wallclockMs:0},startedAt:v,committed:[...c],carryover:f}]},chunkSJRRQZ3R_cjs.c(d,"sprint.opened",e.by,{id:w,goal:a,committed:c,committedWeight:W,budget:p},v)})},commit:(n,e)=>{let a=chunkCWBH7H52_cjs.f(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint to commit into","run the plan ceremony first");let l=e.items;(!Array.isArray(l)||l.length===0)&&chunkS3BXVHO7_cjs.b("invalid-input","commit needs items[]",'pass ["A"]');let p=new Set;for(let c of l)p.has(c)&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${c}" appears twice in items[]`,"list each item once",{items:[c]}),p.add(c),chunkSJRRQZ3R_cjs.u(n,c),a.committed.includes(c)&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${c}" is already committed to ${a.id}`,"nothing to do",{items:[c]}),ne(n,c);return t(n,"ceremony.commit",e,(c,d)=>{for(let v of l)c=chunkSJRRQZ3R_cjs.x(c,v,{stage:"sprint",status:"todo"},e.by,d),c=chunkSJRRQZ3R_cjs.s(c,v,w=>({...w,iteration:a.id}));return c=oe(c,l,a.id,e.by,d),c={...c,iterations:c.iterations.map(v=>v.id===a.id?{...v,committed:[...v.committed,...l]}:v)},chunkSJRRQZ3R_cjs.c(c,"sprint.committed",e.by,{id:a.id,items:l,goalImpact:e.goalImpact??null},d)})},uncommit:(n,e)=>{chunkSJRRQZ3R_cjs.o(n,e.by,"order-backlog");let a=chunkCWBH7H52_cjs.f(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint","nothing to uncommit from");let l=e.items;(!Array.isArray(l)||l.length===0)&&chunkS3BXVHO7_cjs.b("invalid-input","uncommit needs items[]",'pass ["A"]');for(let p of l)chunkSJRRQZ3R_cjs.u(n,p).status==="done"&&chunkS3BXVHO7_cjs.b("invalid-input",`item "${p}" is done`,"finished work cannot be uncommitted",{items:[p]});for(let p of l)a.committed.includes(p)||chunkS3BXVHO7_cjs.b("invalid-input",`item "${p}" is not committed to ${a.id}`,`committed: ${a.committed.join(", ")}`,{items:[p]});return t(n,"ceremony.uncommit",e,(p,c)=>{for(let d of l)p=chunkSJRRQZ3R_cjs.x(p,d,{stage:"backlog",status:"todo"},e.by,c),p=chunkSJRRQZ3R_cjs.t(p,d,["iteration","role"]);return p={...p,iterations:p.iterations.map(d=>d.id===a.id?{...d,committed:d.committed.filter(v=>!l.includes(v))}:d)},chunkSJRRQZ3R_cjs.c(p,"sprint.uncommitted",e.by,{id:a.id,items:l,reason:e.reason??""},c)})},daily:(n,e)=>t(n,"ceremony.daily",e,(a,l)=>chunkSJRRQZ3R_cjs.c(a,"daily",e.by,ie(a),l)),review:(n,e)=>{let a=chunkCWBH7H52_cjs.f(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint to review","run the plan ceremony first");let l=chunkSJRRQZ3R_cjs.j(n,"sprint-review");e.by!=="human"&&!l.includes(e.by)&&chunkS3BXVHO7_cjs.b("gate-unmet",`"${e.by}" may not accept the Sprint Review`,`run review as "human" or as ${l.join(", ")||"a role with canApprove sprint-review"}`,{rule:"sprint-review"});let p=e.feedback??[];return t(n,"ceremony.review",e,(c,d)=>{for(let w of p)c=chunkSJRRQZ3R_cjs.v(c,{...w,stage:"backlog"},e.by,d);let v=a.committed.filter(w=>c.items[w]?.status==="done");return c=chunkSJRRQZ3R_cjs.c(c,"increment",e.by,{sprint:a.id,done:v,goalMet:e.goalMet===true,accepted:e.accepted===true,feedback:p.map(w=>w.id)},d),T(c,"review",d)})},retro:(n,e)=>{chunkSJRRQZ3R_cjs.o(n,e.by,"facilitate");let a=V(n);a||chunkS3BXVHO7_cjs.b("invalid-input","no closed sprint to retrospect","close the sprint (review or cancel) first"),chunkCWBH7H52_cjs.f(n)&&chunkS3BXVHO7_cjs.b("invalid-input","a sprint is still open","retro runs between sprints; review or cancel the open one");let l=F(n,a.id);n.events.some(f=>f.type==="retro"&&f.seq>l)&&chunkS3BXVHO7_cjs.b("invalid-input",`sprint ${a.id} already has a retrospective`,"plan the next sprint");let p=e.lessons??[],c=e.adopt??[],d=e.dismiss??[],v=e.dodChanges,w=[...c.map(f=>f.id),...d],q=w.find((f,W)=>w.indexOf(f)!==W);q&&chunkS3BXVHO7_cjs.b("invalid-input",`lesson "${q}" is referenced more than once`,"adopt or dismiss each lesson once");for(let f of w){let W=n.lessons.find(S=>S.id===f);W||chunkS3BXVHO7_cjs.b("invalid-input",`no lesson "${f}"`,`raised lessons: ${n.lessons.filter(S=>S.status==="raised").map(S=>S.id).join(", ")||"(none)"}`),W.status!=="raised"&&chunkS3BXVHO7_cjs.b("invalid-input",`lesson "${f}" is already ${W.status}`,"only raised lessons can be adopted or dismissed");}return t(n,"ceremony.retro",e,(f,W)=>{let S=[],B=[],U=[],E=false,H=k=>{if(k)if(k.kind==="agreement")f.agreements.includes(k.text)||(f={...f,agreements:[...f.agreements,k.text]}),B.push(k.text);else if(k.kind==="dod"){let I=O(f).definitionOfDone;I.some(_=>JSON.stringify(_)===JSON.stringify(k.policy))||(E=true,f=re(f,[...I,k.policy]));}else k.kind==="backlog"&&(f=chunkSJRRQZ3R_cjs.v(f,{...k.item,stage:"backlog",tags:[...k.item.tags??[],"retro"]},e.by,W),U.push(k.item.id));};for(let k of p){let I=`L${f.lessons.length+1}`,_={id:I,at:W,text:k.text,scope:k.scope,status:"adopted",from:e.by};k.suggestedChange&&(_.suggestedChange=k.suggestedChange),f={...f,lessons:[...f.lessons,_]},S.push(I),H(k.suggestedChange);}for(let k of c)f={...f,lessons:f.lessons.map(I=>I.id===k.id?{...I,status:"adopted",...k.suggestedChange?{suggestedChange:k.suggestedChange}:{}}:I)},S.push(k.id),H(k.suggestedChange??f.lessons.find(I=>I.id===k.id)?.suggestedChange);for(let k of d)f={...f,lessons:f.lessons.map(I=>I.id===k?{...I,status:"dismissed"}:I)};return v&&(E=true,f=re(f,v)),chunkSJRRQZ3R_cjs.c(f,"retro",e.by,{sprint:a.id,adopted:S,dismissed:d,agreements:B,dodChanged:E,backlogAdded:U},W)})},cancel:(n,e)=>{chunkSJRRQZ3R_cjs.o(n,e.by,"order-backlog");let a=chunkCWBH7H52_cjs.f(n);return a||chunkS3BXVHO7_cjs.b("invalid-input","no open sprint to cancel","nothing to do"),t(n,"ceremony.cancel",e,(l,p)=>(l=chunkSJRRQZ3R_cjs.c(l,"sprint.cancelled",e.by,{id:a.id,reason:e.reason??""},p),T(l,"cancel",p)))}}}var he=new Set(["never","po-only","any"]);function se(o){let t=o??{},r=t.sprintBudget;(!r||typeof r!="object"||r.tokens===void 0&&r.turns===void 0&&r.wallclockMs===void 0)&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.sprintBudget must define tokens, turns or wallclockMs",'e.g. { "sprintBudget": { "tokens": 400000, "turns": 60 } }'),(typeof t.productGoal!="string"||t.productGoal.trim()==="")&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.productGoal must be a non-empty string","state the Product Goal in one sentence"),Array.isArray(t.definitionOfDone)||chunkS3BXVHO7_cjs.b("config-invalid","scrum config.definitionOfDone must be a Policy[]",'e.g. [{ "kind": "evidence", "evidenceKind": "test-output" }]');let i=t.refinementSharePct??10;(typeof i!="number"||i<0||i>100)&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.refinementSharePct must be 0..100","omit it for the default 10");let y=t.allowMidSprintAdd??"po-only";(typeof y!="string"||!he.has(y))&&chunkS3BXVHO7_cjs.b("config-invalid",`scrum config.allowMidSprintAdd must be never | po-only | any (got ${JSON.stringify(y)})`,'use "po-only" unless you have a reason');let u=t.inProgressWipLimit;u!==void 0&&(typeof u!="number"||u<1)&&chunkS3BXVHO7_cjs.b("config-invalid","scrum config.inProgressWipLimit must be a positive number","omit it for no limit");let g={sprintBudget:r,productGoal:t.productGoal,definitionOfDone:t.definitionOfDone,refinementSharePct:i,allowMidSprintAdd:y};return u!==void 0&&(g.inProgressWipLimit=u),g}var D=(o,t)=>t===0?0:o/t;function ae(o){let t=o.events.filter(s=>s.type==="sprint.closed").map(s=>s.payload),r=t.filter(s=>s.reason!=="cancel"),i=r.map(s=>s.doneWeight),y=r.reduce((s,n)=>s+n.doneWeight,0),u=r.reduce((s,n)=>s+n.committedWeight,0),g=o.events.filter(s=>s.type==="increment").map(s=>s.payload),m=t.filter(s=>s.budget.tokens!==void 0),h=r.reduce((s,n)=>s+n.spent.tokens,0);return {velocity:i,meanVelocity:D(i.reduce((s,n)=>s+n,0),i.length),burndown:o.events.filter(s=>s.type==="daily").map(s=>s.payload.remainingWeight),commitmentReliability:D(y,u),sprintGoalHitRate:D(g.filter(s=>s.goalMet).length,g.length),carryoverRatio:D(t.reduce((s,n)=>s+n.carryover.length,0),t.reduce((s,n)=>s+n.done.length+n.carryover.length,0)),budgetUtilisation:D(m.reduce((s,n)=>s+n.spent.tokens,0),m.reduce((s,n)=>s+(n.budget.tokens??0),0)),costPerPoint:D(h,y)}}function ce(){return [{id:"product-owner",name:"Product Owner",modelTier:"large",capabilities:["order-backlog","define-acceptance","escalate"],canApprove:["sprint-review"],inputs:["stakeholder-needs","product-goal"],outputs:["ordered-backlog","acceptance-criteria"],do_not:["do not implement items yourself"]},{id:"scrum-master",name:"Scrum Master",modelTier:"large",capabilities:["facilitate","escalate"],canApprove:[],inputs:["board","blockers"],outputs:["ceremony-records","lessons"],do_not:["do not reorder the Product Backlog","do not assign work; the planner pulls"]},{id:"developer",name:"Developer",modelTier:"small",capabilities:["deliver","review","verify"],canApprove:[],inputs:["brief"],outputs:["code","test-output"],do_not:["do not change acceptance criteria","do not touch items outside your brief"]}]}var R=(o,t,r,i,y)=>y?{rule:o,severity:t,item:y,message:r,fix:i}:{rule:o,severity:t,message:r,fix:i};function de(o){for(let t=o.iterations.length-1;t>=0;t--){let r=o.iterations[t];if(r.endedAt!==void 0)return r}}function le(){return [{id:"one-open-sprint",severity:"error",check:(m,h)=>h.type==="ceremony.plan"&&chunkCWBH7H52_cjs.f(m)?[R("one-open-sprint","error",`sprint ${chunkCWBH7H52_cjs.f(m).id} is still open`,"review or cancel it before planning the next sprint")]:[]},{id:"retro-before-plan",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.plan")return [];let s=de(m);if(!s)return [];let n=F(m,s.id);if(m.events.some(a=>a.type==="retro"&&a.seq>n))return [];let e=s.outcome==="cancelled"?"warning":"error";return [R("retro-before-plan",e,`sprint ${s.id} has no retrospective yet`,"run the retro ceremony first (lessons may be empty)")]}},{id:"sprint-budget-fixed",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.plan")return [];let s=h.payload?.budget;return s===void 0||JSON.stringify(s)===JSON.stringify(O(m).sprintBudget)?[]:[R("sprint-budget-fixed","error","sprint length is fixed by config.sprintBudget","change sprintBudget in the config between sprints instead of per plan")]}},{id:"scope-protects-goal",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.commit")return [];let s=O(m),n=h.payload??{};return s.allowMidSprintAdd==="never"?[R("scope-protects-goal","error","mid-sprint additions are disabled",'set allowMidSprintAdd to "po-only" or wait for the next sprint')]:s.allowMidSprintAdd==="po-only"&&!chunkSJRRQZ3R_cjs.n(m,h.by,"order-backlog")?[R("scope-protects-goal","error",`"${h.by}" may not add work mid-sprint`,"ask the Product Owner (order-backlog) to commit it")]:n.goalImpact!=="none"?[R("scope-protects-goal","error",`adding work with goalImpact "${n.goalImpact??"unset"}" endangers the Sprint Goal`,'only commit items with goalImpact: "none"; otherwise cancel and re-plan')]:[]}},{id:"po-orders-backlog",severity:"error",check:(m,h)=>h.type!=="ceremony.refine"||chunkSJRRQZ3R_cjs.n(m,h.by,"order-backlog")?[]:((h.payload??{}).items??[]).filter(n=>n.patch.priority!==void 0).map(n=>R("po-orders-backlog","error",`"${h.by}" may not change the priority of "${n.id}"`,"only the Product Owner orders the backlog; drop priority from the patch",n.id))},{id:"dod-not-weakened",severity:"error",check:(m,h)=>h.type==="ceremony.retro"&&h.payload?.dodChanges!==void 0&&chunkCWBH7H52_cjs.f(m)?[R("dod-not-weakened","error","Definition of Done cannot change while a sprint is open","close the sprint first; DoD changes apply to the next sprint")]:[]},{id:"carryover-reestimated",severity:"error",check:(m,h)=>{if(h.type!=="ceremony.plan")return [];let s=h.payload?.items;if(!Array.isArray(s))return [];let n=de(m);if(!n)return [];let e=F(m,n.id);return s.filter(a=>n.carryover.includes(a)&&!m.events.some(l=>l.type==="item.edited"&&l.seq>e&&l.payload.id===a&&l.payload.changed.includes("weight"))).map(a=>R("carryover-reestimated","error",`carried-over item "${a}" was not re-estimated after ${n.id}`,"refine it with a new weight before committing",a))}}]}function me(o){let t={id:"in_progress",name:"In progress",entryPolicy:[{kind:"dependencies-done"}],exitPolicy:[]};return o.inProgressWipLimit!==void 0&&(t.wipLimit=o.inProgressWipLimit),[{id:"backlog",name:"Product Backlog",entryPolicy:[],exitPolicy:[{kind:"acceptance-written"},{kind:"estimate-present"}]},{id:"sprint",name:"Sprint Backlog",entryPolicy:[],exitPolicy:[]},t,{id:"review",name:"Review",entryPolicy:[],exitPolicy:o.definitionOfDone,review:true},{id:"done",name:"Increment",entryPolicy:[],exitPolicy:[]}]}var be={backlog:"Product Backlog",item:"Product Backlog Item",stage:"Column",iteration:"Sprint",increment:"Increment",ceremony:"Scrum Event",gate:"Sprint Review"};function O(o){return o.config}function ke(o,t,r){let i=o,y=chunkSJRRQZ3R_cjs.u(i,t).blockers.filter(g=>!g.clearedAt);if(y.length){i=chunkSJRRQZ3R_cjs.s(i,t,g=>({...g,blockers:g.blockers.map(m=>m.clearedAt?m:{...m,clearedAt:r})}));for(let g of y)i=chunkSJRRQZ3R_cjs.c(i,"blocker.cleared","system",{id:t,blocker:g.id,reason:"sprint closed"},r);}for(let g of i.pending.filter(m=>m.item===t))i={...i,pending:i.pending.filter(m=>m.id!==g.id)},i=chunkSJRRQZ3R_cjs.c(i,"pending.dropped","system",{id:g.id,item:t,reason:"sprint closed"},r);let u=chunkSJRRQZ3R_cjs.u(i,t);return (u.stage!=="backlog"||u.status!=="todo")&&(i=chunkSJRRQZ3R_cjs.x(i,t,{stage:"backlog",status:"todo"},"system",r)),chunkSJRRQZ3R_cjs.t(i,t,u.type==="question"?["iteration"]:["iteration","role"])}function T(o,t,r){let i=chunkCWBH7H52_cjs.f(o);if(!i)return o;let y=i.committed.map(e=>chunkSJRRQZ3R_cjs.u(o,e)),u=y.filter(e=>e.status==="done").map(e=>e.id),g=y.filter(e=>e.status==="dropped").map(e=>e.id),m=y.filter(e=>e.status!=="done"&&e.status!=="dropped").map(e=>e.id),h=Object.values(o.items).filter(e=>e.type==="question"&&e.parent!==void 0&&m.includes(e.parent)&&e.status!=="done"&&e.status!=="dropped").map(e=>e.id),s=o;for(let e of [...m,...h])s=ke(s,e,r);let n=e=>e.reduce((a,l)=>a+(o.items[l]?.weight??0),0);return s={...s,iterations:s.iterations.map(e=>{if(e.id!==i.id)return e;let{closing:a,...l}=e;return {...l,endedAt:r,outcome:t==="cancel"?"cancelled":"completed",carryover:m}})},chunkSJRRQZ3R_cjs.c(s,"sprint.closed","system",{id:i.id,reason:t,done:u,carryover:m,carriedQuestions:h,dropped:g,doneWeight:n(u),committedWeight:n(i.committed),spent:i.spent,budget:i.budget},r)}function ve(){return {name:"scrum",vocabulary:be,validateConfig:se,defaultStages:me,defaultRoles:ce,requiredCapabilities:["order-backlog","facilitate","deliver"],exclusiveCapabilities:["order-backlog"],plannerOptions(o){let t=O(o).inProgressWipLimit;return t===void 0?{schedulerMode:"level",dispatchStage:"in_progress"}:{schedulerMode:"level",dispatchStage:"in_progress",concurrencyCap:t}},candidates(o){let t=chunkCWBH7H52_cjs.f(o);return !t||t.closing?[]:Object.values(o.items).filter(r=>r.iteration===t.id&&(r.status==="todo"||r.status==="review")&&(r.stage==="sprint"||r.stage==="review"))},invariants(o,t){let r=chunkCWBH7H52_cjs.f(o),i=O(o),y=r?chunkCWBH7H52_cjs.c(r.budget,r.spent):{};return [`Sprint Goal: ${r?.goal??"(no open sprint)"}; Product Goal: ${i.productGoal}`,`Budget remaining: ${JSON.stringify(y)}; stop and hand off when it is gone`,`Definition of Done: ${i.definitionOfDone.map(u=>u.kind==="evidence"?`evidence ${u.evidenceKind}`:u.kind).join(", ")||"(none)"}`,`Do not change the scope of "${t.id}" or its acceptance criteria; raise open_questions instead`]},ceremonies:J(ve),rules:le(),metrics:o=>({...ae(o)}),humanDefaults:{gates:["sprint-review"]},afterComplete(o,t,r){let i=chunkCWBH7H52_cjs.f(o);return !i||!i.closing&&!chunkCWBH7H52_cjs.d(i.budget,i.spent)?o:Object.values(o.items).some(u=>u.iteration===i.id&&u.status==="in_progress")?i.closing?o:chunkSJRRQZ3R_cjs.c({...o,iterations:o.iterations.map(u=>u.id===i.id?{...u,closing:true}:u)},"sprint.closing","system",{id:i.id},r):T(o,"budget",r)}}}exports.a=ie;exports.b=J;exports.c=se;exports.d=ae;exports.e=ce;exports.f=le;exports.g=me;exports.h=be;exports.i=O;exports.j=T;exports.k=ve;//# sourceMappingURL=chunk-7KF5K3L7.cjs.map
|
|
2
|
+
//# sourceMappingURL=chunk-7KF5K3L7.cjs.map
|