@plot-pm/board 0.3.0 → 0.3.1-rc.0
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/dist/board-server.mjs +56 -50
- package/package.json +1 -1
- package/plot-plan-meta.sh +61 -5
package/package.json
CHANGED
package/plot-plan-meta.sh
CHANGED
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
# front matter `assignee:`; "" if absent
|
|
63
63
|
# branches branch names from the `## Branches` section (backtick-
|
|
64
64
|
# quoted, matching the known prefixes; sorted, unique)
|
|
65
|
+
# NOTE: per-branch annotations (`<!-- deferred: ... -->`,
|
|
66
|
+
# `<!-- claimed: ... -->`) bind to the LINE carrying the
|
|
67
|
+
# backticked branch name. An annotation on a wrapped
|
|
68
|
+
# continuation line is not seen — keep it on the branch line.
|
|
65
69
|
# prs PR numbers from `→ #NNN` links in the `## Branches`
|
|
66
70
|
# section (sorted, unique)
|
|
67
71
|
# review_raw the plan's review-channel answer as written (`## Status`
|
|
@@ -72,6 +76,10 @@
|
|
|
72
76
|
# impl normalized: own-branches|same-branch|other-repo|none|
|
|
73
77
|
# UNKNOWN|NONE ("nowhere" is accepted for none; free-text
|
|
74
78
|
# like "here, own branches" normalizes by token)
|
|
79
|
+
# released_raw the release transition record as written (`## Status`
|
|
80
|
+
# `Released:` or front matter `released:` — date and version).
|
|
81
|
+
# Empty until /plot-release records it; the tag stays the git
|
|
82
|
+
# truth and this merely reflects it.
|
|
75
83
|
# approved_raw the approval transition record as written (`## Status`
|
|
76
84
|
# `Approved:` or front matter `approved:` — who/when/channel,
|
|
77
85
|
# e.g. "2026-07-30, alice, in-session"); "" if absent
|
|
@@ -107,7 +115,7 @@ if [ ${#files[@]} -eq 0 ] && [ ${#missing[@]} -eq 0 ]; then
|
|
|
107
115
|
fi
|
|
108
116
|
|
|
109
117
|
for f in ${missing[@]+"${missing[@]}"}; do
|
|
110
|
-
printf '{"file":"%s","format":"none","error":"file not found","phase_raw":"","phase":"NONE","phase_alt_raw":"","phase_alt":"NONE","type":"","title":"","sprint":"","story":"","assignee":"","branches":[],"prs":[],"review_raw":"","review":"NONE","impl_raw":"","impl":"NONE","approved_raw":"","started_raw":[]}\n' \
|
|
118
|
+
printf '{"file":"%s","format":"none","error":"file not found","phase_raw":"","phase":"NONE","phase_alt_raw":"","phase_alt":"NONE","type":"","title":"","sprint":"","story":"","assignee":"","branches":[],"prs":[],"review_raw":"","review":"NONE","impl_raw":"","impl":"NONE","approved_raw":"","released_raw":"","started_raw":[]}\n' \
|
|
111
119
|
"$(printf '%s' "$f" | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
112
120
|
done
|
|
113
121
|
|
|
@@ -179,14 +187,16 @@ function norm_impl(raw, s) {
|
|
|
179
187
|
function reset_state() {
|
|
180
188
|
fm_status = ""; fm_phase = ""; fm_type = ""
|
|
181
189
|
fm_title = ""; fm_sprint = ""; fm_story = ""; fm_assignee = ""
|
|
182
|
-
fm_review = ""; fm_impl = ""; fm_approved = ""; fm_started = ""
|
|
190
|
+
fm_review = ""; fm_impl = ""; fm_approved = ""; fm_started = ""; fm_released = ""
|
|
183
191
|
canon_phase = ""; canon_type = ""
|
|
184
192
|
canon_sprint = ""; canon_story = ""; canon_assignee = ""
|
|
185
|
-
canon_review = ""; canon_impl = ""; canon_approved = ""
|
|
193
|
+
canon_review = ""; canon_impl = ""; canon_approved = ""; canon_released = ""
|
|
186
194
|
h1_title = ""
|
|
187
|
-
in_fm = 0; section = ""; in_comment = 0
|
|
195
|
+
in_fm = 0; section = ""; in_comment = 0; branches_seen = 0
|
|
188
196
|
delete branches; n_branches = 0
|
|
189
197
|
delete prs; n_prs = 0
|
|
198
|
+
delete wave_names; delete wave_of; delete wave_seq; delete wave_count
|
|
199
|
+
delete deferred_of; delete claimed_of; delete ordered_b; n_waves = 0
|
|
190
200
|
delete started; n_started = 0
|
|
191
201
|
}
|
|
192
202
|
function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assignee, review, impl, approved, i, j, out, sorted_b, sorted_p, nb, np) {
|
|
@@ -209,6 +219,7 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
|
|
|
209
219
|
review = strip_placeholder((fm_review != "") ? fm_review : canon_review)
|
|
210
220
|
impl = strip_placeholder((fm_impl != "") ? fm_impl : canon_impl)
|
|
211
221
|
approved = strip_placeholder((fm_approved != "") ? fm_approved : canon_approved)
|
|
222
|
+
released = strip_placeholder((fm_released != "") ? fm_released : canon_released)
|
|
212
223
|
if (fm_started != "" && strip_placeholder(fm_started) != "") started[++n_started] = fm_started
|
|
213
224
|
# Insertion sort + dedupe (portable: no gawk asort).
|
|
214
225
|
nb = 0
|
|
@@ -236,9 +247,25 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
|
|
|
236
247
|
out = out "],\"prs\":["
|
|
237
248
|
for (i = 1; i <= np; i++) out = out (i > 1 ? "," : "") sorted_p[i]
|
|
238
249
|
out = out "]"
|
|
250
|
+
# waves[]: branches grouped by `### ` subheading, in document order. A plan
|
|
251
|
+
# with no subheadings yields one wave with an empty name.
|
|
252
|
+
out = out ",\"waves\":["
|
|
253
|
+
for (w = 1; w <= n_waves; w++) {
|
|
254
|
+
out = out (w > 1 ? "," : "") "{\"name\":\"" jesc(wave_names[w]) "\",\"branches\":["
|
|
255
|
+
first = 1
|
|
256
|
+
for (i = 1; i <= n_branches; i++) {
|
|
257
|
+
if (wave_of[i] != w) continue
|
|
258
|
+
out = out (first ? "" : ",") "{\"branch\":\"" jesc(ordered_b[i]) "\",\"deferred\":" deferred_of[i] \
|
|
259
|
+
",\"claimed\":\"" jesc(claimed_of[i]) "\"}"
|
|
260
|
+
first = 0
|
|
261
|
+
}
|
|
262
|
+
out = out "]}"
|
|
263
|
+
}
|
|
264
|
+
out = out "]"
|
|
239
265
|
out = out ",\"review_raw\":\"" jesc(review) "\",\"review\":\"" norm_review(review) "\""
|
|
240
266
|
out = out ",\"impl_raw\":\"" jesc(impl) "\",\"impl\":\"" norm_impl(impl) "\""
|
|
241
267
|
out = out ",\"approved_raw\":\"" jesc(approved) "\""
|
|
268
|
+
out = out ",\"released_raw\":\"" jesc(released) "\""
|
|
242
269
|
out = out ",\"started_raw\":["
|
|
243
270
|
for (i = 1; i <= n_started; i++) out = out (i > 1 ? "," : "") "\"" jesc(started[i]) "\""
|
|
244
271
|
out = out "]}"
|
|
@@ -264,6 +291,7 @@ in_fm {
|
|
|
264
291
|
else if (lower ~ /^review:/ && fm_review == "") fm_review = val_after_colon($0)
|
|
265
292
|
else if (lower ~ /^impl:/ && fm_impl == "") fm_impl = val_after_colon($0)
|
|
266
293
|
else if (lower ~ /^approved:/ && fm_approved == "") fm_approved = val_after_colon($0)
|
|
294
|
+
else if (lower ~ /^released:/ && fm_released == "") fm_released = val_after_colon($0)
|
|
267
295
|
else if (lower ~ /^started:/ && fm_started == "") fm_started = val_after_colon($0)
|
|
268
296
|
next
|
|
269
297
|
}
|
|
@@ -275,7 +303,9 @@ in_comment { if ($0 ~ /-->/) in_comment = 0; next }
|
|
|
275
303
|
/^#[ \t]/ && h1_title == "" { h1_title = trim(substr($0, 2)) }
|
|
276
304
|
/^## / {
|
|
277
305
|
if ($0 ~ /^## Status/) section = "status"
|
|
278
|
-
|
|
306
|
+
# First `## Branches` wins: a plan documenting the plan format quotes the
|
|
307
|
+
# section in prose, and those later headings are illustration, not contract.
|
|
308
|
+
else if ($0 ~ /^## Branches/) { section = branches_seen ? "" : "branches"; branches_seen = 1 }
|
|
279
309
|
else if ($0 ~ /^## Approval/) section = "approval"
|
|
280
310
|
else section = ""
|
|
281
311
|
next
|
|
@@ -289,6 +319,7 @@ section == "status" {
|
|
|
289
319
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**review[:*]/ && canon_review == "") canon_review = val_after_colon($0)
|
|
290
320
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**impl[:*]/ && canon_impl == "") canon_impl = val_after_colon($0)
|
|
291
321
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**approved[:*]/ && canon_approved == "") canon_approved = val_after_colon($0)
|
|
322
|
+
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**released[:*]/ && canon_released == "") canon_released = val_after_colon($0)
|
|
292
323
|
else if (lower ~ /^[ \t]*[-*]?[ \t]*\**started[:*]/) {
|
|
293
324
|
_s = strip_placeholder(val_after_colon($0))
|
|
294
325
|
if (_s != "") started[++n_started] = _s
|
|
@@ -301,10 +332,35 @@ section == "approval" {
|
|
|
301
332
|
next
|
|
302
333
|
}
|
|
303
334
|
section == "branches" {
|
|
335
|
+
# `### <name>` opens a wave. Branches before any subheading belong to an
|
|
336
|
+
# unnamed wave, so a pre-wave plan parses as exactly one wave.
|
|
337
|
+
if ($0 ~ /^###[ \t]/) {
|
|
338
|
+
wave_names[++n_waves] = trim(substr($0, 4))
|
|
339
|
+
next
|
|
340
|
+
}
|
|
341
|
+
# Claim reflection, written by the worker after its ref push succeeds. This is
|
|
342
|
+
# a reflection, not the claim: git refs remain authoritative. Computed before
|
|
343
|
+
# the branch loop below — match() clobbers RSTART/RLENGTH, which that loop
|
|
344
|
+
# needs to advance.
|
|
345
|
+
claim_note = ""
|
|
346
|
+
if (index($0, "claimed:") > 0) {
|
|
347
|
+
_c = $0
|
|
348
|
+
sub(/^.*<!--[ \t]*claimed:[ \t]*/, "", _c)
|
|
349
|
+
sub(/[ \t]*-->.*$/, "", _c)
|
|
350
|
+
claim_note = trim(_c)
|
|
351
|
+
}
|
|
304
352
|
line = $0
|
|
305
353
|
while (match(line, branch_re)) {
|
|
306
354
|
b = substr(line, RSTART + 1, RLENGTH - 2)
|
|
307
355
|
branches[++n_branches] = b
|
|
356
|
+
if (n_waves == 0) { wave_names[++n_waves] = "" }
|
|
357
|
+
wave_of[n_branches] = n_waves
|
|
358
|
+
wave_seq[n_branches] = ++wave_count[n_waves]
|
|
359
|
+
deferred_of[n_branches] = ($0 ~ /<!--[ \t]*deferred:/) ? "true" : "false"
|
|
360
|
+
# Claim reflection, written by the worker after its ref push succeeds. This
|
|
361
|
+
# is a reflection, not the claim: git refs remain authoritative.
|
|
362
|
+
claimed_of[n_branches] = claim_note
|
|
363
|
+
ordered_b[n_branches] = b
|
|
308
364
|
line = substr(line, RSTART + RLENGTH)
|
|
309
365
|
}
|
|
310
366
|
line = $0
|