@plot-pm/board 0.8.0-rc.8 → 0.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plot-pm/board",
3
- "version": "0.8.0-rc.8",
3
+ "version": "0.8.0",
4
4
  "description": "Local Kanban board for Plot — a glanceable view of plan phases from docs/plans, with sprint and story filters",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/plot-config.sh CHANGED
@@ -27,6 +27,21 @@
27
27
  # Project board | Branch prefixes | Plan directory | Active index |
28
28
  # Delivered index | Sprint directory | Story directory | Story index |
29
29
  # Plan template | Main branch | Board command
30
+ # Worker bound seconds a single prompt run may take in the worker loop
31
+ # before it is ended and the worker exits (no hop). Read by
32
+ # plot-worker-loop.sh; default 3600 (~1h), `0` disables it.
33
+ # Non-numeric or empty falls back to the default. It bounds
34
+ # a HUNG agent — one whose CLI crashed without exiting — so
35
+ # one dead worker cannot hold a slot for hours.
36
+ # Agent registry the directory the dispatcher writes agent manifests to,
37
+ # read by the board's registry. Default `.plot/agents`
38
+ # (repo-relative, gitignored, hence per-worktree). A board
39
+ # served from a worktree the dispatcher never wrote to
40
+ # reads an empty directory and synthesizes the whole fleet
41
+ # with no session ids; point this at a shared location so
42
+ # the board finds the registry wherever it was started.
43
+ # Absent = the default, so a single-checkout project is
44
+ # unaffected.
30
45
  # Agent-runner keys (optional; Plot hardcodes no agent tooling, Principle 5):
31
46
  # Worker command how /plot-dispatch runs an agent headless on a worktree.
32
47
  # `none` = asked, and this repo starts workers by hand —
package/plot-plan-meta.sh CHANGED
@@ -128,6 +128,18 @@
128
128
  # is a note to a reviewer rather than a release note. Comment
129
129
  # interiors stay non-content, as everywhere else in this parser,
130
130
  # so the template's guidance block contributes nothing.
131
+ # long_wave_names wave names too long to be labels — a report, not a refusal.
132
+ # A wave name is a label (`Shaped`, `Gated`, `Offered first`);
133
+ # a sentence-length heading is a plan-authoring mistake the
134
+ # board can only render badly. Names past a threshold judgement
135
+ # (LONG_WAVE_NAME_MAX, set from the estate's longest legitimate
136
+ # name) are listed here in document order, so the reconcile
137
+ # sweep can surface them for a fix. Reads the SAME wave names
138
+ # waves[] carries — never a second scan of the file — so both
139
+ # the ## Branches and ## Waves spellings are covered. [] when
140
+ # every wave name is a label; ALWAYS present, so a consumer
141
+ # never reads undefined. The plan still parses in full: waves[]
142
+ # is unchanged and no name is shortened or dropped.
131
143
  # issues tracker issue numbers this plan answers, from the `## Status`
132
144
  # `Issue:` line or front matter `issue:` (sorted, unique).
133
145
  # A DEDICATED field, never a scan of the body for `#NNN`: a
@@ -204,7 +216,7 @@ if [ ${#files[@]} -eq 0 ] && [ ${#missing[@]} -eq 0 ]; then
204
216
  fi
205
217
 
206
218
  for f in ${missing[@]+"${missing[@]}"}; do
207
- 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":[],"issues":[],"malformed_prs":[],"changelog":[],"review_raw":"","review":"NONE","impl_raw":"","impl":"NONE","design_raw":"","approved_raw":"","released_raw":"","delivered_raw":"","started_raw":[]}\n' \
219
+ 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":[],"issues":[],"malformed_prs":[],"changelog":[],"long_wave_names":[],"review_raw":"","review":"NONE","impl_raw":"","impl":"NONE","design_raw":"","approved_raw":"","released_raw":"","delivered_raw":"","started_raw":[]}\n' \
208
220
  "$(printf '%s' "$f" | sed 's/\\/\\\\/g; s/"/\\"/g')"
209
221
  done
210
222
 
@@ -399,6 +411,27 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
399
411
  out = out "]}"
400
412
  }
401
413
  out = out "]"
414
+ # long_wave_names[]: wave names past LONG_WAVE_NAME_MAX, in document order. A
415
+ # wave name is a label (`Shaped`, `Gated`, `Offered first`); a sentence-length
416
+ # heading is a plan-authoring mistake the board can only render badly. This
417
+ # REPORTS the offenders — a top-level field, never a change to waves[], so the
418
+ # plan still parses and every existing consumer of waves[] is untouched. The
419
+ # threshold is a JUDGEMENT baked into one constant (see LONG_WAVE_NAME_MAX):
420
+ # the longest legitimate name in the estate is `Offered first` at 13, the
421
+ # offender that motivated this is 53. Measured over the whole array so BOTH
422
+ # spellings (## Branches and ## Waves) are covered from one place. length()
423
+ # here is the awk byte length, which can exceed the character count for a name
424
+ # with a multi-byte dash — harmless: the threshold clears every real name by
425
+ # tens of bytes either way, so the verdict never turns on the last byte.
426
+ out = out ",\"long_wave_names\":["
427
+ lwn = 0
428
+ for (w = 1; w <= n_waves; w++) {
429
+ if (length(wave_names[w]) > LONG_WAVE_NAME_MAX) {
430
+ out = out (lwn > 0 ? "," : "") "\"" jesc(wave_names[w]) "\""
431
+ lwn++
432
+ }
433
+ }
434
+ out = out "]"
402
435
  out = out ",\"review_raw\":\"" jesc(review) "\",\"review\":\"" norm_review(review) "\""
403
436
  out = out ",\"impl_raw\":\"" jesc(impl) "\",\"impl\":\"" norm_impl(impl) "\""
404
437
  out = out ",\"design_raw\":\"" jesc(design) "\""
@@ -413,7 +446,12 @@ function emit_record( fmt, praw, palt_raw, traw, title, sprint, story, assigne
413
446
  out = out "}"
414
447
  print out
415
448
  }
416
- BEGIN { branch_re = "`(" PREFIXES ")/[^`]+`" }
449
+ # The longest wave name that still reads as a label, not prose. A JUDGEMENT, not
450
+ # a measurement: the longest legitimate name in the estate is `Offered first`
451
+ # (13), and the offender this exists to catch is a 53-character sentence, so the
452
+ # line sits well clear of both. Reported, never enforced — a name past it makes
453
+ # `long_wave_names`, and nothing refuses the plan.
454
+ BEGIN { branch_re = "`(" PREFIXES ")/[^`]+`"; LONG_WAVE_NAME_MAX = 40 }
417
455
  FNR == 1 {
418
456
  if (NR > 1) emit_record()
419
457
  reset_state()