ex-workflow 0.0.0-stage → 0.2.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +153 -2
  4. package/dist/adapters/index.cjs +2 -0
  5. package/dist/adapters/index.cjs.map +1 -0
  6. package/dist/adapters/index.d.cts +17 -0
  7. package/dist/adapters/index.d.ts +17 -0
  8. package/dist/adapters/index.mjs +2 -0
  9. package/dist/adapters/index.mjs.map +1 -0
  10. package/dist/chunk-2FRRD6A3.mjs +2 -0
  11. package/dist/chunk-2FRRD6A3.mjs.map +1 -0
  12. package/dist/chunk-472WEDPJ.cjs +2 -0
  13. package/dist/chunk-472WEDPJ.cjs.map +1 -0
  14. package/dist/chunk-6R3YFUUV.cjs +6 -0
  15. package/dist/chunk-6R3YFUUV.cjs.map +1 -0
  16. package/dist/chunk-D4HNETUL.cjs +2 -0
  17. package/dist/chunk-D4HNETUL.cjs.map +1 -0
  18. package/dist/chunk-DBR24RTX.cjs +2 -0
  19. package/dist/chunk-DBR24RTX.cjs.map +1 -0
  20. package/dist/chunk-IBRC36PE.mjs +2 -0
  21. package/dist/chunk-IBRC36PE.mjs.map +1 -0
  22. package/dist/chunk-JDVE7DQR.cjs +2 -0
  23. package/dist/chunk-JDVE7DQR.cjs.map +1 -0
  24. package/dist/chunk-KIQOUUEZ.mjs +2 -0
  25. package/dist/chunk-KIQOUUEZ.mjs.map +1 -0
  26. package/dist/chunk-NQU5TH3A.mjs +2 -0
  27. package/dist/chunk-NQU5TH3A.mjs.map +1 -0
  28. package/dist/chunk-NRAPI3GV.cjs +2 -0
  29. package/dist/chunk-NRAPI3GV.cjs.map +1 -0
  30. package/dist/chunk-PD5FBDN7.mjs +2 -0
  31. package/dist/chunk-PD5FBDN7.mjs.map +1 -0
  32. package/dist/chunk-PO2SPQJP.cjs +2 -0
  33. package/dist/chunk-PO2SPQJP.cjs.map +1 -0
  34. package/dist/chunk-QDT35LXB.cjs +2 -0
  35. package/dist/chunk-QDT35LXB.cjs.map +1 -0
  36. package/dist/chunk-S3BXVHO7.cjs +2 -0
  37. package/dist/chunk-S3BXVHO7.cjs.map +1 -0
  38. package/dist/chunk-VGD4V5BA.mjs +6 -0
  39. package/dist/chunk-VGD4V5BA.mjs.map +1 -0
  40. package/dist/chunk-VN2UYV2O.mjs +2 -0
  41. package/dist/chunk-VN2UYV2O.mjs.map +1 -0
  42. package/dist/chunk-XSXHEEJX.mjs +2 -0
  43. package/dist/chunk-XSXHEEJX.mjs.map +1 -0
  44. package/dist/chunk-YJNDBKIG.mjs +2 -0
  45. package/dist/chunk-YJNDBKIG.mjs.map +1 -0
  46. package/dist/cli/bin.cjs +5 -0
  47. package/dist/cli/bin.cjs.map +1 -0
  48. package/dist/cli/bin.d.cts +1 -0
  49. package/dist/cli/bin.d.ts +1 -0
  50. package/dist/cli/bin.mjs +5 -0
  51. package/dist/cli/bin.mjs.map +1 -0
  52. package/dist/cli/index.cjs +2 -0
  53. package/dist/cli/index.cjs.map +1 -0
  54. package/dist/cli/index.d.cts +13 -0
  55. package/dist/cli/index.d.ts +13 -0
  56. package/dist/cli/index.mjs +2 -0
  57. package/dist/cli/index.mjs.map +1 -0
  58. package/dist/index.cjs +2 -0
  59. package/dist/index.cjs.map +1 -0
  60. package/dist/index.d.cts +134 -0
  61. package/dist/index.d.ts +134 -0
  62. package/dist/index.mjs +2 -0
  63. package/dist/index.mjs.map +1 -0
  64. package/dist/kanban/index.cjs +2 -0
  65. package/dist/kanban/index.cjs.map +1 -0
  66. package/dist/kanban/index.d.cts +225 -0
  67. package/dist/kanban/index.d.ts +225 -0
  68. package/dist/kanban/index.mjs +2 -0
  69. package/dist/kanban/index.mjs.map +1 -0
  70. package/dist/roles-BLBRKhUZ.d.ts +14 -0
  71. package/dist/roles-aneKYJ3Z.d.cts +14 -0
  72. package/dist/scrum/index.cjs +2 -0
  73. package/dist/scrum/index.cjs.map +1 -0
  74. package/dist/scrum/index.d.cts +59 -0
  75. package/dist/scrum/index.d.ts +59 -0
  76. package/dist/scrum/index.mjs +2 -0
  77. package/dist/scrum/index.mjs.map +1 -0
  78. package/dist/types.cjs +2 -0
  79. package/dist/types.cjs.map +1 -0
  80. package/dist/types.d.cts +330 -0
  81. package/dist/types.d.ts +330 -0
  82. package/dist/types.mjs +2 -0
  83. package/dist/types.mjs.map +1 -0
  84. package/package.json +146 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0-stage (unreleased)
