github-delivery-os 1.2.1 → 1.2.2

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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
package/README.md CHANGED
@@ -63,15 +63,15 @@ npx github-delivery-os uninstall --dry-run . # Preview (no changes)
63
63
 
64
64
  **What gets installed:**
65
65
 
66
- | Workflow | Purpose |
67
- |----------|---------|
68
- | `sprint-child-creator` | Creates child issues when a sprint (title `SPRINT -`) is opened |
69
- | `auto-close-sprint` | Burn-down, sprint health, auto-close at 100% |
70
- | `notify-release-approver` | Pings approver when production release issue opens |
71
- | `authorize-deployment` | Dual approval (release approver + QA) |
72
- | `auto-assign-qa` | Assigns QA team to `qa` / `qa-request` issues |
73
- | `telegram-issues` | Telegram alerts for bugs, QA, sprints, releases |
74
- | `setup-labels` | One-time workflow to create required labels |
66
+ | Workflow | Trigger | Purpose |
67
+ |----------|---------|---------|
68
+ | `sprint-child-creator` | Issue opened, title contains `SPRINT -` | Parses "Sprint Features (One Per Line)" and creates one child issue per line, each linked back with `Parent Sprint: #N` |
69
+ | `auto-close-sprint` | Issue closed, body contains `Parent Sprint` | Recomputes the parent sprint's burn-down/health and rewrites its status section; auto-closes the sprint at 100% |
70
+ | `notify-release-approver` | Issue opened, labeled `production` | Comments on the issue tagging the repo's `RELEASE_APPROVER` |
71
+ | `authorize-deployment` | Comment posted on a `production`-labeled issue | Checks the commenter and keyword against `RELEASE_APPROVER`/`QA_APPROVER`; once both approve, adds `ready-for-deploy` |
72
+ | `auto-assign-qa` | Issue opened/labeled `qa` or `qa-request` | Assigns the repo's configured `QA_ASSIGNEES` |
73
+ | `telegram-issues` | Issue/comment/PR events | Sends a Telegram alert if `TELEGRAM_BOT_TOKEN`/`TELEGRAM_CHAT_ID` are configured |
74
+ | `setup-labels` | Manual (`workflow_dispatch`) | One-time run that creates all labels Delivery OS needs |
75
75
 
76
76
  Workflows and templates are **copied directly** into your repo. No `workflow_call` or external references.
77
77
 
@@ -104,6 +104,230 @@ When you open an issue using the **Sprint Planning** template with a title like
104
104
 
105
105
  ---
106
106
 
