bmad-dashboard 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -159,9 +159,9 @@ On every **push to `main`**, GitHub Actions:
159
159
  1. Runs tests and build in the `dashboard/` directory.
160
160
  2. If tests pass, bumps the **patch** version (e.g. `1.0.9` → `1.0.10`), publishes to npm via **Trusted Publishers (OIDC)**, and commits the version bump back to `main` (with message `chore(release): 1.0.10 [skip ci]` so the release commit does not trigger another publish).
161
161
 
162
- **Setup (one-time):** Use [npm Trusted Publishers](https://docs.npmjs.com/trusted-publishers). Your **npm account must be linked to your GitHub account** (npm profile/Account link GitHub). Then on [npmjs.com](https://www.npmjs.com/) go to **Packages** → **bmad-dashboard** → **Settings** **Trusted publishing**, choose **GitHub Actions**, set **Workflow filename** to `release.yml`, and save. The workflow file is `.github/workflows/release.yml`.
162
+ **Setup (one-time), either:** **Option A — Granular token (recommended):** Create a [Granular access token](https://docs.npmjs.com/about-access-tokens) on npm with **read and write** access for this package and **Bypass 2FA** enabled. Add it as repo secret **`NPM_TOKEN`** under **Settings** → **Secrets and variables** → **Actions**. **Option B Trusted Publishers (OIDC):** Link npm to GitHub and set Trusted publishing for this package (workflow `release.yml`) on npmjs.com; leave `NPM_TOKEN` unset. The workflow file is `.github/workflows/release.yml`.
163
163
 
164
- **If you get 404 on publish:** The package must exist on npm before you can add a Trusted Publisher (you configure it in the package’s Settings). If [npmjs.com/package/bmad-dashboard](https://www.npmjs.com/package/bmad-dashboard) returns 404, do **one manual publish** from your machine: `cd dashboard && npm login && npm publish --access public` (enter OTP when prompted). After that, add the Trusted Publisher for `release.yml` in the package settings; then CI can publish future versions.
164
+ **If OIDC gives 404 on publish:** The package must exist on npm before you can add a Trusted Publisher (you configure it in the package’s Settings). If [npmjs.com/package/bmad-dashboard](https://www.npmjs.com/package/bmad-dashboard) returns 404, do **one manual publish** from your machine: `cd dashboard && npm login && npm publish --access public` (enter OTP when prompted). After that, add the Trusted Publisher for `release.yml` in the package settings; then CI can publish future versions.
165
165
 
166
166
  ---
167
167
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bmad-dashboard",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Local dashboard to view BMAD project state (phase, artifacts, stories, sprint) in real time",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,20 +11,23 @@ import {
11
11
 
12
12
  const ARCH_STEP_IDS = [1, 2, 3, 4, 5, 6, 7, 8]
13
13
 
14
- /** Match a single AC line: bold type (Given/When/Then/And) or plain type, then text */
15
- const AC_LINE_BOLD = /^-\s*\*\*(Given|When|Then|And)\s*:?\s*(?:\*\*\s*)?(.+)$/
16
- const AC_LINE_PLAIN = /^-\s*(Given|When|Then|And)\s*:?\s*(.+)$/
14
+ /** Match a single AC line: bold type (Given/When/Then/And) or plain type, then text. Support both - and * bullets. */
15
+ const AC_LINE_BOLD = /^[-*]\s*\*\*(Given|When|Then|And)\s*:?\s*(?:\*\*\s*)?(.+)$/
16
+ const AC_LINE_PLAIN = /^[-*]\s*(Given|When|Then|And)\s*:?\s*(.+)$/
17
17
 
18
18
  function parseStoryBody(body, num, title, statusByKey) {
19
19
  const id = num.replace('.', '-')
20
- const rest = (body || '').trim()
20
+ const rest = (body || '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim()
21
21
  let userStory = ''
22
22
  const acceptanceCriteria = []
23
- // Multiple possible markers for start of acceptance criteria block
23
+ // Multiple possible markers for start of acceptance criteria block (case-insensitive)
24
24
  const acMarkers = [
25
25
  /\*\*Acceptance Criteria\s*:?\s*\*\*/i,
26
+ /\*\*Acceptance criteria\s*:?\s*\*\*/i,
26
27
  /^Acceptance Criteria\s*:?\s*$/im,
28
+ /^Acceptance criteria\s*:?\s*$/im,
27
29
  /^#+\s*Acceptance Criteria\s*:?\s*$/im,
30
+ /^#+\s*Acceptance criteria\s*:?\s*$/im,
28
31
  ]
29
32
  let acIndex = -1
30
33
  let acBlockStart = 0
@@ -44,10 +47,21 @@ function parseStoryBody(body, num, title, statusByKey) {
44
47
  const acBlock = rest.slice(acBlockStart).trim()
45
48
  const acLines = acBlock.split(/\n/).map((line) => line.trim()).filter(Boolean)
46
49
  for (const line of acLines) {
50
+ if (line.startsWith('###')) break // next story or heading
47
51
  let m = line.match(AC_LINE_BOLD)
48
52
  if (!m) m = line.match(AC_LINE_PLAIN)
49
53
  if (m) acceptanceCriteria.push({ type: m[1], text: m[2].trim() })
50
- else if (line.startsWith('- ') && line.length > 2) acceptanceCriteria.push({ type: null, text: line.slice(2).trim() })
54
+ else if ((line.startsWith('- ') || line.startsWith('* ')) && line.length > 2)
55
+ acceptanceCriteria.push({ type: null, text: line.slice(2).trim() })
56
+ }
57
+ // If we found AC header but no criteria matched, take any list items in the block
58
+ if (acceptanceCriteria.length === 0 && acBlock.length > 0) {
59
+ for (const line of acLines) {
60
+ if (line.startsWith('###')) break
61
+ const bullet = line.match(/^[-*]\s+(.+)$/) || line.match(/^\d+\.\s+(.+)$/)
62
+ if (bullet && bullet[1].trim().length > 0)
63
+ acceptanceCriteria.push({ type: null, text: bullet[1].trim() })
64
+ }
51
65
  }
52
66
  }
53
67
  // Fallback: no AC header but body has bullet list that looks like criteria (Given/When/Then/And)
@@ -58,7 +72,8 @@ function parseStoryBody(body, num, title, statusByKey) {
58
72
  let m = t.match(AC_LINE_BOLD)
59
73
  if (!m) m = t.match(AC_LINE_PLAIN)
60
74
  if (m) acceptanceCriteria.push({ type: m[1], text: m[2].trim() })
61
- else if (t.startsWith('- ') && t.length > 2) acceptanceCriteria.push({ type: null, text: t.slice(2).trim() })
75
+ else if ((t.startsWith('- ') || t.startsWith('* ')) && t.length > 2)
76
+ acceptanceCriteria.push({ type: null, text: t.slice(2).trim() })
62
77
  }
63
78
  }
64
79
  if (!userStory && rest) {