beadcyte 0.4.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/LICENSE +661 -0
  3. package/README.md +386 -0
  4. package/THIRD_PARTY_NOTICES.md +56 -0
  5. package/bin/beadcyte.mjs +60 -0
  6. package/package.json +77 -0
  7. package/src/changelog-cli.mjs +105 -0
  8. package/src/changelog.mjs +196 -0
  9. package/src/cli.mjs +577 -0
  10. package/src/estimator.mjs +314 -0
  11. package/src/format.mjs +22 -0
  12. package/src/history-walk.mjs +170 -0
  13. package/src/index.mjs +5 -0
  14. package/src/mutate.mjs +193 -0
  15. package/src/projects.mjs +120 -0
  16. package/src/provenance.mjs +75 -0
  17. package/src/review-hours.mjs +117 -0
  18. package/src/roster-path.mjs +24 -0
  19. package/src/scheduler.mjs +424 -0
  20. package/src/serve.mjs +411 -0
  21. package/src/server-state.mjs +105 -0
  22. package/src/ship.mjs +178 -0
  23. package/src/stage-waits.mjs +69 -0
  24. package/src/start.mjs +111 -0
  25. package/src/stop.mjs +66 -0
  26. package/src/velocity.mjs +209 -0
  27. package/src/web/App.vue +691 -0
  28. package/src/web/app.css +54 -0
  29. package/src/web/assets/favicon.svg +12 -0
  30. package/src/web/avatar.ts +53 -0
  31. package/src/web/bead-detail.ts +240 -0
  32. package/src/web/changelog-view.ts +41 -0
  33. package/src/web/components/BeadDrawer.vue +1883 -0
  34. package/src/web/components/BeadSubGraph.vue +326 -0
  35. package/src/web/components/BeadSubGraphOverlay.vue +192 -0
  36. package/src/web/components/BeadTooltip.vue +516 -0
  37. package/src/web/components/BeadcyteMark.vue +64 -0
  38. package/src/web/components/BeadsGantt.vue +2125 -0
  39. package/src/web/components/BeadsGrid.vue +468 -0
  40. package/src/web/components/BeadsIncytes.vue +567 -0
  41. package/src/web/components/BeadsMine.vue +325 -0
  42. package/src/web/components/BeadsTable.vue +335 -0
  43. package/src/web/components/ChangelogOverlay.vue +198 -0
  44. package/src/web/components/ContextMenu.vue +386 -0
  45. package/src/web/components/ControlsPanel.vue +476 -0
  46. package/src/web/components/CostTrend.vue +206 -0
  47. package/src/web/components/FilterPopover.vue +245 -0
  48. package/src/web/components/GroupProgress.vue +274 -0
  49. package/src/web/components/LoadMeter.vue +144 -0
  50. package/src/web/components/MineRow.vue +28 -0
  51. package/src/web/components/OptionsMenu.vue +825 -0
  52. package/src/web/components/PriorityChip.vue +105 -0
  53. package/src/web/components/ScoreStrip.vue +131 -0
  54. package/src/web/components/SearchPalette.vue +210 -0
  55. package/src/web/components/ShipTrend.vue +510 -0
  56. package/src/web/components/ShortcutsOverlay.vue +164 -0
  57. package/src/web/components/Term.vue +177 -0
  58. package/src/web/components/Toast.vue +50 -0
  59. package/src/web/components/TriageMeters.vue +426 -0
  60. package/src/web/components/TypeChip.vue +96 -0
  61. package/src/web/components/Walkthrough.vue +209 -0
  62. package/src/web/components/WhatIfPanel.vue +206 -0
  63. package/src/web/components/WipBullets.vue +191 -0
  64. package/src/web/components/filter-option.ts +9 -0
  65. package/src/web/composables/url-codec.ts +136 -0
  66. package/src/web/composables/useBeadTooltip.ts +148 -0
  67. package/src/web/composables/useKeyboard.ts +97 -0
  68. package/src/web/composables/useLiveRefresh.ts +69 -0
  69. package/src/web/composables/useTheme.ts +125 -0
  70. package/src/web/composables/useUrlState.ts +208 -0
  71. package/src/web/controls-scope.ts +83 -0
  72. package/src/web/cost.ts +251 -0
  73. package/src/web/dep-headings.ts +62 -0
  74. package/src/web/economics.ts +440 -0
  75. package/src/web/env.d.ts +85 -0
  76. package/src/web/frontier.ts +208 -0
  77. package/src/web/gantt-viewport.ts +99 -0
  78. package/src/web/highlights.ts +124 -0
  79. package/src/web/index.html +46 -0
  80. package/src/web/insights.ts +107 -0
  81. package/src/web/keybindings.ts +200 -0
  82. package/src/web/load-meter.ts +72 -0
  83. package/src/web/main.ts +20 -0
  84. package/src/web/markdown.ts +14 -0
  85. package/src/web/mine.ts +137 -0
  86. package/src/web/mutations.ts +21 -0
  87. package/src/web/person.ts +102 -0
  88. package/src/web/projects-text.ts +15 -0
  89. package/src/web/projects.ts +188 -0
  90. package/src/web/refresh.ts +47 -0
  91. package/src/web/search.ts +50 -0
  92. package/src/web/shortcuts.ts +113 -0
  93. package/src/web/status-filter.ts +48 -0
  94. package/src/web/store.ts +1378 -0
  95. package/src/web/style-audit.mjs +346 -0
  96. package/src/web/styles-alt.css +111 -0
  97. package/src/web/styles-ported.css +270 -0
  98. package/src/web/subgraph.ts +362 -0
  99. package/src/web/table.ts +201 -0
  100. package/src/web/theme.ts +88 -0
  101. package/src/web/tokens.css +168 -0
  102. package/src/web/triage.ts +914 -0
  103. package/src/web/view-model.ts +717 -0
  104. package/src/web/walkthrough.ts +133 -0
  105. package/src/web/watchlist.ts +47 -0
  106. package/src/web/whatif.ts +291 -0
  107. package/src/web/window.ts +73 -0
  108. package/src/web/wip.ts +83 -0