107
+ ## Operating From Claude Code (`--with-skill`)
108
+
109
+ Installing with `--with-skill` drops a `.claude/skills/delivery-ops/SKILL.md` skill into the repo, scoped to *this* repo's Delivery OS install. It lets anyone using [Claude Code](https://claude.com/claude-code) drive the workflows above by asking in plain language — e.g. "create a sprint for the checkout redesign" — instead of hand-building `gh issue create` calls and remembering each template's exact field names.
110
+
111
+ Before doing anything, it checks the target repo: confirms Delivery OS is actually installed, that `Setup Labels` has been run, and that `RELEASE_APPROVER` / `QA_APPROVER` / `QA_ASSIGNEES` are configured — flagging (or offering to fix) gaps instead of silently creating an issue that does nothing. It also always shows the constructed title/body/labels or comment text for confirmation before creating or posting for real, since these are visible actions in the repo's activity, not a local preview.
112
+
113
+ ### Create a sprint
114
+ 1. Ask: *"Create a sprint called Sprint 14 for \<goal>, running \<start> to \<end>, with features: \<one per line>"*
115
+ 2. It opens an issue titled `SPRINT - Sprint 14`, labeled `sprint` + `planning`, with `### Sprint Name` / `Start` / `End` / `Goal` / `Features (One Per Line)` / `Approved` fields filled in.
116
+ 3. On open, `sprint-child-creator` splits each feature line into its own child issue, labeled `sprint-active` and linked back with `Parent Sprint: #N`.
117
+ 4. Close each child issue as work finishes — that's what advances the burn-down; `auto-close-sprint` recomputes it and rewrites the parent's `## 🚦 Sprint Status` section, auto-closing the sprint at 100%.
118
+
119
+ ### Request a production release
120
+ 1. Ask: *"Open a production release for \<project> v1.2.0, sprint #N, summary: \<summary>"*
121
+ 2. It opens an issue titled `PRODUCTION RELEASE - <project> - v1.2.0`, labeled `release` + `production` + `approval`, with the sprint reference, version, release summary, QA summary/links, and `Deployment Authorized: No`.
122
+ 3. On open, `notify-release-approver` comments tagging the repo's configured `RELEASE_APPROVER`.
123
+
124
+ ### Approve or decline a release
125
+ 1. Ask: *"Approve release #N"* or *"Decline release #N — \<reason>"*.
126
+ 2. It checks that the currently authenticated `gh` login matches the repo's `RELEASE_APPROVER` — if not, it stops and says so instead of posting a comment that would silently do nothing.
127
+ 3. It posts a comment starting with a recognized keyword (`approved`, `ok`, `go ahead` to approve; `declined`, `rejected`, `not approved` to decline) — `authorize-deployment` only reacts to that leading keyword from the exact configured approver. A later comment from the same approver overrides an earlier one.
128
+
129
+ ### Request QA
130
+ 1. Ask: *"Open a QA request for \<feature>, related to issue #N, testing \<what/where>"*
131
+ 2. It opens an issue titled `QA REQUEST - <feature>`, labeled `qa-request`, with the related task, what to test, environment/build link, and acceptance criteria.
132
+ 3. On open, `auto-assign-qa` assigns the repo's configured `QA_ASSIGNEES`.
133
+
134
+ ### Approve QA
135
+ 1. Ask: *"Mark QA #N as approved"* (or *"looks good"*).
136
+ 2. Same login check as release approval, but against `QA_APPROVER`.
137
+ 3. Posts a comment starting with `qa approved`, `approved`, `qa ok`, or `looks good`.
138
+
139
+ ### Report a bug
140
+ 1. Ask: *"File a bug: \<one-line summary>, severity \<level>, steps: \<...>"*
141
+ 2. It opens an issue titled `[BUG] <summary>`, labeled `bug` + `qa`, with platform, severity, build/version, steps to reproduce, expected vs. actual result, and test environment.
142
+
143
+ ### Track a task
144
+ 1. Ask: *"Create a task to \<summary>, owner \<name>, priority P1"*
145
+ 2. It opens an issue titled `TASK - <summary>`, labeled `task`, with owner, priority, status, acceptance criteria, and links. (No workflow trigger — this is plain tracking.)
146
+
147
+ ### Check status
148
+ - *"What's the status of issue #N?"* → current labels and latest comments.
149
+ - *"How's Sprint 14 doing?"* → reads the parent issue's `## 🚦 Sprint Status` section (progress %, time elapsed, health, burn-down bar).
150
+ - *"What releases are waiting on approval?"* / *"What sprints are active?"* / *"What QA requests are open?"* → lists issues by label (`production`, `sprint`, `qa-request`) so you don't need an issue number in hand.
151
+
152
+ See [How To](docs/how-to.md) for the underlying workflows this drives, field by field.
153
+
154
+ ### Example: filing a bug and a task, step by step
155
+
156
+ Worked against `jkaweesi22/klero`, a repo with Delivery OS installed. The bug part of this was actually run — that issue really exists at [jkaweesi22/klero#1](https://github.com/jkaweesi22/klero/issues/1); the task part follows the identical steps but wasn't actually created, shown for the field shape only.
157
+
158
+ **Filing the bug:**
159
+
160
+ 1. In Claude Code, inside (or pointed at, via `--repo`) the target repo, describe the bug in plain language:
161
+ > *File a bug on jkaweesi22/klero — the order request form submits with an empty phone number, severity high. Steps: fill in the form, leave phone blank, submit. Expected: should block submission. Actual: submits anyway, so there's no way to contact the customer. Tested on Chrome, desktop, production.*
162
+ 2. Claude pre-flights the repo — confirms Delivery OS is installed and the `bug`/`qa` labels exist.
163
+ 3. Claude shows the exact issue it's about to create before doing anything:
164
+ - Title: `[BUG] Order request form submits with empty phone number`
165
+ - Labels: `bug`, `qa`
166
+ - Body, field by field: `Platform(s) Affected` → Web, `Severity` → High, `Build / Version` → main (as deployed), `Bug Summary`, `Steps to Reproduce` (numbered), `Expected Result`, `Actual Result`, `Test Environment` → Chrome, desktop, production.
167
+ 4. Confirm ("yes") when asked to create it.
168
+ 5. Claude runs `gh issue create` and reports back the issue — [jkaweesi22/klero#1](https://github.com/jkaweesi22/klero/issues/1). Nothing else happens automatically; bug reports don't trigger a workflow, they're just labeled and tracked.
169
+
170
+ **Filing the follow-up task:**
171
+
172
+ 1. Ask Claude to turn the bug into tracked work, referencing the bug's issue number:
173
+ > *Create a task to add phone number validation to the order form, owner @jkaweesi22, priority P1, status Backlog, acceptance: form blocks submission until a valid phone number is entered. Link it to #1.*
174
+ 2. Claude shows the constructed issue:
175
+ - Title: `TASK - Add phone number validation to order form`
176
+ - Labels: `task`
177
+ - Body: `Task Summary`, `Description` (references #1), `Owner` → @jkaweesi22, `Priority` → P1 - High, `Status` → Backlog, `Acceptance Criteria`, `Artifacts / Links` → Related bug: #1.
178
+ 3. Confirm ("yes") to create it.
179
+ 4. Claude runs `gh issue create`. Same as the bug — no workflow trigger, just labeled and tracked, now linked back to the bug it addresses.
180
+
181
+ ### Full example: shipping a feature end-to-end
182
+
183
+ A realistic Claude Code session, run from inside the consumer repo (the skill defaults to it since it was installed with `--with-skill` there). `RELEASE_APPROVER`, `QA_APPROVER`, and `QA_ASSIGNEES` are already configured.
184
+
185
+ ```
186
+ You: Create a sprint called "Sprint 14 - Checkout Revamp", running 2026-09-16 to
187
+ 2026-09-30, goal is shipping the new checkout flow, features:
188
+ - Redesign cart summary
189
+ - Add saved payment methods
190
+ - Fix tax rounding bug
191
+
192
+ Claude: This will create an issue in acme/storefront:
193
+
194
+ Title: SPRINT - Sprint 14 - Checkout Revamp
195
+ Labels: sprint, planning
196
+ Body:
197
+ ### Sprint Name
198
+ Sprint 14 - Checkout Revamp
199
+ ### Sprint Start
200
+ 2026-09-16
201
+ ### Sprint End
202
+ 2026-09-30
203
+ ### Sprint Goal
204
+ Ship the new checkout flow
205
+ ### Sprint Features (One Per Line)
206
+ Redesign cart summary
207
+ Add saved payment methods
208
+ Fix tax rounding bug
209
+ ### Sprint Approved
210
+ Pending
211
+
212
+ Create this issue?
213
+
214
+ You: yes
215
+
216
+ Claude: Created #52. sprint-child-creator will fire on open and create one child
217
+ issue per feature — #53 "Redesign cart summary", #54 "Add saved payment
218
+ methods", #55 "Fix tax rounding bug" — each labeled sprint-active and
219
+ linked back with "Parent Sprint: #52".
220
+
221
+ [ ... engineers do the work, close #53 and #54 as they land ... ]
222
+
223
+ You: How's Sprint 14 doing?
224
+
225
+ Claude: Reading #52... ## 🚦 Sprint Status: 67% complete (2/3 closed), 20% of
226
+ sprint time elapsed, 🟢 on track.
227
+
228
+ You: QA found a rounding issue in the tax calc — file a bug. Severity high,
229
+ repros on checkout with 3+ items, expected total matches line items,
230
+ actual is off by $0.01.
231
+
232
+ Claude: This will create an issue in acme/storefront:
233
+
234
+ Title: [BUG] Tax rounding off by $0.01 with 3+ items
235
+ Labels: bug, qa
236
+ Body: (Platform, Severity: High, Steps to Reproduce, Expected vs.
237
+ Actual Result, Test Environment filled in from what you said)
238
+
239
+ Create this issue?
240
+
241
+ You: yes
242
+
243
+ Claude: Created #56.
244
+
245
+ [ ... #55 fixed, referencing #56 ... ]
246
+
247
+ You: Open a QA request for the tax rounding fix, related to #55, test on
248
+ staging, acceptance: totals match to the cent for carts of 1-10 items.
249
+
250
+ Claude: This will create an issue in acme/storefront:
251
+
252
+ Title: QA REQUEST - Tax rounding fix
253
+ Labels: qa-request
254
+ Body: (Related Sprint Task Issue #55, What to Test, Environment +
255
+ Build Link: staging, Acceptance Criteria filled in)
256
+
257
+ Create this issue?
258
+
259
+ You: yes
260
+
261
+ Claude: Created #57. auto-assign-qa will assign it to the configured
262
+ QA_ASSIGNEES.
263
+
264
+ [ ... QA tests it, comes back clean ... ]
265
+
266
+ You: Mark QA #57 as approved, looks good.
267
+
268
+ Claude: Checking gh auth status... authenticated as jane-qa, which matches this
269
+ repo's QA_APPROVER. Posting:
270
+
271
+ "looks good — verified on staging, totals match to the cent"
272
+
273
+ on #57.
274
+
275
+ You: yes, post it
276
+
277
+ Claude: Posted. Now close #55 to update the sprint burn-down?
278
+
279
+ You: yes
280
+
281
+ Claude: Closed #55. Sprint 14 is now 100% complete — auto-close-sprint closed
282
+ #52 and posted a completion comment.
283
+
284
+ You: Open a production release for storefront v2.4.1, sprint #52, summary
285
+ "checkout revamp: new cart summary, saved payment methods, tax rounding
286
+ fix", QA evidence: #57.
287
+
288
+ Claude: This will create an issue in acme/storefront:
289
+
290
+ Title: PRODUCTION RELEASE - storefront - v2.4.1
291
+ Labels: release, production, approval
292
+ Body:
293
+ ### Sprint Reference (Sprint Planning Issue #)
294
+ #52
295
+ ### Version / Build Number
296
+ v2.4.1
297
+ ### Release Summary
298
+ Checkout revamp: new cart summary, saved payment methods, tax
299
+ rounding fix
300
+ ### QA Summary + Evidence Links
301
+ #57
302
+ ### Overall QA Recommendation
303
+ Approve for Production
304
+ ### Deployment Authorized
305
+ No
306
+
307
+ Create this issue?
308
+
309
+ You: yes
310
+
311
+ Claude: Created #58. notify-release-approver posted a comment tagging this
312
+ repo's RELEASE_APPROVER (john-lead).
313
+
314
+ [ ... some time later, as john-lead ... ]
315
+
316
+ You: Approve release #58.
317
+
318
+ Claude: Checking gh auth status... authenticated as john-lead, which matches
319
+ RELEASE_APPROVER. Posting "approved" on #58.
320
+
321
+ You: yes
322
+
323
+ Claude: Posted. authorize-deployment will add ready-for-deploy once both
324
+ approvers (release + QA) have a qualifying comment on record.
325
+ ```
326
+
327
+ Each `yes` above is a real confirmation gate — Claude shows the exact issue/comment content before it creates or posts anything, since it's a visible action in the repo.
328
+
329
+ ---
330
+
107
331
  ## Documentation
108
332
 
109
333
  | Document | Description |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-delivery-os",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "A GitHub-native Delivery Governance Framework for structured sprint execution, QA review, and collaborative production release control.",
5
5
  "main": "src/install.js",
6
6
  "bin": {
@@ -48,6 +48,7 @@
48
48
  ".github/scripts/authorize-deployment-verdict.js",
49
49
  ".github/scripts/auto-close-sprint.js",
50
50
  ".github/scripts/sprint-child-creator.js",
51
+ ".github/scripts/package.json",
51
52
  ".github/ISSUE_TEMPLATE",
52
53
  ".claude/skills/delivery-ops"
53
54
  ],
package/src/install.js CHANGED
@@ -27,6 +27,17 @@ const WORKFLOWS = [
27
27
  // them explicitly in package.json's "files".
28
28
  const SCRIPTS = ['authorize-deployment-verdict', 'auto-close-sprint', 'sprint-child-creator'];
29
29
 
30
+ // These scripts are CommonJS (`require`/`module.exports`). Node picks CJS vs.
31
+ // ESM per-file by walking up to the nearest package.json — so a consumer repo
32
+ // whose own root package.json has `"type": "module"` would otherwise make
33
+ // Node treat these .js files as ES modules too, breaking `require()` at
34
+ // runtime with "ReferenceError: module is not defined in ES module scope".
35
+ // This override pins the .github/scripts subtree to CommonJS regardless of
36
+ // the consumer's own type field. Always installed alongside SCRIPTS, same as
37
+ // SCRIPTS is alongside WORKFLOWS — not itself require()'d by anything, but a
38
+ // required dependency of every script that is.
39
+ const SCRIPTS_PACKAGE_JSON = 'package.json';
40
+
30
41
  // Which workflow requires which script, so `status` can flag a workflow
31
42
  // that's present but whose required script is missing (an install that will
32
43
  // fail with MODULE_NOT_FOUND the next time that workflow actually runs).
@@ -240,6 +251,21 @@ function runInstall(options) {
240
251
  { overwrite, dryRun, relDir: '.github/scripts' }
241
252
  ));
242
253
 
254
+ // The CommonJS-pinning package.json (see SCRIPTS_PACKAGE_JSON above) —
255
+ // always installed alongside SCRIPTS, via the same helper, counted the
256
+ // same way (mirrors how scripts/install.sh reuses copy_managed_files for
257
+ // this exact file rather than hand-rolling the copy).
258
+ const { name: scriptsPkgName, ext: scriptsPkgExt } = path.parse(SCRIPTS_PACKAGE_JSON);
259
+ const scriptsPkgResult = copyManagedFiles(
260
+ [scriptsPkgName],
261
+ scriptsPkgExt,
262
+ scriptsSrc,
263
+ scriptsDest,
264
+ { overwrite, dryRun, relDir: '.github/scripts' }
265
+ );
266
+ scriptsCopied += scriptsPkgResult.copied;
267
+ scriptsSkipped += scriptsPkgResult.skipped;
268
+
243
269
  let templatesSkipped = 0;
244
270
  let skillSkipped = 0;
245
271
 
@@ -472,6 +498,19 @@ async function runStatus(options) {
472
498
  return !fs.existsSync(path.join(targetAbs, '.github', 'scripts', `${requiredScript}.js`));
473
499
  });
474
500
 
501
+ // A script can be present while the CommonJS-pinning package.json (see
502
+ // SCRIPTS_PACKAGE_JSON in src/install.js) is missing — e.g. an install from
503
+ // before this fix existed. That's fine in a repo whose own package.json
504
+ // has no "type" field or "type": "commonjs", but breaks with
505
+ // "ReferenceError: module is not defined in ES module scope" the moment
506
+ // the consumer repo's package.json has "type": "module". Flagged
507
+ // separately from brokenWorkflows since it's silent until that condition
508
+ // is hit, not an immediate break.
509
+ const scriptsRequiringPkgJson = installedWorkflows.some((wf) => REQUIRED_SCRIPT_BY_WORKFLOW[wf]);
510
+ const scriptsPkgJsonMissing =
511
+ scriptsRequiringPkgJson &&
512
+ !fs.existsSync(path.join(targetAbs, '.github', 'scripts', SCRIPTS_PACKAGE_JSON));
513
+
475
514
  if (installedWorkflows.length > 0 || installedTemplates.length > 0 || skillInstalled) {
476
515
  const manifest = readManifest(targetAbs);
477
516
  if (manifest && manifest.version) {
@@ -514,6 +553,15 @@ async function runStatus(options) {
514
553
  console.log('');
515
554
  }
516
555
 
556
+ if (scriptsPkgJsonMissing) {
557
+ console.log(`⚠️ .github/scripts/${SCRIPTS_PACKAGE_JSON} is missing.`);
558
+ console.log(' If this repo\'s own package.json has "type": "module", every workflow that');
559
+ console.log(' require()s a script under .github/scripts will fail with "module is not');
560
+ console.log(' defined in ES module scope" the next time it runs.');
561
+ console.log(' Fix: npx github-delivery-os@latest install --overwrite .');
562
+ console.log('');
563
+ }
564
+
517
565
  if (installedTemplates.length > 0) {
518
566
  console.log('Templates:');
519
567
  installedTemplates.forEach((t) => console.log(` ✓ ${t}`));
@@ -592,6 +640,19 @@ function runUninstall(options) {
592
640
  }
593
641
  }
594
642
 
643
+ // The CommonJS-pinning package.json travels with SCRIPTS — same
644
+ // unconditional removal.
645
+ const scriptsPkgDest = path.join(scriptsDest, SCRIPTS_PACKAGE_JSON);
646
+ if (fs.existsSync(scriptsPkgDest)) {
647
+ if (dryRun) {
648
+ console.log(` [dry-run] Would remove: .github/scripts/${SCRIPTS_PACKAGE_JSON}`);
649
+ } else {
650
+ fs.unlinkSync(scriptsPkgDest);
651
+ console.log(` Removed: .github/scripts/${SCRIPTS_PACKAGE_JSON}`);
652
+ }
653
+ scriptsRemoved++;
654
+ }
655
+
595
656
  if (withTemplates) {
596
657
  for (const t of TEMPLATES) {
597
658
  const dest = path.join(templatesDest, t);
@@ -634,7 +695,9 @@ function runUninstall(options) {
634
695
  // reason the other three are checked explicitly rather than assumed:
635
696
  // defensive completeness against a future change (e.g. a failed unlink,
636
697
  // or script removal ever becoming flag-gated like templates/skill).
637
- const anyScriptsRemain = SCRIPTS.some((name) => fs.existsSync(path.join(scriptsDest, `${name}.js`)));
698
+ const anyScriptsRemain =
699
+ SCRIPTS.some((name) => fs.existsSync(path.join(scriptsDest, `${name}.js`))) ||
700
+ fs.existsSync(path.join(scriptsDest, SCRIPTS_PACKAGE_JSON));
638
701
  const skillRemains = fs.existsSync(skillPath(targetAbs));
639
702
  const nothingLeft = !anyWorkflowsRemain && !anyTemplatesRemain && !anyScriptsRemain && !skillRemains;
640
703
 
@@ -688,6 +751,7 @@ module.exports = {
688
751
  WORKFLOWS,
689
752
  TEMPLATES,
690
753
  SCRIPTS,
754
+ SCRIPTS_PACKAGE_JSON,
691
755
  REQUIRED_SCRIPT_BY_WORKFLOW,
692
756
  },
693
757
  };