4
+
5
+ Pre-release under the `stage` dist-tag.
6
+
7
+ - Kanban module (`ex-workflow/kanban`): configurable columns with WIP limits and explicit policies, commitment and delivery points, classes of service (expedite with WIP bypass, fixed-date, standard, intangible), six cadences, seven rules, a board view, cadences-due report, and flow metrics from events (lead and cycle time, throughput, WIP, flow efficiency, aging WIP, cumulative flow, SLE compliance, blocker time).
8
+ - Core: planner hooks `dispatchStage` (per-item function), `priorityOf`, `tieBreaker`, `wipCounts`, `wipLimitOf`; `Methodology.report`; `canDo` / `requireCap` exported.
9
+ - Core: `blocker.raised` / `blocker.cleared` events carry the item transition they made (`transition`, or `null`).
10
+ - Core: `plan()` / `next()` report `skipped` (ready cards not pulled, with reason and detail) and the same list is in the `planner.resolved` payload; the CLI `next` output includes it. New plan reason `policy-blocked`.
11
+ - Kanban: class-band ordering (question, expedite, fixed-date, standard, intangible) with aging promotion governed by `fairness.maxDeferralRounds` (default 5); the commitment column's policies gate the pull out of it.
12
+ - CLI: `exwf init kanban`; `exwf status` prints the methodology report.
13
+ - Size: `core+kanban` measured and budgeted next to `core+scrum` (both set at measured size; see size-budget.json).
14
+
15
+ ## 0.1.0-stage (2026-10-19)
16
+
17
+ Pre-release for integration testing, published under the `stage` dist-tag.
18
+
19
+ - Core: data-driven methodology engine (state, roles, items, gates, budgets, handoffs, escalation) on top of ex-flow.
20
+ - Scrum: sprint planning, daily, review, retro, carryover, DoD and agreements, velocity and cost-per-point metrics.
21
+ - Adapters subpath (`ex-workflow/adapters`): file-based state, briefs and handoffs with atomic writes and locking.
22
+ - `exwf` CLI (`ex-workflow/cli`): drive a workflow from the shell.
23
+ - 112 tests covering core, Scrum, adapters and CLI.
24
+ - Known backlog: see the "Known backlog" section of the README.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Supakit Kitjaroen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,154 @@
1
- # Temporary Holding Version
1
+ # ex-workflow
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Methodology engine for AI teams. Scrum, Kanban and Waterfall (Scrum and Kanban today; Waterfall follows) 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
+
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
+
7
+ ## Install
8
+
9
+ ```sh
10
+ pnpm add ex-workflow@stage
11
+ ```
12
+
13
+ Pre-releases are published under the `stage` dist-tag (currently `0.2.0-stage`); `latest` is reserved for 0.1.0.
14
+
15
+ Node >= 18. Runs on macOS, Linux and Windows.
16
+
17
+ ## Quick start
18
+
19
+ ```ts
20
+ import { init, addItem, next, complete } from "ex-workflow";
21
+ import { scrum } from "ex-workflow/scrum";
22
+
23
+ const m = scrum();
24
+ const config = { sprintBudget: { tokens: 300_000 }, productGoal: "ship the checkout", definitionOfDone: [{ kind: "evidence", evidenceKind: "test-output" }] };
25
+ let state = init({ methodology: m, config }).state;
26
+ state = addItem(state, { id: "CART", title: "cart API", weight: 3, priority: 5, acceptance: ["add/remove items"] }, "product-owner");
27
+ state = m.ceremonies["plan"]!(state, { by: "scrum-master", goal: "customers can pay", items: "auto" }).state;
28
+
29
+ const { state: s2, briefs } = next(state, m); // dispatches work, returns one brief per item
30
+ // ...run each brief with your agent, then record the result:
31
+ // state = complete(s2, m, handoff, accounting).state;
32
+ // state = m.ceremonies["review"]!(state, { by: "human", accepted: true, goalMet: true }).state;
33
+ ```
34
+
35
+ To persist state, use the file adapter (the only part of the package that touches disk):
36
+
37
+ ```ts
38
+ import { loadState, saveState, withStateLock } from "ex-workflow/adapters";
39
+
40
+ await withStateLock(process.cwd(), async () => {
41
+ const state = await loadState(process.cwd());
42
+ await saveState(process.cwd(), complete(state, m, handoff, accounting).state);
43
+ });
44
+ ```
45
+
46
+ `test/sprint.e2e.test.ts` is a complete two-sprint scenario: rework, a blocker, an escalation, a retro that changes the working agreements, and metrics.
47
+
48
+ ### Kanban
49
+
50
+ ```ts
51
+ import { addItem, complete, init, next } from "ex-workflow";
52
+ import { board, kanban, kanbanMetrics } from "ex-workflow/kanban";
53
+
54
+ const m = kanban(); // default board: options → ready (commit, WIP 4) → dev (WIP 3) → review (WIP 2) → done
55
+ let state = init({ methodology: m, config: { classesOfService: { standard: { sle: { percentile: 85, targetMs: 7 * 86_400_000 } } } } }).state;
56
+ state = addItem(state, { id: "SEARCH", title: "search box", acceptance: ["finds by name"] }, "service-request-manager");
57
+ state = m.ceremonies["replenishment"]!(state, { by: "service-request-manager", items: ["SEARCH"] }).state; // the only push: options → commitment point
58
+ const { state: s2, briefs } = next(state, m); // the planner pulls ready → dev within WIP; expedite cards jump the queue
59
+ // ...run each brief, then complete(s2, m, handoff, accounting); cards advance column by column
60
+ board(s2, new Date().toISOString()); // columns with active/queued counts and card ages
61
+ kanbanMetrics(s2); // lead time, cycle time per column, throughput, WIP, flow efficiency, aging, CFD, SLE compliance
62
+ ```
63
+
64
+ Cadences are ceremonies: `replenishment`, `delivery-planning`, `service-delivery-review` (WIP, policies, SLEs), `operations-review` (blockers, aging WIP), `risk-review` (fixed-date risk, stale blockers), `strategy-review` (classes of service). `exwf status` reports which cadences are due (`config.cadences.<name>.everyTurns`). `test/kanban.e2e.test.ts` is a full week with an expedite, an escalation and a blocker.
65
+
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
+
68
+ ## CLI
69
+
70
+ State lives in `.workflow/`. Every command prints JSON; errors exit 1, bad usage exits 2.
71
+
72
+ | Command | Returns |
73
+ |---|---|
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 }` |
77
+ | `next [--max n]` | `{ ok, reason, skipped, briefs }`; writes `.workflow/briefs/<id>.json` |
78
+ | `complete <id> <handoff.json> --tokens-in n --tokens-out n --duration-ms n --model m [--role r]` | `{ ok, item, warnings }` |
79
+ | `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, e.g. Kanban's cadences due; `null` for Scrum) |
82
+ | `board` | `{ ok, columns }` |
83
+ | `metrics` | `{ ok, metrics }` |
84
+ | `pending` / `lessons` | the arrays |
85
+ | `validate <action.json>` | `{ ok: true, violations }` |
86
+ | `role add <manifest.json>` / `role list` | `{ ok, roles }` |
87
+
88
+ `--by` defaults to `human`.
89
+
90
+ ### Concurrency
91
+
92
+ 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
+
94
+ ## Layers
95
+
96
+ ```
97
+ L3 MCP server (planned) daemon, hook enforcement, dashboard, team mode
98
+ L2 agent adapters Claude Code agents/*.md, future Cursor/Codex formats (planned)
99
+ L1 skills SKILL.md + scripts/wf.js (bundled L0) (planned)
100
+ L0 ex-workflow this spec: state, policy, planner, accounting (npm, free)
101
+ ```
102
+
103
+ This package is L0. All layers read and write the same `.workflow/` files.
104
+
105
+ ## Status
106
+
107
+ 0.2.0-stage adds the Kanban module. Waterfall follows. Design: [docs/superpowers/specs/2026-10-19-ex-workflow-design.md](docs/superpowers/specs/2026-10-19-ex-workflow-design.md).
108
+
109
+ ## Known backlog
110
+
111
+ Minor items deferred past 0.2.0-stage:
112
+
113
+ - Stale-lock takeover can race when a lock is older than 60 s.
114
+ - `decide(approve)` ignores a `needs-review` verdict.
115
+ - `setDod` hard-codes the `review` stage id in the Scrum methodology.
116
+ - The `closing` sprint state is not enforced on commit, plan or uncommit.
117
+ - State is written before briefs; a crash between the two leaves them out of step.
118
+ - `roles/*.json` are re-merged on every load.
119
+ - Evidence can go stale across a rework cycle.
120
+ - The scrum stub size row in `size-budget.json` guards little; the `core+scrum` budget ratchets down from 45238 B (spec target 40960 B).
121
+ - Kanban WIP limits bound active cards (`in_progress`, `blocked`, `awaiting_human`); cards the engine advanced into a column's queue are reported as `queued` and surfaced by operations-review, not refused.
122
+ - Kanban `wipBypass` is the total number of extra slots a column grants while any expedite is active, not one per expedite.
123
+ - Kanban cadences use `item.completed` counts as turns; a wall-clock cadence schedule is the host's job.
124
+ - Minor test gaps: retro duplicate-ref rejection, `writeAtomic` failure path, thin CLI usage and `decide` tests.
125
+
126
+ ## Development gate
127
+
128
+ 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
130
+ minified build, the dist identity check and the size ratchet, and `prepublishOnly` runs it
131
+ before any publish. oxfmt and oxlint need Node ^20.19 or >=22.12 on the developer machine; the
132
+ package itself supports Node >=18 (verified on ubuntu, macOS and Windows x Node 18/20/22
133
+ before the hosted workflow was removed).
134
+
135
+ ## Publishing
136
+
137
+ For the owner. The `stage` dist-tag keeps `latest` free for 0.1.0:
138
+
139
+ ```sh
140
+ pnpm run ci && npm publish --tag stage
141
+ ```
142
+
143
+ ## Design principles
144
+
145
+ 1. One engine, three methodologies (Scrum and Kanban today; Waterfall follows), 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
+ 2. The program decides, the LLM executes. Which item may move, who may approve, whether a stage may start: engine, not prompt.
147
+ 3. Roles are data. Methodologies reference capabilities, never role names.
148
+ 4. Pure, serialisable state. Every operation is `(state, action) -> state` or `(state) -> view`. No I/O in core.
149
+ 5. Zero runtime dependencies beyond `ex-flow` and `exsorted` (both MIT, both the owner's). Runs on Node on macOS, Linux and Windows.
150
+ 6. Errors resolve: every violation names the exact rule, the exact item, and a concrete fix.
151
+
152
+ ## License
153
+
154
+ MIT
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunk6R3YFUUV_cjs=require('../chunk-6R3YFUUV.cjs');require('../chunk-S3BXVHO7.cjs');Object.defineProperty(exports,"WORKFLOW_DIR",{enumerable:true,get:function(){return chunk6R3YFUUV_cjs.a}});Object.defineProperty(exports,"loadState",{enumerable:true,get:function(){return chunk6R3YFUUV_cjs.e}});Object.defineProperty(exports,"saveBrief",{enumerable:true,get:function(){return chunk6R3YFUUV_cjs.f}});Object.defineProperty(exports,"saveHandoff",{enumerable:true,get:function(){return chunk6R3YFUUV_cjs.g}});Object.defineProperty(exports,"saveState",{enumerable:true,get:function(){return chunk6R3YFUUV_cjs.d}});Object.defineProperty(exports,"statePath",{enumerable:true,get:function(){return chunk6R3YFUUV_cjs.b}});Object.defineProperty(exports,"withStateLock",{enumerable:true,get:function(){return chunk6R3YFUUV_cjs.c}});//# sourceMappingURL=index.cjs.map
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
@@ -0,0 +1,17 @@
1
+ import { WorkflowState, Brief, Handoff } from '../types.cjs';
2
+
3
+ declare const WORKFLOW_DIR = ".workflow";
4
+ declare function statePath(root: string): string;
5
+ interface LockOptions {
6
+ retries?: number;
7
+ intervalMs?: number;
8
+ staleMs?: number;
9
+ }
10
+ /** Run `fn` while holding `.workflow/state.lock`, so concurrent exwf commands cannot lose each other's updates. */
11
+ declare function withStateLock<T>(root: string, fn: () => Promise<T>, opts?: LockOptions): Promise<T>;
12
+ declare function saveState(root: string, state: WorkflowState): Promise<void>;
13
+ declare function loadState(root: string): Promise<WorkflowState>;
14
+ declare function saveBrief(root: string, brief: Brief): Promise<string>;
15
+ declare function saveHandoff(root: string, handoff: Handoff, seq: number): Promise<string>;
16
+
17
+ export { type LockOptions, WORKFLOW_DIR, loadState, saveBrief, saveHandoff, saveState, statePath, withStateLock };
@@ -0,0 +1,17 @@
1
+ import { WorkflowState, Brief, Handoff } from '../types.js';
2
+
3
+ declare const WORKFLOW_DIR = ".workflow";
4
+ declare function statePath(root: string): string;
5
+ interface LockOptions {
6
+ retries?: number;
7
+ intervalMs?: number;
8
+ staleMs?: number;
9
+ }
10
+ /** Run `fn` while holding `.workflow/state.lock`, so concurrent exwf commands cannot lose each other's updates. */
11
+ declare function withStateLock<T>(root: string, fn: () => Promise<T>, opts?: LockOptions): Promise<T>;
12
+ declare function saveState(root: string, state: WorkflowState): Promise<void>;
13
+ declare function loadState(root: string): Promise<WorkflowState>;
14
+ declare function saveBrief(root: string, brief: Brief): Promise<string>;
15
+ declare function saveHandoff(root: string, handoff: Handoff, seq: number): Promise<string>;
16
+
17
+ export { type LockOptions, WORKFLOW_DIR, loadState, saveBrief, saveHandoff, saveState, statePath, withStateLock };
@@ -0,0 +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-VGD4V5BA.mjs';import'../chunk-2FRRD6A3.mjs';//# sourceMappingURL=index.mjs.map
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
@@ -0,0 +1,2 @@
1
+ var o=class extends Error{code;fix;items;rule;constructor(t,i,e,s={}){if(!e||e.trim()==="")throw new TypeError("WorkflowError: fix must not be empty");super(i),this.name="WorkflowError",this.code=t,this.fix=e,s.items&&(this.items=s.items),s.rule&&(this.rule=s.rule);}toJSON(){return {code:this.code,message:this.message,fix:this.fix,...this.items?{items:this.items}:{},...this.rule?{rule:this.rule}:{}}}};function n(r,t,i,e){throw new o(r,t,i,e)}var l=new Set(["__proto__","constructor","prototype"]);function g(r,t){(typeof r!="string"||!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(r)||r.includes("..")||l.has(r))&&n("invalid-input",`${t} ${JSON.stringify(r)} is not a valid id`,"use letters, digits, - _ . (e.g. CART-12)");}export{o as a,n as b,g as c};//# sourceMappingURL=chunk-2FRRD6A3.mjs.map
2
+ //# sourceMappingURL=chunk-2FRRD6A3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"names":["WorkflowError","code","message","fix","extra","fail","RESERVED_IDS","assertId","id","what"],"mappings":"AAOO,IAAMA,CAAAA,CAAN,cAA4B,KAAM,CAC9B,KACA,GAAA,CACA,KAAA,CACA,IAAA,CAET,WAAA,CAAYC,CAAAA,CAAiBC,CAAAA,CAAiBC,CAAAA,CAAaC,CAAAA,CAA4B,EAAC,CAAG,CACzF,GAAI,CAACD,CAAAA,EAAOA,CAAAA,CAAI,IAAA,EAAK,GAAM,GAAI,MAAM,IAAI,SAAA,CAAU,sCAAsC,EACzF,KAAA,CAAMD,CAAO,CAAA,CACb,IAAA,CAAK,KAAO,eAAA,CACZ,IAAA,CAAK,IAAA,CAAOD,CAAAA,CACZ,IAAA,CAAK,GAAA,CAAME,CAAAA,CACPC,CAAAA,CAAM,QAAO,IAAA,CAAK,KAAA,CAAQA,CAAAA,CAAM,KAAA,CAAA,CAChCA,EAAM,IAAA,GAAM,IAAA,CAAK,IAAA,CAAOA,CAAAA,CAAM,MACpC,CAEA,MAAA,EAA6F,CAC3F,OAAO,CACL,IAAA,CAAM,IAAA,CAAK,IAAA,CACX,QAAS,IAAA,CAAK,OAAA,CACd,GAAA,CAAK,IAAA,CAAK,IACV,GAAI,IAAA,CAAK,KAAA,CAAQ,CAAE,MAAO,IAAA,CAAK,KAAM,CAAA,CAAI,EAAC,CAC1C,GAAI,IAAA,CAAK,IAAA,CAAO,CAAE,IAAA,CAAM,IAAA,CAAK,IAAK,CAAA,CAAI,EACxC,CACF,CACF,EAEO,SAASC,CAAAA,CACdJ,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACO,CACP,MAAM,IAAIJ,EAAcC,CAAAA,CAAMC,CAAAA,CAASC,CAAAA,CAAKC,CAAK,CACnD,CAEA,IAAME,CAAAA,CAAe,IAAI,IAAI,CAAC,WAAA,CAAa,aAAA,CAAe,WAAW,CAAC,CAAA,CAG/D,SAASC,CAAAA,CAASC,EAAaC,CAAAA,CAAoB,CAAA,CAEtD,OAAOD,CAAAA,EAAO,UACd,CAAC,8BAAA,CAA+B,IAAA,CAAKA,CAAE,GACvCA,CAAAA,CAAG,QAAA,CAAS,IAAI,CAAA,EAChBF,CAAAA,CAAa,GAAA,CAAIE,CAAE,CAAA,GAEnBH,EACE,eAAA,CACA,CAAA,EAAGI,CAAI,CAAA,CAAA,EAAI,KAAK,SAAA,CAAUD,CAAE,CAAC,CAAA,kBAAA,CAAA,CAC7B,2CACF,EACJ","file":"chunk-2FRRD6A3.mjs","sourcesContent":["import type { ErrorCode } from \"./types.ts\";\n\nexport interface WorkflowErrorExtra {\n items?: string[];\n rule?: string;\n}\n\nexport class WorkflowError extends Error {\n readonly code: ErrorCode;\n readonly fix: string;\n readonly items?: string[];\n readonly rule?: string;\n\n constructor(code: ErrorCode, message: string, fix: string, extra: WorkflowErrorExtra = {}) {\n if (!fix || fix.trim() === \"\") throw new TypeError(\"WorkflowError: fix must not be empty\");\n super(message);\n this.name = \"WorkflowError\";\n this.code = code;\n this.fix = fix;\n if (extra.items) this.items = extra.items;\n if (extra.rule) this.rule = extra.rule;\n }\n\n toJSON(): { code: ErrorCode; message: string; fix: string; items?: string[]; rule?: string } {\n return {\n code: this.code,\n message: this.message,\n fix: this.fix,\n ...(this.items ? { items: this.items } : {}),\n ...(this.rule ? { rule: this.rule } : {}),\n };\n }\n}\n\nexport function fail(\n code: ErrorCode,\n message: string,\n fix: string,\n extra?: WorkflowErrorExtra,\n): never {\n throw new WorkflowError(code, message, fix, extra);\n}\n\nconst RESERVED_IDS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n/** Ids become object keys and file names: letters, digits, `.`, `_`, `-`; no `..`, no prototype names. */\nexport function assertId(id: unknown, what: string): void {\n if (\n typeof id !== \"string\" ||\n !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id) ||\n id.includes(\"..\") ||\n RESERVED_IDS.has(id)\n )\n fail(\n \"invalid-input\",\n `${what} ${JSON.stringify(id)} is not a valid id`,\n \"use letters, digits, - _ . (e.g. CART-12)\",\n );\n}\n"]}
@@ -0,0 +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-472WEDPJ.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/scrum/ceremonies.ts","../src/scrum/config.ts","../src/scrum/metrics.ts","../src/scrum/roles.ts","../src/scrum/rules.ts","../src/scrum/stages.ts","../src/scrum/index.ts"],"names":["STATUSES","velocityOf","state","closed","e","sum","dailyReport","it","openIteration","byStatus","s","blockers","remainingWeight","id","item","b","spent","rem","remaining","velocity","forecast","share","raisedLessons","l","lastClosedIteration","i","closedSeq","backlogOrdered","carry","items","timSort","x","cx","cy","assertCommittable","getItem","fail","assertPolicies","stageOf","attachQuestions","parentIds","iterationId","by","now","q","moveItem","patchItem","setDod","policies","configOf","st","selectAuto","budget","out","tokens","est","estimateTokens","scrumCeremonies","methodology","act","type","input","reduce","applyAction","nowOf","requireCap","split","patch","editItem","sp","n","addItem","appendEvent","goal","cfg","wanted","last","carryover","w","committedWeight","seen","stripItemFields","c","approvers","approverIds","feedback","done","f","closeSprint","closedAt","newLessons","adopt","dismiss","dod","refs","a","dupe","r","ref","adopted","agreements","backlogAdded","dodChanged","applyChange","cur","p","lesson","d","ADD_MODES","validateScrumConfig","raw","add","wip","ratio","num","den","scrumMetrics","counted","doneWeight","increments","withTokens","tokensSpent","scrumRoles","v","rule","severity","message","fix","lastClosed","scrumRules","seq","sev","canDo","scrumStages","config","inProgress","SCRUM_VOCABULARY","toBacklog","open","reason","committed","dropped","carriedQuestions","weightOf","ids","_c","rest","scrum","cap","left","_itemId","isExhausted"],"mappings":"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","file":"chunk-472WEDPJ.cjs","sourcesContent":["import { timSort } from \"exsorted\";\nimport { estimateTokens, remaining } from \"../budget.ts\";\nimport { fail } from \"../errors.ts\";\nimport {\n addItem,\n editItem,\n getItem,\n moveItem,\n patchItem,\n stageOf,\n stripItemFields,\n type ItemPatch,\n} from \"../items.ts\";\nimport { applyAction } from \"../methodology.ts\";\nimport { assertPolicies } from \"../policies.ts\";\nimport { openIteration } from \"../planner.ts\";\nimport { approverIds, canDo, requireCap } from \"../roles.ts\";\nexport { canDo };\nimport { appendEvent, nowOf } from \"../state.ts\";\nimport type {\n Budget,\n Ceremony,\n CeremonyInput,\n ItemStatus,\n Iteration,\n Lesson,\n LessonChange,\n Methodology,\n NewItem,\n Policy,\n WorkItem,\n WorkflowState,\n} from \"../types.ts\";\nimport { closeSprint, configOf } from \"./index.ts\";\n\nconst STATUSES: ItemStatus[] = [\n \"todo\",\n \"in_progress\",\n \"blocked\",\n \"review\",\n \"awaiting_human\",\n \"done\",\n \"dropped\",\n];\n\nexport interface DailyReport {\n sprint: string | null;\n goal: string | null;\n byStatus: Record<ItemStatus, number>;\n blockers: Array<{ item: string; blocker: string; owner: string; reason: string }>;\n spent: Required<Budget>;\n remaining: Budget;\n remainingWeight: number;\n raisedLessons: number;\n velocity: number | null;\n forecast: \"on-track\" | \"at-risk\" | \"unknown\";\n}\n\nexport function velocityOf(state: WorkflowState): number | null {\n const closed = state.events.filter(\n (e) => e.type === \"sprint.closed\" && (e.payload as { reason: string }).reason !== \"cancel\",\n );\n if (closed.length === 0) return null;\n return (\n closed.reduce((sum, e) => sum + (e.payload as { doneWeight: number }).doneWeight, 0) /\n closed.length\n );\n}\n\nexport function dailyReport(state: WorkflowState): DailyReport {\n const it = openIteration(state);\n const byStatus = Object.fromEntries(STATUSES.map((s) => [s, 0])) as Record<ItemStatus, number>;\n const blockers: DailyReport[\"blockers\"] = [];\n let remainingWeight = 0;\n for (const id of it?.committed ?? []) {\n const item = state.items[id];\n if (!item) continue;\n byStatus[item.status] += 1;\n if (item.status !== \"done\") remainingWeight += item.weight ?? 0;\n for (const b of item.blockers)\n if (!b.clearedAt)\n blockers.push({ item: id, blocker: b.id, owner: b.owner, reason: b.reason });\n }\n const spent = it?.spent ?? { tokens: 0, turns: 0, wallclockMs: 0 };\n const rem = it ? remaining(it.budget, it.spent) : {};\n const velocity = velocityOf(state);\n let forecast: DailyReport[\"forecast\"] = \"unknown\";\n if (it && velocity !== null && it.budget.tokens) {\n const share = (rem.tokens ?? 0) / it.budget.tokens;\n forecast = remainingWeight <= velocity * share ? \"on-track\" : \"at-risk\";\n }\n const raisedLessons = state.lessons.filter((l) => l.status === \"raised\").length;\n return {\n sprint: it?.id ?? null,\n goal: it?.goal ?? null,\n byStatus,\n blockers,\n spent,\n remaining: rem,\n remainingWeight,\n raisedLessons,\n velocity,\n forecast,\n };\n}\n\nfunction lastClosedIteration(state: WorkflowState): Iteration | undefined {\n for (let i = state.iterations.length - 1; i >= 0; i--) {\n const it = state.iterations[i]!;\n if (it.endedAt !== undefined) return it;\n }\n return undefined;\n}\n\n/** Event seq of the sprint.closed event of `id`; infinity when it is missing, so nothing counts as \"after\" it. */\nexport function closedSeq(state: WorkflowState, id: string): number {\n return (\n state.events.find((e) => e.type === \"sprint.closed\" && (e.payload as { id: string }).id === id)\n ?.seq ?? Number.POSITIVE_INFINITY\n );\n}\n\nfunction backlogOrdered(state: WorkflowState): WorkItem[] {\n const carry = new Set(lastClosedIteration(state)?.carryover ?? []);\n const items = Object.values(state.items).filter(\n (i) => i.stage === \"backlog\" && i.status === \"todo\" && i.type !== \"question\",\n );\n return timSort([...items], (x, y) => {\n const cx = carry.has(x.id) ? 1 : 0;\n const cy = carry.has(y.id) ? 1 : 0;\n if (cx !== cy) return cy - cx;\n return (y.priority ?? 0) - (x.priority ?? 0);\n });\n}\n\n/** Throw unless the item sits in the Product Backlog and meets the backlog exit policy. */\nfunction assertCommittable(state: WorkflowState, id: string): void {\n const item = getItem(state, id);\n if (item.stage !== \"backlog\" || item.status !== \"todo\")\n fail(\n \"invalid-input\",\n `item \"${id}\" is not in the Product Backlog (${item.stage}/${item.status})`,\n \"only backlog items can be committed\",\n { items: [id] },\n );\n assertPolicies(state, item, stageOf(state, \"backlog\").exitPolicy, \"enter the Sprint Backlog\");\n}\n\n/** Open questions raised by the given parents travel with them into the sprint (they carry no weight). */\nfunction attachQuestions(\n state: WorkflowState,\n parentIds: string[],\n iterationId: string,\n by: string,\n now: string,\n): WorkflowState {\n let s = state;\n for (const q of Object.values(state.items)) {\n if (\n q.type !== \"question\" ||\n q.parent === undefined ||\n !parentIds.includes(q.parent) ||\n q.status === \"done\" ||\n q.status === \"dropped\"\n )\n continue;\n if (q.stage !== \"sprint\" || q.status !== \"todo\")\n s = moveItem(s, q.id, { stage: \"sprint\", status: \"todo\" }, by, now);\n s = patchItem(s, q.id, (it) => ({ ...it, iteration: iterationId }));\n }\n return s;\n}\n\n/** Set the Definition of Done in the config and on the review stage. */\nfunction setDod(state: WorkflowState, policies: Policy[]): WorkflowState {\n return {\n ...state,\n config: { ...configOf(state), definitionOfDone: policies },\n stages: state.stages.map((st) => (st.id === \"review\" ? { ...st, exitPolicy: policies } : st)),\n };\n}\n\nfunction selectAuto(state: WorkflowState, budget: Budget): string[] {\n const out: string[] = [];\n let tokens = 0;\n for (const item of backlogOrdered(state)) {\n if (budget.tokens !== undefined) {\n const est = estimateTokens(state, item.weight);\n if (tokens + est > budget.tokens) break;\n tokens += est;\n } else if (budget.turns !== undefined && out.length >= budget.turns) break;\n out.push(item.id);\n }\n return out;\n}\n\nexport function scrumCeremonies(methodology: () => Methodology): Record<string, Ceremony> {\n const act = (\n state: WorkflowState,\n type: string,\n input: CeremonyInput,\n reduce: (s: WorkflowState, now: string) => WorkflowState,\n ) =>\n applyAction(state, methodology(), { type, by: input.by, payload: input }, (s) =>\n reduce(s, nowOf(input.now)),\n );\n\n const refine: Ceremony = (state, input) => {\n requireCap(state, input.by, \"define-acceptance\", \"deliver\");\n const items = (input[\"items\"] ?? []) as Array<{ id: string; patch: ItemPatch }>;\n const split = (input[\"split\"] ?? []) as Array<{ from: string; into: NewItem[] }>;\n if (items.length === 0 && split.length === 0)\n fail(\"invalid-input\", \"refine needs items[] or split[]\", \"pass at least one patch or split\");\n return act(state, \"ceremony.refine\", input, (s, now) => {\n for (const { id, patch } of items) s = editItem(s, id, patch, input.by, now);\n for (const sp of split) {\n getItem(s, sp.from);\n for (const n of sp.into) s = addItem(s, { ...n, parent: sp.from }, input.by, now);\n s = moveItem(s, sp.from, { status: \"dropped\" }, input.by, now);\n }\n return appendEvent(\n s,\n \"ceremony.refine\",\n input.by,\n {\n edited: items.map((i) => i.id),\n split: split.map((x) => ({ from: x.from, into: x.into.map((n) => n.id) })),\n },\n now,\n );\n });\n };\n\n const plan: Ceremony = (state, input) => {\n requireCap(state, input.by, \"facilitate\");\n const goal = input[\"goal\"];\n if (typeof goal !== \"string\" || goal.trim() === \"\")\n fail(\n \"invalid-input\",\n \"sprint planning needs a non-empty goal\",\n \"state the Sprint Goal in one sentence\",\n );\n const cfg = configOf(state);\n const budget = (input[\"budget\"] as Budget | undefined) ?? cfg.sprintBudget;\n const wanted =\n input[\"items\"] === \"auto\"\n ? selectAuto(state, budget)\n : (input[\"items\"] as string[] | undefined);\n if (!Array.isArray(wanted))\n fail(\n \"invalid-input\",\n 'sprint planning needs items: string[] or \"auto\"',\n 'pass [\"A\",\"B\"] or \"auto\"',\n );\n if (wanted.length === 0)\n fail(\n \"invalid-input\",\n \"no backlog items fit the sprint\",\n \"refine the backlog (acceptance + estimates) or raise the budget in config\",\n );\n for (const id of wanted) assertCommittable(state, id);\n return act(state, \"ceremony.plan\", input, (s, now) => {\n const id = `S${s.iterations.length + 1}`;\n const last = lastClosedIteration(s);\n const carryover = wanted.filter((w) => last?.carryover.includes(w));\n for (const w of wanted) {\n s = moveItem(s, w, { stage: \"sprint\", status: \"todo\" }, input.by, now);\n s = patchItem(s, w, (it) => ({ ...it, iteration: id }));\n }\n s = attachQuestions(s, wanted, id, input.by, now);\n const committedWeight = wanted.reduce((sum, w) => sum + (s.items[w]?.weight ?? 0), 0);\n s = {\n ...s,\n iterations: [\n ...s.iterations,\n {\n id,\n goal,\n budget,\n spent: { tokens: 0, turns: 0, wallclockMs: 0 },\n startedAt: now,\n committed: [...wanted],\n carryover,\n },\n ],\n };\n return appendEvent(\n s,\n \"sprint.opened\",\n input.by,\n { id, goal, committed: wanted, committedWeight, budget },\n now,\n );\n });\n };\n\n const commit: Ceremony = (state, input) => {\n const it = openIteration(state);\n if (!it) fail(\"invalid-input\", \"no open sprint to commit into\", \"run the plan ceremony first\");\n const items = input[\"items\"] as string[] | undefined;\n if (!Array.isArray(items) || items.length === 0)\n fail(\"invalid-input\", \"commit needs items[]\", 'pass [\"A\"]');\n const seen = new Set<string>();\n for (const id of items) {\n if (seen.has(id))\n fail(\"invalid-input\", `item \"${id}\" appears twice in items[]`, \"list each item once\", {\n items: [id],\n });\n seen.add(id);\n getItem(state, id);\n if (it.committed.includes(id))\n fail(\"invalid-input\", `item \"${id}\" is already committed to ${it.id}`, \"nothing to do\", {\n items: [id],\n });\n assertCommittable(state, id);\n }\n return act(state, \"ceremony.commit\", input, (s, now) => {\n for (const id of items) {\n s = moveItem(s, id, { stage: \"sprint\", status: \"todo\" }, input.by, now);\n s = patchItem(s, id, (x) => ({ ...x, iteration: it.id }));\n }\n s = attachQuestions(s, items, it.id, input.by, now);\n s = {\n ...s,\n iterations: s.iterations.map((x) =>\n x.id === it.id ? { ...x, committed: [...x.committed, ...items] } : x,\n ),\n };\n return appendEvent(\n s,\n \"sprint.committed\",\n input.by,\n { id: it.id, items, goalImpact: input[\"goalImpact\"] ?? null },\n now,\n );\n });\n };\n\n const uncommit: Ceremony = (state, input) => {\n requireCap(state, input.by, \"order-backlog\");\n const it = openIteration(state);\n if (!it) fail(\"invalid-input\", \"no open sprint\", \"nothing to uncommit from\");\n const items = input[\"items\"] as string[] | undefined;\n if (!Array.isArray(items) || items.length === 0)\n fail(\"invalid-input\", \"uncommit needs items[]\", 'pass [\"A\"]');\n for (const id of items) {\n if (getItem(state, id).status === \"done\")\n fail(\"invalid-input\", `item \"${id}\" is done`, \"finished work cannot be uncommitted\", {\n items: [id],\n });\n }\n for (const id of items)\n if (!it.committed.includes(id))\n fail(\n \"invalid-input\",\n `item \"${id}\" is not committed to ${it.id}`,\n `committed: ${it.committed.join(\", \")}`,\n { items: [id] },\n );\n return act(state, \"ceremony.uncommit\", input, (s, now) => {\n for (const id of items) {\n s = moveItem(s, id, { stage: \"backlog\", status: \"todo\" }, input.by, now);\n s = stripItemFields(s, id, [\"iteration\", \"role\"]);\n }\n s = {\n ...s,\n iterations: s.iterations.map((x) =>\n x.id === it.id ? { ...x, committed: x.committed.filter((c) => !items.includes(c)) } : x,\n ),\n };\n return appendEvent(\n s,\n \"sprint.uncommitted\",\n input.by,\n { id: it.id, items, reason: input[\"reason\"] ?? \"\" },\n now,\n );\n });\n };\n\n const daily: Ceremony = (state, input) =>\n act(state, \"ceremony.daily\", input, (s, now) =>\n appendEvent(s, \"daily\", input.by, dailyReport(s), now),\n );\n\n const review: Ceremony = (state, input) => {\n const it = openIteration(state);\n if (!it) fail(\"invalid-input\", \"no open sprint to review\", \"run the plan ceremony first\");\n const approvers = approverIds(state, \"sprint-review\");\n if (input.by !== \"human\" && !approvers.includes(input.by)) {\n fail(\n \"gate-unmet\",\n `\"${input.by}\" may not accept the Sprint Review`,\n `run review as \"human\" or as ${approvers.join(\", \") || \"a role with canApprove sprint-review\"}`,\n { rule: \"sprint-review\" },\n );\n }\n const feedback = (input[\"feedback\"] ?? []) as NewItem[];\n return act(state, \"ceremony.review\", input, (s, now) => {\n for (const n of feedback) s = addItem(s, { ...n, stage: \"backlog\" }, input.by, now);\n const done = it.committed.filter((id) => s.items[id]?.status === \"done\");\n s = appendEvent(\n s,\n \"increment\",\n input.by,\n {\n sprint: it.id,\n done,\n goalMet: input[\"goalMet\"] === true,\n accepted: input[\"accepted\"] === true,\n feedback: feedback.map((f) => f.id),\n },\n now,\n );\n return closeSprint(s, \"review\", now);\n });\n };\n\n const retro: Ceremony = (state, input) => {\n requireCap(state, input.by, \"facilitate\");\n const last = lastClosedIteration(state);\n if (!last)\n fail(\n \"invalid-input\",\n \"no closed sprint to retrospect\",\n \"close the sprint (review or cancel) first\",\n );\n if (openIteration(state))\n fail(\n \"invalid-input\",\n \"a sprint is still open\",\n \"retro runs between sprints; review or cancel the open one\",\n );\n const closedAt = closedSeq(state, last.id);\n if (state.events.some((e) => e.type === \"retro\" && e.seq > closedAt))\n fail(\n \"invalid-input\",\n `sprint ${last.id} already has a retrospective`,\n \"plan the next sprint\",\n );\n const newLessons = (input[\"lessons\"] ?? []) as Array<{\n text: string;\n scope: Lesson[\"scope\"];\n suggestedChange?: LessonChange;\n }>;\n const adopt = (input[\"adopt\"] ?? []) as Array<{ id: string; suggestedChange?: LessonChange }>;\n const dismiss = (input[\"dismiss\"] ?? []) as string[];\n const dod = input[\"dodChanges\"] as Policy[] | undefined;\n const refs = [...adopt.map((a) => a.id), ...dismiss];\n const dupe = refs.find((r, i) => refs.indexOf(r) !== i);\n if (dupe)\n fail(\n \"invalid-input\",\n `lesson \"${dupe}\" is referenced more than once`,\n \"adopt or dismiss each lesson once\",\n );\n for (const ref of refs) {\n const l = state.lessons.find((x) => x.id === ref);\n if (!l)\n fail(\n \"invalid-input\",\n `no lesson \"${ref}\"`,\n `raised lessons: ${\n state.lessons\n .filter((x) => x.status === \"raised\")\n .map((x) => x.id)\n .join(\", \") || \"(none)\"\n }`,\n );\n if (l.status !== \"raised\")\n fail(\n \"invalid-input\",\n `lesson \"${ref}\" is already ${l.status}`,\n \"only raised lessons can be adopted or dismissed\",\n );\n }\n return act(state, \"ceremony.retro\", input, (s, now) => {\n const adopted: string[] = [];\n const agreements: string[] = [];\n const backlogAdded: string[] = [];\n let dodChanged = false;\n const applyChange = (c: LessonChange | undefined) => {\n if (!c) return;\n if (c.kind === \"agreement\") {\n if (!s.agreements.includes(c.text)) s = { ...s, agreements: [...s.agreements, c.text] };\n agreements.push(c.text);\n } else if (c.kind === \"dod\") {\n const cur = configOf(s).definitionOfDone;\n if (!cur.some((p) => JSON.stringify(p) === JSON.stringify(c.policy))) {\n dodChanged = true;\n s = setDod(s, [...cur, c.policy]);\n }\n } else if (c.kind === \"backlog\") {\n s = addItem(\n s,\n { ...c.item, stage: \"backlog\", tags: [...(c.item.tags ?? []), \"retro\"] },\n input.by,\n now,\n );\n backlogAdded.push(c.item.id);\n }\n };\n for (const l of newLessons) {\n const id = `L${s.lessons.length + 1}`;\n const lesson: Lesson = {\n id,\n at: now,\n text: l.text,\n scope: l.scope,\n status: \"adopted\",\n from: input.by,\n };\n if (l.suggestedChange) lesson.suggestedChange = l.suggestedChange;\n s = { ...s, lessons: [...s.lessons, lesson] };\n adopted.push(id);\n applyChange(l.suggestedChange);\n }\n for (const a of adopt) {\n s = {\n ...s,\n lessons: s.lessons.map((x) =>\n x.id === a.id\n ? {\n ...x,\n status: \"adopted\" as const,\n ...(a.suggestedChange ? { suggestedChange: a.suggestedChange } : {}),\n }\n : x,\n ),\n };\n adopted.push(a.id);\n applyChange(a.suggestedChange ?? s.lessons.find((x) => x.id === a.id)?.suggestedChange);\n }\n for (const d of dismiss)\n s = {\n ...s,\n lessons: s.lessons.map((x) => (x.id === d ? { ...x, status: \"dismissed\" as const } : x)),\n };\n if (dod) {\n dodChanged = true;\n s = setDod(s, dod);\n }\n return appendEvent(\n s,\n \"retro\",\n input.by,\n {\n sprint: last.id,\n adopted,\n dismissed: dismiss,\n agreements,\n dodChanged,\n backlogAdded,\n },\n now,\n );\n });\n };\n\n const cancel: Ceremony = (state, input) => {\n requireCap(state, input.by, \"order-backlog\");\n const it = openIteration(state);\n if (!it) fail(\"invalid-input\", \"no open sprint to cancel\", \"nothing to do\");\n return act(state, \"ceremony.cancel\", input, (s, now) => {\n s = appendEvent(\n s,\n \"sprint.cancelled\",\n input.by,\n { id: it.id, reason: input[\"reason\"] ?? \"\" },\n now,\n );\n return closeSprint(s, \"cancel\", now);\n });\n };\n\n return { refine, plan, commit, uncommit, daily, review, retro, cancel };\n}\n","import { fail } from \"../errors.ts\";\nimport type { Budget, Policy } from \"../types.ts\";\n\nexport interface ScrumConfig {\n sprintBudget: Budget;\n productGoal: string;\n definitionOfDone: Policy[];\n refinementSharePct: number;\n allowMidSprintAdd: \"never\" | \"po-only\" | \"any\";\n inProgressWipLimit?: number;\n}\n\nconst ADD_MODES = new Set([\"never\", \"po-only\", \"any\"]);\n\nexport function validateScrumConfig(raw: unknown): ScrumConfig {\n const c = (raw ?? {}) as Record<string, unknown>;\n const budget = c[\"sprintBudget\"] as Budget | undefined;\n if (\n !budget ||\n typeof budget !== \"object\" ||\n (budget.tokens === undefined && budget.turns === undefined && budget.wallclockMs === undefined)\n ) {\n fail(\n \"config-invalid\",\n \"scrum config.sprintBudget must define tokens, turns or wallclockMs\",\n 'e.g. { \"sprintBudget\": { \"tokens\": 400000, \"turns\": 60 } }',\n );\n }\n if (typeof c[\"productGoal\"] !== \"string\" || c[\"productGoal\"].trim() === \"\")\n fail(\n \"config-invalid\",\n \"scrum config.productGoal must be a non-empty string\",\n \"state the Product Goal in one sentence\",\n );\n if (!Array.isArray(c[\"definitionOfDone\"]))\n fail(\n \"config-invalid\",\n \"scrum config.definitionOfDone must be a Policy[]\",\n 'e.g. [{ \"kind\": \"evidence\", \"evidenceKind\": \"test-output\" }]',\n );\n const share = c[\"refinementSharePct\"] ?? 10;\n if (typeof share !== \"number\" || share < 0 || share > 100)\n fail(\n \"config-invalid\",\n \"scrum config.refinementSharePct must be 0..100\",\n \"omit it for the default 10\",\n );\n const add = c[\"allowMidSprintAdd\"] ?? \"po-only\";\n if (typeof add !== \"string\" || !ADD_MODES.has(add))\n fail(\n \"config-invalid\",\n `scrum config.allowMidSprintAdd must be never | po-only | any (got ${JSON.stringify(add)})`,\n 'use \"po-only\" unless you have a reason',\n );\n const wip = c[\"inProgressWipLimit\"];\n if (wip !== undefined && (typeof wip !== \"number\" || wip < 1))\n fail(\n \"config-invalid\",\n \"scrum config.inProgressWipLimit must be a positive number\",\n \"omit it for no limit\",\n );\n const out: ScrumConfig = {\n sprintBudget: budget,\n productGoal: c[\"productGoal\"],\n definitionOfDone: c[\"definitionOfDone\"] as Policy[],\n refinementSharePct: share,\n allowMidSprintAdd: add as ScrumConfig[\"allowMidSprintAdd\"],\n };\n if (wip !== undefined) out.inProgressWipLimit = wip as number;\n return out;\n}\n","import type { Budget, WorkflowState } from \"../types.ts\";\n\ninterface Closed {\n reason: string;\n done: string[];\n carryover: string[];\n doneWeight: number;\n committedWeight: number;\n spent: Required<Budget>;\n budget: Budget;\n}\n\nexport interface ScrumMetrics {\n velocity: number[];\n meanVelocity: number;\n burndown: number[];\n commitmentReliability: number;\n sprintGoalHitRate: number;\n carryoverRatio: number;\n budgetUtilisation: number;\n costPerPoint: number;\n}\n\nconst ratio = (num: number, den: number) => (den === 0 ? 0 : num / den);\n\nexport function scrumMetrics(state: WorkflowState): ScrumMetrics {\n const closed = state.events\n .filter((e) => e.type === \"sprint.closed\")\n .map((e) => e.payload as Closed);\n const counted = closed.filter((c) => c.reason !== \"cancel\");\n const velocity = counted.map((c) => c.doneWeight);\n const doneWeight = counted.reduce((s, c) => s + c.doneWeight, 0);\n const committedWeight = counted.reduce((s, c) => s + c.committedWeight, 0);\n const increments = state.events\n .filter((e) => e.type === \"increment\")\n .map((e) => e.payload as { goalMet: boolean });\n const withTokens = closed.filter((c) => c.budget.tokens !== undefined);\n const tokensSpent = counted.reduce((s, c) => s + c.spent.tokens, 0);\n return {\n velocity,\n meanVelocity: ratio(\n velocity.reduce((s, x) => s + x, 0),\n velocity.length,\n ),\n burndown: state.events\n .filter((e) => e.type === \"daily\")\n .map((e) => (e.payload as { remainingWeight: number }).remainingWeight),\n commitmentReliability: ratio(doneWeight, committedWeight),\n sprintGoalHitRate: ratio(increments.filter((i) => i.goalMet).length, increments.length),\n carryoverRatio: ratio(\n closed.reduce((s, c) => s + c.carryover.length, 0),\n closed.reduce((s, c) => s + c.done.length + c.carryover.length, 0),\n ),\n budgetUtilisation: ratio(\n withTokens.reduce((s, c) => s + c.spent.tokens, 0),\n withTokens.reduce((s, c) => s + (c.budget.tokens ?? 0), 0),\n ),\n costPerPoint: ratio(tokensSpent, doneWeight), // cost per delivered point over completed sprints\n };\n}\n","import type { Role } from \"../types.ts\";\n\nexport function scrumRoles(): Role[] {\n return [\n {\n id: \"product-owner\",\n name: \"Product Owner\",\n modelTier: \"large\",\n capabilities: [\"order-backlog\", \"define-acceptance\", \"escalate\"],\n canApprove: [\"sprint-review\"],\n inputs: [\"stakeholder-needs\", \"product-goal\"],\n outputs: [\"ordered-backlog\", \"acceptance-criteria\"],\n do_not: [\"do not implement items yourself\"],\n },\n {\n id: \"scrum-master\",\n name: \"Scrum Master\",\n modelTier: \"large\",\n capabilities: [\"facilitate\", \"escalate\"],\n canApprove: [],\n inputs: [\"board\", \"blockers\"],\n outputs: [\"ceremony-records\", \"lessons\"],\n do_not: [\"do not reorder the Product Backlog\", \"do not assign work; the planner pulls\"],\n },\n {\n id: \"developer\",\n name: \"Developer\",\n modelTier: \"small\",\n capabilities: [\"deliver\", \"review\", \"verify\"],\n canApprove: [],\n inputs: [\"brief\"],\n outputs: [\"code\", \"test-output\"],\n do_not: [\"do not change acceptance criteria\", \"do not touch items outside your brief\"],\n },\n ];\n}\n","import { openIteration } from \"../planner.ts\";\nimport type { Budget, Iteration, Rule, Violation, WorkflowState } from \"../types.ts\";\nimport type { ItemPatch } from \"../items.ts\";\nimport { canDo, closedSeq } from \"./ceremonies.ts\";\nimport { configOf } from \"./index.ts\";\n\nconst v = (\n rule: string,\n severity: Violation[\"severity\"],\n message: string,\n fix: string,\n item?: string,\n): Violation => (item ? { rule, severity, item, message, fix } : { rule, severity, message, fix });\n\nfunction lastClosed(state: WorkflowState): Iteration | undefined {\n for (let i = state.iterations.length - 1; i >= 0; i--) {\n const it = state.iterations[i]!;\n if (it.endedAt !== undefined) return it;\n }\n return undefined;\n}\nexport function scrumRules(): Rule[] {\n const oneOpen: Rule = {\n id: \"one-open-sprint\",\n severity: \"error\",\n check: (s, a) =>\n a.type === \"ceremony.plan\" && openIteration(s)\n ? [\n v(\n \"one-open-sprint\",\n \"error\",\n `sprint ${openIteration(s)!.id} is still open`,\n \"review or cancel it before planning the next sprint\",\n ),\n ]\n : [],\n };\n\n const retroFirst: Rule = {\n id: \"retro-before-plan\",\n severity: \"error\",\n check: (s, a) => {\n if (a.type !== \"ceremony.plan\") return [];\n const last = lastClosed(s);\n if (!last) return [];\n const seq = closedSeq(s, last.id);\n if (s.events.some((e) => e.type === \"retro\" && e.seq > seq)) return [];\n const sev = last.outcome === \"cancelled\" ? \"warning\" : \"error\";\n return [\n v(\n \"retro-before-plan\",\n sev,\n `sprint ${last.id} has no retrospective yet`,\n \"run the retro ceremony first (lessons may be empty)\",\n ),\n ];\n },\n };\n\n const budgetFixed: Rule = {\n id: \"sprint-budget-fixed\",\n severity: \"error\",\n check: (s, a) => {\n if (a.type !== \"ceremony.plan\") return [];\n const b = (a.payload as { budget?: Budget } | undefined)?.budget;\n if (b === undefined || JSON.stringify(b) === JSON.stringify(configOf(s).sprintBudget))\n return [];\n return [\n v(\n \"sprint-budget-fixed\",\n \"error\",\n \"sprint length is fixed by config.sprintBudget\",\n \"change sprintBudget in the config between sprints instead of per plan\",\n ),\n ];\n },\n };\n\n const scope: Rule = {\n id: \"scope-protects-goal\",\n severity: \"error\",\n check: (s, a) => {\n if (a.type !== \"ceremony.commit\") return [];\n const cfg = configOf(s);\n const p = (a.payload ?? {}) as { goalImpact?: string };\n if (cfg.allowMidSprintAdd === \"never\")\n return [\n v(\n \"scope-protects-goal\",\n \"error\",\n \"mid-sprint additions are disabled\",\n 'set allowMidSprintAdd to \"po-only\" or wait for the next sprint',\n ),\n ];\n if (cfg.allowMidSprintAdd === \"po-only\" && !canDo(s, a.by, \"order-backlog\"))\n return [\n v(\n \"scope-protects-goal\",\n \"error\",\n `\"${a.by}\" may not add work mid-sprint`,\n \"ask the Product Owner (order-backlog) to commit it\",\n ),\n ];\n if (p.goalImpact !== \"none\")\n return [\n v(\n \"scope-protects-goal\",\n \"error\",\n `adding work with goalImpact \"${p.goalImpact ?? \"unset\"}\" endangers the Sprint Goal`,\n 'only commit items with goalImpact: \"none\"; otherwise cancel and re-plan',\n ),\n ];\n return [];\n },\n };\n\n const poOrders: Rule = {\n id: \"po-orders-backlog\",\n severity: \"error\",\n check: (s, a) => {\n if (a.type !== \"ceremony.refine\" || canDo(s, a.by, \"order-backlog\")) return [];\n const items =\n ((a.payload ?? {}) as { items?: Array<{ id: string; patch: ItemPatch }> }).items ?? [];\n return items\n .filter((i) => i.patch.priority !== undefined)\n .map((i) =>\n v(\n \"po-orders-backlog\",\n \"error\",\n `\"${a.by}\" may not change the priority of \"${i.id}\"`,\n \"only the Product Owner orders the backlog; drop priority from the patch\",\n i.id,\n ),\n );\n },\n };\n\n const dod: Rule = {\n id: \"dod-not-weakened\",\n severity: \"error\",\n check: (s, a) =>\n a.type === \"ceremony.retro\" &&\n (a.payload as { dodChanges?: unknown } | undefined)?.dodChanges !== undefined &&\n openIteration(s)\n ? [\n v(\n \"dod-not-weakened\",\n \"error\",\n \"Definition of Done cannot change while a sprint is open\",\n \"close the sprint first; DoD changes apply to the next sprint\",\n ),\n ]\n : [],\n };\n\n const carry: Rule = {\n id: \"carryover-reestimated\",\n severity: \"error\",\n check: (s, a) => {\n if (a.type !== \"ceremony.plan\") return [];\n const items = (a.payload as { items?: string[] | \"auto\" } | undefined)?.items;\n if (!Array.isArray(items)) return [];\n const last = lastClosed(s);\n if (!last) return [];\n const seq = closedSeq(s, last.id);\n return items\n .filter(\n (id) =>\n last.carryover.includes(id) &&\n !s.events.some(\n (e) =>\n e.type === \"item.edited\" &&\n e.seq > seq &&\n (e.payload as { id: string; changed: string[] }).id === id &&\n (e.payload as { changed: string[] }).changed.includes(\"weight\"),\n ),\n )\n .map((id) =>\n v(\n \"carryover-reestimated\",\n \"error\",\n `carried-over item \"${id}\" was not re-estimated after ${last.id}`,\n \"refine it with a new weight before committing\",\n id,\n ),\n );\n },\n };\n\n return [oneOpen, retroFirst, budgetFixed, scope, poOrders, dod, carry];\n}\n","import type { Stage } from \"../types.ts\";\nimport type { ScrumConfig } from \"./config.ts\";\n\nexport function scrumStages(config: ScrumConfig): Stage[] {\n const inProgress: Stage = {\n id: \"in_progress\",\n name: \"In progress\",\n entryPolicy: [{ kind: \"dependencies-done\" }],\n exitPolicy: [],\n };\n if (config.inProgressWipLimit !== undefined) inProgress.wipLimit = config.inProgressWipLimit;\n return [\n {\n id: \"backlog\",\n name: \"Product Backlog\",\n entryPolicy: [],\n exitPolicy: [{ kind: \"acceptance-written\" }, { kind: \"estimate-present\" }],\n },\n { id: \"sprint\", name: \"Sprint Backlog\", entryPolicy: [], exitPolicy: [] },\n inProgress,\n {\n id: \"review\",\n name: \"Review\",\n entryPolicy: [],\n exitPolicy: config.definitionOfDone,\n review: true,\n },\n { id: \"done\", name: \"Increment\", entryPolicy: [], exitPolicy: [] },\n ];\n}\n","import { isExhausted, remaining } from \"../budget.ts\";\nimport { getItem, moveItem, patchItem, stripItemFields } from \"../items.ts\";\nimport { openIteration } from \"../planner.ts\";\nimport { appendEvent } from \"../state.ts\";\nimport type { CoreTerm, Methodology, PlannerOptions, WorkItem, WorkflowState } from \"../types.ts\";\nimport { scrumCeremonies } from \"./ceremonies.ts\";\nimport { validateScrumConfig, type ScrumConfig } from \"./config.ts\";\nimport { scrumMetrics, type ScrumMetrics } from \"./metrics.ts\";\nimport { scrumRoles } from \"./roles.ts\";\nimport { scrumRules } from \"./rules.ts\";\nimport { scrumStages } from \"./stages.ts\";\n\nexport { validateScrumConfig, scrumRoles, scrumRules, scrumStages, scrumMetrics };\nexport type { ScrumMetrics };\nexport type { ScrumConfig };\nexport { scrumCeremonies, dailyReport, canDo } from \"./ceremonies.ts\";\nexport type { DailyReport } from \"./ceremonies.ts\";\n\nexport const SCRUM_VOCABULARY: Record<CoreTerm, string> = {\n backlog: \"Product Backlog\",\n item: \"Product Backlog Item\",\n stage: \"Column\",\n iteration: \"Sprint\",\n increment: \"Increment\",\n ceremony: \"Scrum Event\",\n gate: \"Sprint Review\",\n};\n\n/** Advanced; used by ceremonies. */\nexport function configOf(state: WorkflowState): ScrumConfig {\n return state.config as ScrumConfig;\n}\n\n/** Send an item back to the backlog: clear its open blockers and pending decisions, strip iteration and role. */\nfunction toBacklog(state: WorkflowState, id: string, now: string): WorkflowState {\n let s = state;\n const open = getItem(s, id).blockers.filter((b) => !b.clearedAt);\n if (open.length) {\n s = patchItem(s, id, (it) => ({\n ...it,\n blockers: it.blockers.map((b) => (b.clearedAt ? b : { ...b, clearedAt: now })),\n }));\n for (const b of open)\n s = appendEvent(\n s,\n \"blocker.cleared\",\n \"system\",\n { id, blocker: b.id, reason: \"sprint closed\" },\n now,\n );\n }\n for (const p of s.pending.filter((x) => x.item === id)) {\n s = { ...s, pending: s.pending.filter((x) => x.id !== p.id) };\n s = appendEvent(\n s,\n \"pending.dropped\",\n \"system\",\n { id: p.id, item: id, reason: \"sprint closed\" },\n now,\n );\n }\n const cur = getItem(s, id);\n if (cur.stage !== \"backlog\" || cur.status !== \"todo\")\n s = moveItem(s, id, { stage: \"backlog\", status: \"todo\" }, \"system\", now);\n // a question keeps its role: only the escalation target can answer it\n return stripItemFields(s, id, cur.type === \"question\" ? [\"iteration\"] : [\"iteration\", \"role\"]);\n}\n\n/** Advanced; used by ceremonies. Closes the open sprint and returns unfinished work (and its open questions) to the backlog. */\nexport function closeSprint(\n state: WorkflowState,\n reason: \"budget\" | \"review\" | \"cancel\",\n now: string,\n): WorkflowState {\n const it = openIteration(state);\n if (!it) return state;\n const committed = it.committed.map((id) => getItem(state, id));\n const done = committed.filter((i) => i.status === \"done\").map((i) => i.id);\n const dropped = committed.filter((i) => i.status === \"dropped\").map((i) => i.id);\n const carryover = committed\n .filter((i) => i.status !== \"done\" && i.status !== \"dropped\")\n .map((i) => i.id);\n const carriedQuestions = Object.values(state.items)\n .filter(\n (i) =>\n i.type === \"question\" &&\n i.parent !== undefined &&\n carryover.includes(i.parent) &&\n i.status !== \"done\" &&\n i.status !== \"dropped\",\n )\n .map((i) => i.id);\n let s: WorkflowState = state;\n for (const id of [...carryover, ...carriedQuestions]) s = toBacklog(s, id, now);\n const weightOf = (ids: string[]) =>\n ids.reduce((sum, id) => sum + (state.items[id]?.weight ?? 0), 0);\n s = {\n ...s,\n iterations: s.iterations.map((x) => {\n if (x.id !== it.id) return x;\n const { closing: _c, ...rest } = x;\n return {\n ...rest,\n endedAt: now,\n outcome: reason === \"cancel\" ? \"cancelled\" : \"completed\",\n carryover,\n };\n }),\n };\n return appendEvent(\n s,\n \"sprint.closed\",\n \"system\",\n {\n id: it.id,\n reason,\n done,\n carryover,\n carriedQuestions,\n dropped,\n doneWeight: weightOf(done),\n committedWeight: weightOf(it.committed),\n spent: it.spent,\n budget: it.budget,\n },\n now,\n );\n}\n\nexport function scrum(): Methodology<ScrumConfig> {\n return {\n name: \"scrum\",\n vocabulary: SCRUM_VOCABULARY,\n validateConfig: validateScrumConfig,\n defaultStages: scrumStages,\n defaultRoles: scrumRoles,\n requiredCapabilities: [\"order-backlog\", \"facilitate\", \"deliver\"],\n exclusiveCapabilities: [\"order-backlog\"],\n plannerOptions(state): PlannerOptions {\n const cap = configOf(state).inProgressWipLimit;\n return cap === undefined\n ? { schedulerMode: \"level\", dispatchStage: \"in_progress\" }\n : { schedulerMode: \"level\", dispatchStage: \"in_progress\", concurrencyCap: cap };\n },\n candidates(state): WorkItem[] {\n const it = openIteration(state);\n if (!it || it.closing) return [];\n return Object.values(state.items).filter(\n (i) =>\n i.iteration === it.id &&\n (i.status === \"todo\" || i.status === \"review\") &&\n (i.stage === \"sprint\" || i.stage === \"review\"),\n );\n },\n invariants(state, item): string[] {\n const it = openIteration(state);\n const cfg = configOf(state);\n const left = it ? remaining(it.budget, it.spent) : {};\n return [\n `Sprint Goal: ${it?.goal ?? \"(no open sprint)\"}; Product Goal: ${cfg.productGoal}`,\n `Budget remaining: ${JSON.stringify(left)}; stop and hand off when it is gone`,\n `Definition of Done: ${cfg.definitionOfDone.map((p) => (p.kind === \"evidence\" ? `evidence ${p.evidenceKind}` : p.kind)).join(\", \") || \"(none)\"}`,\n `Do not change the scope of \"${item.id}\" or its acceptance criteria; raise open_questions instead`,\n ];\n },\n ceremonies: scrumCeremonies(scrum),\n rules: scrumRules(),\n metrics: (state) => ({ ...scrumMetrics(state) }),\n humanDefaults: { gates: [\"sprint-review\"] },\n afterComplete(state, _itemId, now) {\n const it = openIteration(state);\n if (!it || (!it.closing && !isExhausted(it.budget, it.spent))) return state;\n const inFlight = Object.values(state.items).some(\n (i) => i.iteration === it.id && i.status === \"in_progress\",\n );\n if (!inFlight) return closeSprint(state, \"budget\", now);\n if (it.closing) return state;\n return appendEvent(\n {\n ...state,\n iterations: state.iterations.map((x) => (x.id === it.id ? { ...x, closing: true } : x)),\n },\n \"sprint.closing\",\n \"system\",\n { id: it.id },\n now,\n );\n },\n };\n}\n"]}
@@ -0,0 +1,6 @@
1
+ 'use strict';var chunkS3BXVHO7_cjs=require('./chunk-S3BXVHO7.cjs'),promises=require('fs/promises'),crypto=require('crypto'),n=require('path');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var n__default=/*#__PURE__*/_interopDefault(n);var c=".workflow";function y(t){return n__default.default.join(t,c,"state.json")}async function g(t,e){let i=`${t}.tmp-${process.pid}-${crypto.randomBytes(4).toString("hex")}`;try{await promises.mkdir(n__default.default.dirname(t),{recursive:!0}),await promises.writeFile(i,e,"utf8"),await promises.rename(i,t);}catch(r){await promises.unlink(i).catch(()=>{}),chunkS3BXVHO7_cjs.b("invalid-input",`cannot write ${t}: ${r.message}`,"check the directory exists and is writable");}}async function E(t,e,i={}){let{retries:r=40,intervalMs:d=50,staleMs:m=6e4}=i,a=n__default.default.join(t,c,"state.lock");await promises.mkdir(n__default.default.dirname(a),{recursive:true});let u=false;for(let f=0;!u;f++)try{let s=await promises.open(a,"wx");await s.writeFile(`${process.pid} ${new Date().toISOString()}
2
+ `),await s.close(),u=!0;}catch(s){if(s.code!=="EEXIST")throw s;if(await promises.stat(a).then(w=>Date.now()-w.mtimeMs,()=>0)>m){await promises.unlink(a).catch(()=>{});continue}f>=r&&chunkS3BXVHO7_cjs.b("invalid-input","another exwf command holds .workflow/state.lock","retry, or delete the file if no exwf process is running"),await new Promise(w=>setTimeout(w,d));}try{return await e()}finally{await promises.unlink(a).catch(()=>{});}}async function D(t,e){await g(y(t),JSON.stringify(e,null,2)+`
3
+ `);}async function M(t){let e=y(t),i;try{i=await promises.readFile(e,"utf8");}catch{chunkS3BXVHO7_cjs.b("invalid-input",`no workflow state at ${e}`,"run `exwf init <scrum|kanban|waterfall> --config <file>` in this directory first");}let r;try{r=JSON.parse(i);}catch(f){chunkS3BXVHO7_cjs.b("invalid-input",`${e} is not valid JSON: ${f.message}`,"restore it from git or re-run exwf init");}(typeof r!="object"||r===null||Array.isArray(r))&&chunkS3BXVHO7_cjs.b("invalid-input",`${e} does not contain a workflow state object`,"restore it from git or re-run exwf init");let d=r;d.version!==1&&chunkS3BXVHO7_cjs.b("state-version",`${e} has schema version ${String(d.version)}; this ex-workflow reads version 1`,"upgrade ex-workflow, or run the migration this version documents in its changelog");let m=n__default.default.join(t,c,"roles"),a=[];try{a=(await promises.readdir(m)).filter(f=>f.endsWith(".json"));}catch{}let u={...d.roles};for(let f of a){let s=n__default.default.join(m,f),l;try{l=JSON.parse(await promises.readFile(s,"utf8"));}catch(w){chunkS3BXVHO7_cjs.b("invalid-input",`role manifest ${s} is not valid JSON: ${w.message}`,"fix or delete that manifest");}(typeof l!="object"||l===null||typeof l.id!="string")&&chunkS3BXVHO7_cjs.b("invalid-input",`role manifest ${s} is not an object with a string id`,"a role manifest needs at least an id"),u[l.id]||(u[l.id]=l);}return {...d,roles:u}}function k(t,e){return n__default.default.resolve(e).startsWith(n__default.default.resolve(t,c)+n__default.default.sep)||chunkS3BXVHO7_cjs.b("invalid-input",`${e} resolves outside ${c}/`,"use a plain item id (letters, digits, - _ .)"),e}async function R(t,e){let i=k(t,n__default.default.join(t,c,"briefs",`${e.item.id}.json`));return await g(i,JSON.stringify(e,null,2)+`
4
+ `),i}async function T(t,e,i){let r=k(t,n__default.default.join(t,c,"handoffs",`${e.item}-${i}.json`));return await g(r,JSON.stringify(e,null,2)+`
5
+ `),r}exports.a=c;exports.b=y;exports.c=E;exports.d=D;exports.e=M;exports.f=R;exports.g=T;//# sourceMappingURL=chunk-6R3YFUUV.cjs.map
6
+ //# sourceMappingURL=chunk-6R3YFUUV.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/file.ts"],"names":["WORKFLOW_DIR","statePath","root","path","writeAtomic","file","content","tmp","randomBytes","mkdir","writeFile","rename","e","unlink","fail","withStateLock","fn","opts","retries","intervalMs","staleMs","lock","held","attempt","fh","open","stat","st","resolve","saveState","state","loadState","raw","readFile","parsed","rolesDir","manifests","readdir","roles","manifestPath","role","inWorkflowDir","saveBrief","brief","saveHandoff","handoff","seq"],"mappings":"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","file":"chunk-6R3YFUUV.cjs","sourcesContent":["import { mkdir, open, readFile, readdir, rename, stat, unlink, writeFile } from \"node:fs/promises\";\nimport { randomBytes } from \"node:crypto\";\nimport path from \"node:path\";\nimport { fail } from \"../errors.ts\";\nimport type { Brief, Handoff, Role, WorkflowState } from \"../types.ts\";\n\nexport const WORKFLOW_DIR = \".workflow\";\n\nexport function statePath(root: string): string {\n return path.join(root, WORKFLOW_DIR, \"state.json\");\n}\n\nasync function writeAtomic(file: string, content: string): Promise<void> {\n const tmp = `${file}.tmp-${process.pid}-${randomBytes(4).toString(\"hex\")}`;\n try {\n await mkdir(path.dirname(file), { recursive: true });\n await writeFile(tmp, content, \"utf8\");\n await rename(tmp, file);\n } catch (e) {\n // best effort: remove the temp file if it was created; ignore failure\n await unlink(tmp).catch(() => undefined);\n fail(\n \"invalid-input\",\n `cannot write ${file}: ${(e as Error).message}`,\n \"check the directory exists and is writable\",\n );\n }\n}\n\nexport interface LockOptions {\n retries?: number;\n intervalMs?: number;\n staleMs?: number;\n}\n\n/** Run `fn` while holding `.workflow/state.lock`, so concurrent exwf commands cannot lose each other's updates. */\nexport async function withStateLock<T>(\n root: string,\n fn: () => Promise<T>,\n opts: LockOptions = {},\n): Promise<T> {\n const { retries = 40, intervalMs = 50, staleMs = 60_000 } = opts;\n const lock = path.join(root, WORKFLOW_DIR, \"state.lock\");\n await mkdir(path.dirname(lock), { recursive: true });\n let held = false;\n for (let attempt = 0; !held; attempt++) {\n try {\n const fh = await open(lock, \"wx\");\n await fh.writeFile(`${process.pid} ${new Date().toISOString()}\\n`);\n await fh.close();\n held = true;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== \"EEXIST\") throw e;\n const age = await stat(lock).then(\n (st) => Date.now() - st.mtimeMs,\n () => 0,\n );\n if (age > staleMs) {\n await unlink(lock).catch(() => undefined);\n continue;\n }\n if (attempt >= retries)\n fail(\n \"invalid-input\",\n \"another exwf command holds .workflow/state.lock\",\n \"retry, or delete the file if no exwf process is running\",\n );\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n try {\n return await fn();\n } finally {\n await unlink(lock).catch(() => undefined);\n }\n}\n\nexport async function saveState(root: string, state: WorkflowState): Promise<void> {\n await writeAtomic(statePath(root), JSON.stringify(state, null, 2) + \"\\n\");\n}\n\nexport async function loadState(root: string): Promise<WorkflowState> {\n const file = statePath(root);\n let raw: string;\n try {\n raw = await readFile(file, \"utf8\");\n } catch {\n fail(\n \"invalid-input\",\n `no workflow state at ${file}`,\n \"run `exwf init <scrum|kanban|waterfall> --config <file>` in this directory first\",\n );\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n fail(\n \"invalid-input\",\n `${file} is not valid JSON: ${(e as Error).message}`,\n \"restore it from git or re-run exwf init\",\n );\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n fail(\n \"invalid-input\",\n `${file} does not contain a workflow state object`,\n \"restore it from git or re-run exwf init\",\n );\n }\n const state = parsed as WorkflowState;\n if (state.version !== 1)\n fail(\n \"state-version\",\n `${file} has schema version ${String(state.version)}; this ex-workflow reads version 1`,\n \"upgrade ex-workflow, or run the migration this version documents in its changelog\",\n );\n const rolesDir = path.join(root, WORKFLOW_DIR, \"roles\");\n let manifests: string[] = [];\n try {\n manifests = (await readdir(rolesDir)).filter((f) => f.endsWith(\".json\"));\n } catch {\n /* no extra roles */\n }\n const roles = { ...state.roles };\n for (const f of manifests) {\n const manifestPath = path.join(rolesDir, f);\n let role: Role;\n try {\n role = JSON.parse(await readFile(manifestPath, \"utf8\")) as Role;\n } catch (e) {\n fail(\n \"invalid-input\",\n `role manifest ${manifestPath} is not valid JSON: ${(e as Error).message}`,\n \"fix or delete that manifest\",\n );\n }\n if (typeof role !== \"object\" || role === null || typeof role.id !== \"string\") {\n fail(\n \"invalid-input\",\n `role manifest ${manifestPath} is not an object with a string id`,\n \"a role manifest needs at least an id\",\n );\n }\n if (!roles[role.id]) roles[role.id] = role;\n }\n return { ...state, roles };\n}\n\nfunction inWorkflowDir(root: string, file: string): string {\n if (!path.resolve(file).startsWith(path.resolve(root, WORKFLOW_DIR) + path.sep))\n fail(\n \"invalid-input\",\n `${file} resolves outside ${WORKFLOW_DIR}/`,\n \"use a plain item id (letters, digits, - _ .)\",\n );\n return file;\n}\n\nexport async function saveBrief(root: string, brief: Brief): Promise<string> {\n const file = inWorkflowDir(\n root,\n path.join(root, WORKFLOW_DIR, \"briefs\", `${brief.item.id}.json`),\n );\n await writeAtomic(file, JSON.stringify(brief, null, 2) + \"\\n\");\n return file;\n}\n\nexport async function saveHandoff(root: string, handoff: Handoff, seq: number): Promise<string> {\n const file = inWorkflowDir(\n root,\n path.join(root, WORKFLOW_DIR, \"handoffs\", `${handoff.item}-${seq}.json`),\n );\n await writeAtomic(file, JSON.stringify(handoff, null, 2) + \"\\n\");\n return file;\n}\n"]}