package/README.md ADDED
@@ -0,0 +1,386 @@
1
+ <img src="docs/beadcyte-mark.png" alt="beadcyte" width="380">
2
+
3
+ <!-- hand-maintained: start -->
4
+ <!-- Written by the maintainer, not by agents. See CLAUDE.md. -->
5
+
6
+ A local web-based history and projected future, for any
7
+ [beads](https://github.com/gastownhall/beads) project.
8
+
9
+ Pairing agents with beads has changed how our team works: far more is in flight than before. However, velocity in one place exposes bottlenecks in another. **If production of ideas becomes cheap, managing the flow of ideas becomes critical**. This tool is for teams using beads to coordinate with agents over long-horizon tasks. [The feature tour](#the-tour) below walks through each view.
10
+
11
+ beadcyte reads your beads DB with `bd list --all --json` and draws two things that look alike and are not: what **happened**, which is measured, and what it **expects to happen**, which is a model's opinion. Three models drive the projection: a historical-median duration estimator, a greedy WIP-cap scheduler calibrated against your real throughput, and an eight-signal triage score. Each is shown with its own uncertainty rather than as a flat number.
12
+
13
+ beadcyte is made by [Incyte Studios](https://incytestudios.com).
14
+
15
+ <!-- hand-maintained: end -->
16
+
17
+ ---
18
+
19
+ ## Quick start
20
+
21
+ ```bash
22
+ cd /path/to/your/beads/project
23
+ npx beadcyte start
24
+ ```
25
+
26
+ That opens an interactive app on `127.0.0.1:4173` and gives you the terminal
27
+ back; `npx beadcyte stop` ends it. Localhost only, no auth, no build step —
28
+ same threat model as `bv`.
29
+
30
+ Or install it once; `bcyte` is a short alias for the same command:
31
+
32
+ ```bash
33
+ npm i -g beadcyte
34
+ beadcyte start
35
+ ```
36
+
37
+ For a single self-contained SVG, with no server:
38
+
39
+ ```bash
40
+ beadcyte --out gantt.svg
41
+ ```
42
+
43
+ The SVG has a system font stack and no external references, so it embeds
44
+ anywhere: MR comments, wiki pages, dashboards.
45
+
46
+ ---
47
+
48
+ ## The tour
49
+
50
+ ### Mine — what should I be doing, what is going on
51
+
52
+ ![The mine view](docs/screenshots/mine.png)
53
+
54
+ The first tab, and the one the app opens on. Everything on it is about one
55
+ person: what is ready for you (assigned to you, approved with `spec:ready`,
56
+ not already moving, every blocker closed), what you have in progress and in
57
+ review, which of your beads are waiting on someone else and who that is,
58
+ whose beads are waiting on you, and what you are watching. Unassigned beads
59
+ the scheduler would route to you appear as suggestions, marked as inferred.
60
+
61
+ Who "you" are is set once, in the options menu, from the assignees present in
62
+ the data, and remembered by the browser. A shared link carrying `?me=` shows
63
+ that person's view for one load without changing your own choice. Until a
64
+ user is chosen, the view asks.
65
+
66
+ The same two questions are one click away on the Gantt and grid too: the
67
+ MINE buttons in the controls row set the filters to *my ready work* or *my
68
+ work in review* outright, so the result never depends on what was selected
69
+ before, and clicking the active one clears back to the defaults. The
70
+ `unblocked` term they rely on is an ordinary filter as well.
71
+
72
+ ### Gantt — history and projection on one timeline
73
+
74
+ ![The Gantt view](docs/screenshots/gantt.png)
75
+
76
+ Past bars are real `started_at → closed_at`. Future bars are the scheduler's
77
+ projection, and their length is a bucketed median of how long comparable work
78
+ has actually taken. A dashed red rule marks today, group headers carry a
79
+ progress chip, and dependency arrows connect `blocks` edges between visible
80
+ bars.
81
+
82
+ Bar styling distinguishes the cases that matter: shipped work carries a ship
83
+ marker, closed-without-shipping is dim, backlog beads that are not
84
+ `spec:ready` are faint, and a bar whose assignee the scheduler **guessed** by
85
+ affinity is hatched — with the lane header counting how many of its beads are
86
+ guesses — rather than presented as a decision. In the
87
+ screenshot ten of this repo's 40 closed beads are dim for a real reason: they
88
+ were closed without ship evidence, so nothing says they shipped.
89
+
90
+ The footer under the chart counts bars by kind, and each name explains
91
+ itself on hover: `shipped` and `closedNoShip` are history; `inProgressLive`
92
+ is the spent part of work under way; `future`, `futureBacklog` (not
93
+ `spec:ready`, scheduled after the ready work) and `unassigned` (from the pool
94
+ nobody owns) are the projection. A projected bar is the **work**, to scale.
95
+ The waiting around it — unclaimed time before an affinity pick, review time
96
+ before the landing — is drawn dull, hatched and cut short at the date it ends,
97
+ with a dotted connector for what was cut: its length is not to scale, its
98
+ end is. The tooltip gives both numbers.
99
+
100
+ Status is one control, not two: the filter starts with every status except
101
+ closed and deferred selected, and the panel says `3 selected` rather than
102
+ leaving you to infer a default from an empty chip.
103
+
104
+ Hovering a bar gives the bead's detail and a projected finish **date** — not a
105
+ day offset — including whether that date is a projection or just the end of the
106
+ scheduling window.
107
+
108
+ A window that would squeeze below six pixels a day scrolls instead: the plot
109
+ shows a readable span centred on today, with a scrollbar under it. Drag the
110
+ axis to pan, wheel over the axis to zoom, swipe or shift-wheel over the plot
111
+ to pan, and `t` brings today back to the centre. A window that fits is drawn
112
+ whole, as before.
113
+
114
+ ### Grid — browse without the time axis
115
+
116
+ ![The grid view](docs/screenshots/grid.png)
117
+
118
+ The same filtered set as cards: title, chips, assignee, labels. Better than the
119
+ Gantt for reading titles and worse for anything about time, which is why both
120
+ exist.
121
+
122
+ ### Table — every derived number in one sortable place
123
+
124
+ ![The table view](docs/screenshots/table.png)
125
+
126
+ The same filtered set as dense rows, one per bead, with everything the app
127
+ knows in columns: type, priority, status, assignee (marked when the scheduler
128
+ inferred it), labels, estimate, projected finish, triage score, group. Every
129
+ column sorts; the default is triage score, highest first, because the table's
130
+ job is "what next". Unlike the Gantt it never drops rows to keep a group
131
+ short, so it is also the readable equivalent of the chart — nothing in the app
132
+ is reachable only by reading a bar.
133
+
134
+ ### Incytes — the project, not the beads
135
+
136
+ ![The incytes view](docs/screenshots/incytes.png)
137
+
138
+ Ships per week over the velocity window, per-group completion sorted by size
139
+ so the outlier is findable, and Allocation: everyone's work in flight against
140
+ their calibrated cap on one shared scale, with the run past the cap drawn at
141
+ its real length. That block used to sit under the controls on every view; it
142
+ is a project-wide fact, so it lives here.
143
+
144
+ Beside the ship trend, **Cost per week**: seat hours stacked by seat, with
145
+ tokens in and out in the figures and the table, in the same weekly buckets.
146
+ Weeks behind today are what closed beads recorded; weeks ahead are projected
147
+ from the median cost of comparable shipped work, placed where the schedule
148
+ lands each bead, and drawn dulled and dashed so they cannot be read as
149
+ measured. The same block appears on a person's pane for their beads. See
150
+ [docs/economics.md](docs/economics.md#cost-trajectory) for exactly how.
151
+
152
+ **This screenshot is beadcyte's own repo, and the spike is the honest shape
153
+ of recovered data.** Nothing here recorded a ship while the work happened; the
154
+ evidence was read back out of `Closes <id>` commit trailers afterwards, so
155
+ every ship lands in the week the trailers exist and the seven weeks before it
156
+ are structurally zero — the repo did not exist.
157
+
158
+ Which is why the headline says _"first week of history — no baseline yet"_
159
+ rather than `+700%`. With one shipping week the mean **is** that week divided
160
+ by the window length, so a percentage against it is decided by the window and
161
+ not by the work: identical beads report +700% at ±90d and +300% at ±30d. A
162
+ number that moves when you change the axis is an artefact with a percent sign
163
+ on it, so the chart declines to print one.
164
+
165
+ If your own trend looks empty rather than spiky, nothing is broken and nothing
166
+ was recorded — see [what to record](docs/economics.md#what-counts-as-ship-evidence).
167
+
168
+ Pick a person — the chips at the top of the view, a swimlane header when
169
+ grouped by assignee, a handle on a grid card or in the Allocation block — and
170
+ the same two charts re-scope to them: their ships per week in the project's
171
+ weeks, and the progress of the beads recorded as theirs. Below that, their
172
+ roster line (the raw cap, the calibrated cap and how it was derived, or a
173
+ plain statement that no roster was written and the cap is a default), what is
174
+ in flight, what is ready for them, what the scheduler would route to them
175
+ next — marked as a projection, because nobody decided it — and their recent
176
+ ships. `?who=` carries the selection in the link.
177
+
178
+ Two more blocks on that pane are the plan's edge for the person. **Frontier**
179
+ is a ruler of the coming days — the window's forward span, 7 to 60 — with a
180
+ hollow mark where a bead starts for them and a filled one where it lands,
181
+ read off the same schedule the Gantt draws; dashed marks are assignments the
182
+ scheduler inferred. **Proposed next** ranks what they could take, with the
183
+ reasons stated beside each: the scheduler's own routing, roster affinity,
184
+ triage score, what it unblocks, priority, whether they have room today — and,
185
+ where someone else is over cap, that person's not-yet-started beads offered
186
+ across. Stage puts a proposal into the what-if (below), where the diff shows
187
+ what moves; nothing is written until it is confirmed.
188
+
189
+ ### The drawer — why a bead ranks where it does
190
+
191
+ ![The bead drawer](docs/screenshots/drawer.png)
192
+
193
+ Triage's eight signals as contribution meters. The track length is the
194
+ signal's declared weight, so a signal that could never matter much is visibly
195
+ short. The fill is what this bead actually contributed. A tick marks what a
196
+ high value looks like on **your** repo, and a cut-off track marks weight the
197
+ signal cannot reach at all.
198
+
199
+ Signals that cannot separate anything on your data are labelled `FLAT` — one
200
+ of them carries the second-largest weight and is frequently non-zero on
201
+ exactly one bead, because shallow dependency graphs give it nothing to measure.
202
+ An authoritative-looking number that means nothing is worse than no number, so
203
+ the drawer says which is which. Below that: the dependency subgraph — for an
204
+ epic, the graph of all its children and the blocks edges between them, since
205
+ an epic's own neighbourhood is just the epic, with a full-screen view for the
206
+ large ones — the dossier with projected dates, and where the bead's time went.
207
+
208
+ That last one distinguishes what was **measured** from what beadcyte
209
+ **computed**. The queue wait is `started_at − created_at`, arithmetic on
210
+ fields `bd` maintains for free, so it is derived wherever nobody recorded it —
211
+ hatched, and its legend row tagged `DERIVED`, because a reconstructed number
212
+ that looks measured is one you can never separate out again. Worked hours are
213
+ never derived: the estimator prefers them over wall-clock, so an invented
214
+ figure would override the one real signal rather than diluting it.
215
+
216
+ Every derived figure in the drawer explains itself. A dotted underline marks
217
+ a term that will: the score, each of the eight signal names, the estimate's
218
+ source (`(feature), n=8` — n is the sample count behind the median, and a
219
+ small one deserves less trust), the projected finish and why it sometimes says
220
+ _finishes after_, the phase names, the tense of the dependency headings, and
221
+ the synthetic-assignee marker. Hover shows the sentence; Tab reaches it; a
222
+ click or tap pins it; Escape, a scroll or a tap elsewhere dismisses it. The
223
+ sentences come from the modules that compute the figures, so a formula cannot
224
+ change without its explanation changing beside it.
225
+
226
+ ### First run
227
+
228
+ The first visit opens a short walkthrough in the corner — the bar kinds, the
229
+ projection being a model rather than a plan, triage, the views, the controls.
230
+ It is not a modal and takes no focus; skip or finish it and it never returns
231
+ unasked. The options menu re-opens it, and nothing in it exists only there.
232
+
233
+ ### What if
234
+
235
+ Stage changes without writing them: reassign, reprioritise or mark
236
+ `spec:ready` from a bead's drawer, change someone's cap from their roster
237
+ line on incytes, or add an idea with a rough size from the what-if panel.
238
+ Every plan-reading view then shows the plan as it would be — the Gantt draws
239
+ each moved bead's old work as a dashed ghost with the delta beside it — and
240
+ the panel lists what moves and by how much, where ideas land, and the
241
+ frontier: how many beads land for each person in the next two weeks, before
242
+ and after. Discard drops it all. Confirm shows the `bd` commands the change
243
+ set amounts to, then runs them one after another through the same
244
+ whitelisted endpoint the quick actions use, and reports what happened to
245
+ each; a cap is a roster.json edit and is reported rather than written.
246
+
247
+ ### Acting on a bead
248
+
249
+ Right-click a bar, a card, a table row or a mine row — or press `a` with the
250
+ drawer open — for the quick actions the allocate ritual otherwise runs through
251
+ the CLI: claim, assign to someone on the roster, mark or remove `spec:ready`,
252
+ add a label, defer. Each runs one
253
+ `bd` command on the server; [How beadcyte uses bd](docs/bd-usage.md) lists
254
+ every one of them and how to reverse it by hand. Nothing else writes to your
255
+ tracker; there is no bulk action and no client-side undo, by design.
256
+
257
+ ### Options — projects, current user, theme, refresh
258
+
259
+ ![The options menu](docs/screenshots/options.png)
260
+
261
+ Switch between local beads projects, say who you are for the mine view, pick
262
+ light/dark/system and one of twelve styles with live previews — including
263
+ ports of Catppuccin, Dracula, GitHub, Gruvbox, Nord, One, Solarized and Tokyo
264
+ Night, and a High Contrast original — and set the poll interval. A project the current server
265
+ cannot read is shown as unavailable with the reason, rather than failing when
266
+ you click it.
267
+
268
+ ---
269
+
270
+ ### Keyboard
271
+
272
+ Press `?` for the shortcuts. The convention is single letters with no
273
+ modifier — `j`/`k` walk the beads in view, `1`–`5` switch views, `g` and
274
+ `w` cycle group-by and window, `p` pins, `,` opens options — and nothing
275
+ fires while you are typing in a field. The keyboard cursor is the open drawer:
276
+ there is no separate focused row, so exactly one thing ever looks selected.
277
+ The overlay is generated from the same table that binds the keys, so it cannot
278
+ drift from them.
279
+
280
+ ## Flags
281
+
282
+ `beadcyte [flags]` — SVG mode:
283
+
284
+ | Flag | Default | Meaning |
285
+ | -------------------- | ----------------------- | -------------------------------------- |
286
+ | `--from -Nd` | `-90d` | Window start, relative to today |
287
+ | `--to +Nd` | `+90d` | Window end, relative to today |
288
+ | `--group-by MODE` | `epic` | `epic` / `assignee` / `seat` / `track` |
289
+ | `--max-per-group N` | `20` | Rows per swimlane before truncation |
290
+ | `--include-deferred` | `false` | Include `status=deferred` beads |
291
+ | `--roster PATH` | `.beadcyte/roster.json` | Per-project WIP caps and affinities |
292
+ | `--out PATH` | `./beadcyte.svg` | SVG output path |
293
+
294
+ `beadcyte changelog [flags]` — regenerate `CHANGELOG.md` from closed beads:
295
+
296
+ | Flag | Meaning |
297
+ | ---------- | ------------------------------------------- |
298
+ | _(none)_ | Write `CHANGELOG.md` at the repo root |
299
+ | `--check` | Exit 2 if the committed file is out of date |
300
+ | `--stdout` | Print instead of writing |
301
+
302
+ An entry appears when a closed bead carries ship evidence. Spikes, `upstream:`
303
+ bugs, chores and epics are excluded, and releases are cut by git tag — the
304
+ file states both rules in its own header, so a reader can tell "nothing
305
+ shipped" from "this file does not list that".
306
+
307
+ `beadcyte start [flags]` — interactive mode. Starts the server in the
308
+ background, prints its address and the log path, and returns; `beadcyte stop`
309
+ ends it, from the same directory. `beadcyte serve [flags]` runs the same server
310
+ in the foreground instead, with Ctrl-C to stop. Both take the same flags:
311
+
312
+ | Flag | Default | Meaning |
313
+ | ---------------- | ----------------------- | ----------------------------------- |
314
+ | `--port N` | `4173` | Listen port; falls through if taken |
315
+ | `--roster PATH` | `.beadcyte/roster.json` | Same roster convention |
316
+ | `--cache-ttl MS` | `30000` | `bd` shell-out cache TTL |
317
+
318
+ The version tag in the header opens the changelog, rendered in the app from
319
+ the copy shipped with the build. Set `BEADCYTE_CHANGELOG_URL` to add a link out
320
+ to the same file on your repo; it is absent when unset.
321
+
322
+ Most of the interactive app's state lives in the URL — view, grouping,
323
+ filters, window — so a link shares what you were looking at. Links written
324
+ before the status filter absorbed the old `showClosed` / `includeDeferred`
325
+ toggles still resolve to the same view.
326
+
327
+ ---
328
+
329
+ ## Documentation
330
+
331
+ | | |
332
+ | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
333
+ | [What to record](docs/economics.md) | What beadcyte reads out of your beads, what breaks when it is missing, and how to record it. **Start here if your charts look empty.** |
334
+ | [The model](docs/model.md) | How the estimator, the scheduler and the triage score work, what they are calibrated against, and where they are known to be wrong. |
335
+ | [How beadcyte uses bd](docs/bd-usage.md) | Every `bd` command the app runs — the reads, the background history walk, each quick action and how to reverse it — and whose name a claim carries. |
336
+ | [Roster](docs/roster.md) | Per-project WIP caps and affinity routing. |
337
+ | [Programmatic use](docs/api.md) | Using the estimator and scheduler as libraries. |
338
+ | [Theming](docs/theming.md) | The token layer, light/dark, named styles, and the audit that keeps a restyle from relabelling the data. |
339
+ | [CHANGELOG](CHANGELOG.md) | What has shipped. Generated from the tracker, not written by hand. |
340
+
341
+ ---
342
+
343
+ ## Development
344
+
345
+ ```bash
346
+ npm install
347
+ npm run dev # beadcyte serve against this repo's own beads (port 4173)
348
+ npm test # unit + parity + perf suites
349
+ npm run typecheck # vue-tsc --noEmit
350
+ npm run build # static bundle → src/web/dist
351
+ npm run changelog # regenerate CHANGELOG.md
352
+ npm run changelog:check # fail if the committed CHANGELOG.md is stale
353
+ ```
354
+
355
+ `npm run dev` points the dev server at beadcyte's own beads DB, so the app is
356
+ always dogfooding itself.
357
+
358
+ ---
359
+
360
+ ## Non-goals
361
+
362
+ - **Resource-constrained scheduling.** Greedy dispatch, no solver. No
363
+ cross-human load balancing and no auto-reassignment: the chart is a
364
+ projection of current allocation, not a proposal for a better one.
365
+ - **Drag-editing the plan.** Dates come from the model; changing them means
366
+ changing the beads.
367
+ - **Non-`bd` trackers.** The input shape is `bd list --json`; anything else
368
+ needs an adapter.
369
+
370
+ ## Licence
371
+
372
+ AGPL-3.0-only. See [LICENSE](LICENSE).
373
+
374
+ beadcyte is copyright [Incyte Studios, LLC](https://incytestudios.com) and released under the GNU Affero
375
+ General Public License, version 3. You may use, change and redistribute it
376
+ under the same terms. If you run a modified version as a network service,
377
+ section 13 obliges you to offer its users the corresponding source.
378
+
379
+ Incyte Studios stays the sole copyright holder so that it can also offer the
380
+ project under other terms. That is why contributions are accepted under a
381
+ permissive inbound licence rather than the AGPL; see
382
+ [CONTRIBUTING.md](CONTRIBUTING.md).
383
+
384
+ Dependencies are MIT, ISC, BSD and Apache-2.0 licensed and carry their own
385
+ notices. The triage score is a local reimplementation of a formula documented
386
+ by another tool, not a copy of its code; see [docs/model.md](docs/model.md).
@@ -0,0 +1,56 @@
1
+ # Third-party notices
2
+
3
+ beadcyte is released under AGPL-3.0-only (see [LICENSE](LICENSE)). The named
4
+ colour styles in `src/web/styles-ported.css` reproduce palette values published
5
+ by the projects below, each under the MIT licence. Palette values are facts
6
+ rather than copyrightable expression, but the values were copied from licensed
7
+ files, so the copyright line and permission notice of each are reproduced here
8
+ as that licence asks. Theme names belong to their owners and are used only to
9
+ identify the palette a style reproduces.
10
+
11
+ The Default, Synthwave, Terminal and High Contrast styles are beadcyte's own.
12
+
13
+ ## MIT License
14
+
15
+ The following applies to each project in the table, with the copyright line
16
+ shown for it:
17
+
18
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ > of this software and associated documentation files (the "Software"), to deal
20
+ > in the Software without restriction, including without limitation the rights
21
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ > copies of the Software, and to permit persons to whom the Software is
23
+ > furnished to do so, subject to the following conditions:
24
+ >
25
+ > The above copyright notice and this permission notice shall be included in
26
+ > all copies or substantial portions of the Software.
27
+ >
28
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ > SOFTWARE.
35
+
36
+ | Style | Project | Copyright | Licence source | Palette source |
37
+ | --- | --- | --- | --- | --- |
38
+ | Catppuccin | [catppuccin/palette](https://github.com/catppuccin/palette) | Copyright (c) 2021 Catppuccin | [LICENSE](https://github.com/catppuccin/catppuccin/blob/main/LICENSE) | `palette.json`, Mocha and Latte flavours |
39
+ | Dracula | [dracula/dracula-theme](https://github.com/dracula/dracula-theme) | Copyright (c) 2023 Dracula Theme | [LICENSE](https://github.com/dracula/dracula-theme/blob/master/LICENSE) | README colour palette tables, Dracula and Alucard |
40
+ | GitHub | [primer/primitives](https://github.com/primer/primitives) 7.11.13 | Copyright (c) 2018 GitHub Inc. | [LICENSE](https://github.com/primer/primitives/blob/main/LICENSE) | `dist/json/colors/light.json` and `dark.json` |
41
+ | Gruvbox | [morhetz/gruvbox](https://github.com/morhetz/gruvbox) | Pavel Pertsev | `"license": "MIT"` in [package.json](https://raw.githubusercontent.com/morhetz/gruvbox/master/package.json); the repository ships no LICENSE file | `colors/gruvbox.vim` |
42
+ | Nord | [nordtheme/nord](https://github.com/nordtheme/nord) | Copyright (c) 2016-present Sven Greb | [license](https://github.com/nordtheme/nord/blob/develop/license) | `src/nord.css`, `--nord0` to `--nord15` |
43
+ | One | [atom/one-dark-syntax](https://github.com/atom/one-dark-syntax) and [one-light-syntax](https://github.com/atom/one-light-syntax) | Copyright (c) 2016 GitHub Inc. | [LICENSE.md](https://github.com/atom/one-dark-syntax/blob/master/LICENSE.md) | `styles/colors.less` in each, authored as HSL |
44
+ | Solarized | [altercation/solarized](https://github.com/altercation/solarized) | Copyright (c) 2011 Ethan Schoonover | [LICENSE](https://github.com/altercation/solarized/blob/master/LICENSE) | README palette table |
45
+ | Tokyo Night | [enkia/tokyo-night-vscode-theme](https://github.com/enkia/tokyo-night-vscode-theme) | Copyright (c) 2018-present Enkia | [LICENSE.txt](https://github.com/enkia/tokyo-night-vscode-theme/blob/master/LICENSE.txt) | `themes/tokyo-night-color-theme.json` and the light variant |
46
+
47
+ ## What was changed
48
+
49
+ A port keeps each theme's hues. Where a published colour fell short of
50
+ beadcyte's legibility floors it was moved in lightness only, and the lightness
51
+ of every colour-only encoding token was then placed by
52
+ `scripts/place-encoding-lightness.mjs` so each pair stays distinguishable under
53
+ simulated colour-vision deficiency. Two named substitutions go further and are
54
+ noted above their blocks in `src/web/styles-ported.css`: Nord's bar hues carry
55
+ scaled chroma, and Solarized's future bars use its magenta rather than its
56
+ violet. The derivation rules are in [docs/theming.md](docs/theming.md).
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+ // beadcyte — CLI dispatcher. The package is published unscoped as `beadcyte`
3
+ // so `npx beadcyte start` works from any beads project. A global install puts
4
+ // two names on PATH for the same file: `beadcyte`, and `bcyte` for short.
5
+ //
6
+ // Subcommands:
7
+ // beadcyte → default SVG mode (see src/cli.mjs)
8
+ // beadcyte export [args] → alias for the default SVG mode
9
+ // beadcyte start [args] → serve in the background, print the address, return
10
+ // beadcyte stop → end the background server for this directory
11
+ // beadcyte serve [args] → the same server in the foreground (see src/serve.mjs)
12
+ // beadcyte changelog → generate CHANGELOG.md from closed beads
13
+ // beadcyte --help → passes to whichever subcommand's --help
14
+ // beadcyte --version → prints the version from package.json
15
+ //
16
+ // A subcommand is the FIRST positional arg with no leading `--`. Flags stay
17
+ // in their subcommand's argv slice; `beadcyte --from -30d` is the default subcommand
18
+ // with `--from -30d`, not a subcommand called `--from`.
19
+
20
+ import { readFileSync } from "node:fs";
21
+ import { fileURLToPath } from "node:url";
22
+ import { dirname, join } from "node:path";
23
+
24
+ const __filename = fileURLToPath(import.meta.url);
25
+ const __dirname = dirname(__filename);
26
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
27
+
28
+ const argv = process.argv.slice(2);
29
+ const first = argv[0];
30
+ const KNOWN_SUBCOMMANDS = new Set(["start", "stop", "serve", "export", "changelog"]);
31
+
32
+ // Handle version flag first
33
+ if (first === "--version" || first === "-v") {
34
+ console.log(packageJson.version);
35
+ process.exit(0);
36
+ }
37
+
38
+ if (first === "serve") {
39
+ process.argv = [process.argv[0], process.argv[1], ...argv.slice(1)];
40
+ await import("../src/serve.mjs");
41
+ } else if (first === "start") {
42
+ process.argv = [process.argv[0], process.argv[1], ...argv.slice(1)];
43
+ await import("../src/start.mjs");
44
+ } else if (first === "stop") {
45
+ process.argv = [process.argv[0], process.argv[1], ...argv.slice(1)];
46
+ await import("../src/stop.mjs");
47
+ } else if (first === "changelog") {
48
+ process.argv = [process.argv[0], process.argv[1], ...argv.slice(1)];
49
+ await import("../src/changelog-cli.mjs");
50
+ } else if (first === "export" || first === undefined || first.startsWith("--")) {
51
+ // default: SVG mode (drop `export` if present)
52
+ if (first === "export")
53
+ process.argv = [process.argv[0], process.argv[1], ...argv.slice(1)];
54
+ await import("../src/cli.mjs");
55
+ } else {
56
+ console.error(
57
+ `beadcyte: unknown subcommand "${first}". Try one of: ${[...KNOWN_SUBCOMMANDS].join(", ")}, or omit for the default SVG mode.`,
58
+ );
59
+ process.exit(2);
60
+ }
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "beadcyte",
3
+ "version": "0.4.0",
4
+ "description": "Gantt of bead history + projected future — historical-median estimator + greedy WIP-cap scheduler + self-contained SVG",
5
+ "author": "Incyte Studios, LLC <hello@incytestudios.com> (https://incytestudios.com)",
6
+ "type": "module",
7
+ "bin": {
8
+ "beadcyte": "bin/beadcyte.mjs",
9
+ "bcyte": "bin/beadcyte.mjs"
10
+ },
11
+ "exports": {
12
+ ".": "./src/index.mjs",
13
+ "./estimator": "./src/estimator.mjs",
14
+ "./scheduler": "./src/scheduler.mjs",
15
+ "./cli": "./src/cli.mjs",
16
+ "./format": "./src/format.mjs",
17
+ "./changelog": "./src/changelog.mjs"
18
+ },
19
+ "files": [
20
+ "bin",
21
+ "src",
22
+ "!src/**/*.test.mjs",
23
+ "!src/web/__fixtures__",
24
+ "!src/web/dist",
25
+ "README.md",
26
+ "CHANGELOG.md",
27
+ "LICENSE",
28
+ "THIRD_PARTY_NOTICES.md"
29
+ ],
30
+ "scripts": {
31
+ "dev": "node bin/beadcyte.mjs serve",
32
+ "build": "vite build",
33
+ "preview": "vite preview",
34
+ "typecheck": "vue-tsc --noEmit",
35
+ "test": "node --test 'src/**/*.test.mjs'",
36
+ "changelog": "node src/changelog-cli.mjs",
37
+ "changelog:check": "node src/changelog-cli.mjs --check"
38
+ },
39
+ "dependencies": {
40
+ "@incytestudios/ddv": "^1.0.0-rc.4",
41
+ "@lucide/vue": "^1.39.0",
42
+ "@vitejs/plugin-vue": "^5.2.1",
43
+ "@vueuse/core": "^10.11.0",
44
+ "@vueuse/gesture": "^2.0.0",
45
+ "date-fns": "^3.6.0",
46
+ "downsample": "^1.4.0",
47
+ "marked": "^18.0.11",
48
+ "pinia": "^2.3.0",
49
+ "vite": "^5.4.11",
50
+ "vue": "^3.5.13"
51
+ },
52
+ "engines": {
53
+ "node": ">=20"
54
+ },
55
+ "keywords": [
56
+ "beads",
57
+ "bd",
58
+ "gantt",
59
+ "scheduling",
60
+ "svg",
61
+ "planning"
62
+ ],
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "git+ssh://git@gitlab.com/incytestudios/beadcyte.git"
66
+ },
67
+ "homepage": "https://gitlab.com/incytestudios/beadcyte",
68
+ "bugs": {
69
+ "url": "https://gitlab.com/incytestudios/beadcyte/-/issues"
70
+ },
71
+ "license": "AGPL-3.0-only",
72
+ "devDependencies": {
73
+ "@tsconfig/node20": "^20.1.10",
74
+ "typescript": "~5.6.3",
75
+ "vue-tsc": "~2.1.10"
76
+ }
77
+ }