paperclip-plugin-plica 0.5.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/CHANGELOG.md +378 -0
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/dist/manifest.js +98 -0
- package/dist/ui/demo-data.json +4636 -0
- package/dist/ui/index.js +18634 -0
- package/dist/worker.js +31671 -0
- package/package.json +81 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Short-form. The reader-facing write-up for each version is in
|
|
4
|
+
[`docs/releases/`](docs/releases/).
|
|
5
|
+
|
|
6
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
## 0.5.0
|
|
9
|
+
|
|
10
|
+
- **Published to npm as `paperclip-plugin-plica`.** Install it from Paperclip's
|
|
11
|
+
Plugin Manager (**Install Plugin**, then the package name) or with
|
|
12
|
+
`paperclipai plugin install paperclip-plugin-plica`, and upgrade it with
|
|
13
|
+
`paperclipai plugin upgrade nickallevato.plugin-plica`. The package is
|
|
14
|
+
prebuilt, so there is nothing to clone or build. Installing from a git clone
|
|
15
|
+
with `--local` remains the development route.
|
|
16
|
+
- **Host-duplicate selectors are subtracted in the browser, not at build time.**
|
|
17
|
+
Plica's sheet is now Tailwind's whole output; at injection, Plica reads every
|
|
18
|
+
selector the page's other stylesheets define through the CSSOM and deletes its
|
|
19
|
+
own class rules the host already has, so a stray `.hidden` still cannot pin
|
|
20
|
+
Paperclip in its mobile layout. The build-time version subtracted against
|
|
21
|
+
whichever Paperclip UI build was on the builder's disk, which went stale on
|
|
22
|
+
every Paperclip upgrade and would have made a published package wrong for
|
|
23
|
+
everyone else's Paperclip.
|
|
24
|
+
- **Removed: the "Stylesheet stale" badge and `PLICA_HOST_CSS`.** With nothing
|
|
25
|
+
recorded at build time there is nothing to go stale, so the badge that warned
|
|
26
|
+
about it, the override that pointed the build at a host sheet, and
|
|
27
|
+
`scripts/host-css.mjs` are gone. The build no longer needs a Paperclip UI
|
|
28
|
+
build on disk.
|
|
29
|
+
- **Paperclip upgrades no longer need a Plica rebuild.** The one operational rule
|
|
30
|
+
in the README — rebuild Plica after every Paperclip upgrade, host first — no
|
|
31
|
+
longer applies, and one package no longer carries a particular Paperclip
|
|
32
|
+
version's stylesheet baked into it.
|
|
33
|
+
- **Plica reloads itself after an upgrade.** After a `git pull && pnpm build`
|
|
34
|
+
that bumps the version, a **Reload 0.x.y** chip appears in the header; one
|
|
35
|
+
click has Paperclip re-read the plugin from disk in place, where it used to
|
|
36
|
+
take a DevTools snippet. Instance admins only. A new version that adds a
|
|
37
|
+
capability shows **Reinstall needed** instead, since Paperclip only grants
|
|
38
|
+
capabilities on a fresh install.
|
|
39
|
+
- **"Recent" replaces the live strip.** The full-width row of pills across the
|
|
40
|
+
top of the page is gone; the left column now carries **Recent** — one line per
|
|
41
|
+
task, live ones first and newest first, with the same pulsing dot on the rows
|
|
42
|
+
an agent is on right now and the task's own status glyph on the rest. A row is
|
|
43
|
+
as wide as the column, so the ticket title fits, and a task that has just
|
|
44
|
+
finished stays in place instead of vanishing with its run. The list scrolls
|
|
45
|
+
inside a capped height, so a run starting cannot shove Portfolio or Routines
|
|
46
|
+
down the page.
|
|
47
|
+
- **Fixed: the board no longer overflows the viewport at phone width.** Recent's
|
|
48
|
+
rows were as wide as their untruncated ticket titles, which widened the
|
|
49
|
+
single-column grid past the window and clipped every pane in it on the right —
|
|
50
|
+
Orgs lost its runs/day and Need-you figures, and its header lost `need you`.
|
|
51
|
+
Every panel now has a floor of zero width, so the column is the window again
|
|
52
|
+
and the titles truncate.
|
|
53
|
+
|
|
54
|
+
## 0.4.0
|
|
55
|
+
|
|
56
|
+
### On a phone
|
|
57
|
+
|
|
58
|
+
- **Queue rows stay readable at phone width.** A row's actions drop to their
|
|
59
|
+
own line under the title instead of crushing it to "Budget…" and the meta to
|
|
60
|
+
one word per line; the Today / This week / Whenever picks come back there
|
|
61
|
+
instead of hiding.
|
|
62
|
+
|
|
63
|
+
### Decide by
|
|
64
|
+
|
|
65
|
+
- **"Orgs", not "companies"**, everywhere Plica labels them: the list, the
|
|
66
|
+
queue and portfolio grouping, the header ("all orgs").
|
|
67
|
+
|
|
68
|
+
- **The queue owns the page.** The wide company ledger is now a compact
|
|
69
|
+
**Orgs** list in the left column — name, who is working, runs per day,
|
|
70
|
+
and Need you — so the queue takes the main column. Every figure the ledger
|
|
71
|
+
showed (Questions, Blocked, Review, Open, Tokens, the run sparkline, the
|
|
72
|
+
lead agent) is in a card on hovering a company's name, with Watch and Open.
|
|
73
|
+
Narrow, the page stacks Orgs, the queue, then Portfolio and Routines.
|
|
74
|
+
|
|
75
|
+
- **The queue is grouped by when you'll decide.** Today, Unsorted, This week,
|
|
76
|
+
Alerts, Whenever and Snoozed replace Now / Soon / Later as the default
|
|
77
|
+
grouping (Severity is still one click away). The lanes come from Paperclip's
|
|
78
|
+
own decision triage, so a day set in Plica is the day Paperclip's Decisions
|
|
79
|
+
page shows.
|
|
80
|
+
- **Unsorted rows sort in one click**: Today · This week · Whenever sit inline.
|
|
81
|
+
- **Every row has a triage menu**: decide by, snooze (1 hour to a week), wake,
|
|
82
|
+
archive. Changes apply immediately and are rolled back with a toast if
|
|
83
|
+
Paperclip refuses them.
|
|
84
|
+
- **Snoozed items are away.** They sit folded in the Snoozed lane and nowhere
|
|
85
|
+
else, and they no longer count toward the Needs you badge.
|
|
86
|
+
- The header reads *N today (N overdue) · N unsorted · N snoozed*.
|
|
87
|
+
- The demo fixture now carries realistic triage (it used to store an instant
|
|
88
|
+
where Paperclip stores a preset or a date), and demo mode accepts the triage
|
|
89
|
+
and archive writes.
|
|
90
|
+
|
|
91
|
+
### A calmer board
|
|
92
|
+
|
|
93
|
+
- **Colour marks one thing per row.** The ledger's Questions, Blocked and
|
|
94
|
+
Review counts are plain ink now; only **Need you** carries ochre or brick.
|
|
95
|
+
Every nonzero count used to be ochre, so one question read as loudly as five
|
|
96
|
+
things waiting on you.
|
|
97
|
+
- **Critical rows in Now carry an edge, not a band.** A faint tint and a brick
|
|
98
|
+
edge replace the solid pink (maroon in dark mode) fill.
|
|
99
|
+
- **Moving work and good runs are sage, not neon.** Portfolio bars, the
|
|
100
|
+
sparkline and answered cards use Plica's new low-chroma `ok` colour.
|
|
101
|
+
- **Liveness is Paperclip's own blue**, the same one its nav dots and
|
|
102
|
+
in-progress icons use.
|
|
103
|
+
- **The ledger no longer clips its last column.** The totals row was padded
|
|
104
|
+
wider than the rows above it, which pushed the pin and open icons out of the
|
|
105
|
+
card. The sparkline now hides when the ledger is narrow rather than when the
|
|
106
|
+
window is, and the board stacks (ledger and queue first) when there isn't
|
|
107
|
+
room for both columns.
|
|
108
|
+
- **One toggle style.** Hot first / My order, Trouble / Company and the queue
|
|
109
|
+
grouping all draw like Paperclip's tabs.
|
|
110
|
+
- "Expected every every 1h" on an overdue heartbeat now reads "expected every 1h".
|
|
111
|
+
|
|
112
|
+
### Paperclip v2026.916.0
|
|
113
|
+
|
|
114
|
+
- **In-progress tasks draw Paperclip's new spinner glyph.** The host replaced the
|
|
115
|
+
rotate arrow with an open circle that turns (and holds still under reduced
|
|
116
|
+
motion);
|
|
117
|
+
Plica's copy of the glyph had fallen behind, so the same task looked
|
|
118
|
+
different in Plica and in Paperclip.
|
|
119
|
+
- **Links into `/tasks` and `/chats` keep their company.** Both are new
|
|
120
|
+
company-scoped routes; Plica did not know them, so a link into one could lose
|
|
121
|
+
its company prefix.
|
|
122
|
+
- **Dialogs respect reduced motion**, as Paperclip's now do.
|
|
123
|
+
- **`pnpm check:vendored`** reports any vendored host file that has drifted from
|
|
124
|
+
the Paperclip checkout. Nothing caught the two above until now.
|
|
125
|
+
|
|
126
|
+
### The mark
|
|
127
|
+
|
|
128
|
+
- **Plica has its own icon.** A sheet folded down its middle, seen end-on — a
|
|
129
|
+
*plica*, which reads flat as a caret. It replaces the two stock Lucide icons
|
|
130
|
+
that stood in for it: the Telescope on the breadcrumb-bar button and the
|
|
131
|
+
Layers glyph beside the page title. Both surfaces now show the same mark, so
|
|
132
|
+
the button in the host's chrome and the page it opens are recognisably the
|
|
133
|
+
same thing.
|
|
134
|
+
- Drawn as an SVG component rather than shipped as the supplied PNG, so it
|
|
135
|
+
inherits `currentColor` and tracks the text beside it through hover, light
|
|
136
|
+
mode and dark mode. The source artwork and its geometry are kept in
|
|
137
|
+
[`docs/brand/`](docs/brand/) for anyone who has to redraw it.
|
|
138
|
+
|
|
139
|
+
### The stylesheet coupling
|
|
140
|
+
|
|
141
|
+
- **Plica now warns when it needs rebuilding after a Paperclip upgrade.** Plica
|
|
142
|
+
filters its own utilities against Paperclip's compiled stylesheet once, at
|
|
143
|
+
build time; upgrade Paperclip and that filtering goes stale, and Plica's
|
|
144
|
+
leftover duplicates can override Paperclip's responsive rules and strand the
|
|
145
|
+
whole application in its mobile layout. The symptom shows up in Paperclip's
|
|
146
|
+
own chrome with nothing pointing at Plica, and the fix — `pnpm build` in the
|
|
147
|
+
Plica checkout — is not one anyone would guess. A **Stylesheet stale** badge
|
|
148
|
+
now appears in the Plica header, and its hover text names the fix and shows
|
|
149
|
+
the stylesheet Plica was built against next to the one currently loaded.
|
|
150
|
+
- **It stays quiet unless it is sure.** If the host's stylesheet cannot be
|
|
151
|
+
identified from the page, Plica shows nothing rather than a warning it cannot
|
|
152
|
+
stand behind. Nothing about rendering, data or demo mode changes either way.
|
|
153
|
+
|
|
154
|
+
### Documentation
|
|
155
|
+
|
|
156
|
+
- **A documentation set with real screenshots**, in [`docs/`](docs/): install,
|
|
157
|
+
configuration, the board, the queue, and troubleshooting. The README is now an
|
|
158
|
+
overview that hands off to them rather than the only page there is.
|
|
159
|
+
- Screenshots are **generated**, by `scripts/capture-screenshots.mjs`, from a
|
|
160
|
+
running instance in demo mode. Refreshing them after a UI change is one
|
|
161
|
+
command instead of a manual session with a cropping tool, which is the only
|
|
162
|
+
version of "keep the screenshots current" that survives contact with a
|
|
163
|
+
release. See [`docs/screenshots/README.md`](docs/screenshots/README.md).
|
|
164
|
+
- Removed the README's claim that a classic layout is available behind a toggle.
|
|
165
|
+
The classic views were retired in `e40e459`; the line documented a feature
|
|
166
|
+
that does not exist.
|
|
167
|
+
- `demoDataUrl` is now documented as accepted-and-ignored on the settings page.
|
|
168
|
+
It is declared in the manifest and rendered by the host, but nothing reads it.
|
|
169
|
+
- Corrected two `PLUGIN_SPEC.md §24` citations in `src/manifest.ts` and
|
|
170
|
+
`src/ui/host/api.ts`. §24 is *Operator UX*; the statement they lean on is in
|
|
171
|
+
the spec's *Current implementation caveats*.
|
|
172
|
+
- Marked the plugin-migration plan as completed and corrected its description of
|
|
173
|
+
what shipped — a `globalToolbarButton` slot, not a navigate launcher in the
|
|
174
|
+
sidebar zone.
|
|
175
|
+
|
|
176
|
+
## 0.3.0
|
|
177
|
+
|
|
178
|
+
### Demo mode
|
|
179
|
+
|
|
180
|
+
- **Plica can now serve the whole HUD from a bundled fixture instead of the
|
|
181
|
+
live instance**, so the page can be shown or screenshotted without exposing
|
|
182
|
+
real company names, ticket titles or agent narration. Four invented companies
|
|
183
|
+
with ~40 tickets, ~22 agents, live runs, an overdue routine and a company in
|
|
184
|
+
the red — sized so every surface has something to draw rather than reading as
|
|
185
|
+
an empty prototype.
|
|
186
|
+
- Two switches: `?demo=1` on the URL (sticky for the browser session, and
|
|
187
|
+
superseded as soon as the setting is changed) and a **Demo mode** checkbox
|
|
188
|
+
on the host's plugin settings page,
|
|
189
|
+
which Paperclip renders from the new `instanceConfigSchema` in the manifest.
|
|
190
|
+
Host plugin config is company-scoped and Plica is not, so the box ticked for
|
|
191
|
+
any one company turns the whole page into a demo.
|
|
192
|
+
- The substitution happens at one seam — `request()` in `src/ui/host/api.ts` —
|
|
193
|
+
which every read Plica performs already funnels through. No component knows
|
|
194
|
+
demo mode exists, and none can leak real data by forgetting about it. Writes
|
|
195
|
+
are intercepted too, so approving an approval or answering an interaction
|
|
196
|
+
works in a walkthrough without reaching the server.
|
|
197
|
+
- Fails closed. The page renders a placeholder until the mode is resolved and
|
|
198
|
+
an error if the fixture cannot be loaded, rather than showing real data for a
|
|
199
|
+
frame or falling back to it silently. A **Demo data** badge sits in the
|
|
200
|
+
header the whole time it is on.
|
|
201
|
+
- Addressed by the plugin's row UUID, looked up from `/api/plugins`. The
|
|
202
|
+
plugin-**key** form of the asset route 500s: its `getById` guard reads
|
|
203
|
+
`error.code` while drizzle puts the Postgres `22P02` on `error.cause`, so a
|
|
204
|
+
non-UUID id escapes the guard instead of falling through to `getByKey`.
|
|
205
|
+
- The fixture is a real file at `dist/ui/demo-data.json`, so renaming a company
|
|
206
|
+
is an edit and a reload. Structural changes go through
|
|
207
|
+
`scripts/gen-demo-data.mjs` (`pnpm demo:data`); a test asserts the two agree.
|
|
208
|
+
Timestamps are relative tokens resolved at page load, so the demo never reads
|
|
209
|
+
as months stale.
|
|
210
|
+
|
|
211
|
+
### Layout
|
|
212
|
+
|
|
213
|
+
- **Live now moved out of the rail and onto a strip across the top of the
|
|
214
|
+
board.** It was the one block whose height tracked the size of the fleet, so
|
|
215
|
+
every run that started or finished shoved the lists below it down the page.
|
|
216
|
+
As a single row of pills its height cannot change at all, and nothing below
|
|
217
|
+
it ever moves. Running agents are a glance, not a list you work through.
|
|
218
|
+
- Each run is now a pill: company, ticket, agent, elapsed. The title and the
|
|
219
|
+
agent's narration moved into the hover, where they cannot wrap a pill onto a
|
|
220
|
+
second line and change the strip's height.
|
|
221
|
+
- No cap and no "+N more" line — the row scrolls sideways, so the header count
|
|
222
|
+
and what you can reach always agree.
|
|
223
|
+
- The rail is a sticky column **capped** at the viewport rather than pinned to
|
|
224
|
+
a fixed height. The fixed height had to guess how much chrome sat above it
|
|
225
|
+
and guessed high, which pushed Routines off the bottom of the screen.
|
|
226
|
+
Routines is now `shrink-0`: it is the one thing that can never be squeezed
|
|
227
|
+
out of view, and Portfolio scrolls inside itself only once the column would
|
|
228
|
+
otherwise overflow.
|
|
229
|
+
|
|
230
|
+
### Portfolio (was Projects)
|
|
231
|
+
|
|
232
|
+
- The projects rail is now a chart, not a list. The folds, the company
|
|
233
|
+
grouping, the `most open` / `least open` sort and the per-project deep links
|
|
234
|
+
are gone — what people actually read off that rail was the shape of the bars,
|
|
235
|
+
and the rows were not being clicked.
|
|
236
|
+
- One bar per project across every company, **scaled to the largest project**
|
|
237
|
+
so lengths compare down the column rather than only within a row. Three
|
|
238
|
+
segments now: moving, **waiting**, blocked — waiting is the untouched
|
|
239
|
+
remainder the old two-segment bar left as bare track and therefore never
|
|
240
|
+
named.
|
|
241
|
+
- Ordered worst-first (latest overdue → most stuck → biggest), not by deadline.
|
|
242
|
+
A chart read at a glance must put the worst bar under the eye first.
|
|
243
|
+
- **Trouble / By company** toggle in the header, persisted in
|
|
244
|
+
`plica.portfolioSort`. Company order follows the board's own — watched first,
|
|
245
|
+
then hot-first or the sidebar order — so a company sits in the same place in
|
|
246
|
+
both panes, and the worst project still leads inside each company. Gathering
|
|
247
|
+
the bars is the only way to see that one company's whole portfolio is stuck,
|
|
248
|
+
which trouble-order scatters down the column.
|
|
249
|
+
- In company order each block is headed by the company's name and its own
|
|
250
|
+
open / blocked / late figures. The header is **sticky**, because a block can
|
|
251
|
+
be taller than the pane and scrolling past the name would leave a run of bars
|
|
252
|
+
with nothing saying whose they are. The per-row company icon drops away in
|
|
253
|
+
that mode — the header already answers it — and stays in Trouble order, where
|
|
254
|
+
consecutive bars have no shared owner to head.
|
|
255
|
+
- `plica.projectGrouping` and `plica.projectSort` retired; both are cleared on
|
|
256
|
+
load with the other legacy keys.
|
|
257
|
+
|
|
258
|
+
### Routines
|
|
259
|
+
|
|
260
|
+
- Replaced the week's timetable with **exceptions only**: failed, wedged on a
|
|
261
|
+
blocked issue, or overdue. A schedule you can predict is not information —
|
|
262
|
+
the old list spent its whole height saying twenty routines would fire on
|
|
263
|
+
time and gave the two that broke the same weight as the rest.
|
|
264
|
+
- Healthy routines are a count in the footer. When everything is healthy the
|
|
265
|
+
block is one reassuring line; with no routines at all it says so distinctly.
|
|
266
|
+
- A routine that both failed and ran late is one problem, filed under the
|
|
267
|
+
failure, which is the half that says why.
|
|
268
|
+
|
|
269
|
+
### Needs you
|
|
270
|
+
|
|
271
|
+
- Age filter chips in the rail header: **All / Today / Yesterday / Last week /
|
|
272
|
+
Old**, persisted in `plica.queueAgeFilter`. A rail carrying a hundred-odd
|
|
273
|
+
items is a wall you stop reading, and the oldest things on it are the least
|
|
274
|
+
likely to still matter.
|
|
275
|
+
- Buckets are **calendar days cut at local midnight**, not rolling hours — an
|
|
276
|
+
item raised at 9pm last night is yesterday's at 8am today. The Age *grouping*
|
|
277
|
+
now uses the same buckets, so the two can never disagree about which pile an
|
|
278
|
+
item is in.
|
|
279
|
+
- Each chip carries the count of the **unfiltered** queue, so an empty bucket
|
|
280
|
+
is distinguishable from a hidden one. Empty buckets stay visible but disabled
|
|
281
|
+
rather than disappearing, so the chips never move under the cursor as items
|
|
282
|
+
age past midnight.
|
|
283
|
+
- Under an age filter, **Later starts open**: narrowing to "Old" is an explicit
|
|
284
|
+
request for that slice, and a rail whose only match is folded away reads as
|
|
285
|
+
empty.
|
|
286
|
+
- The rail's badge and "oldest" now describe what is on screen, not the queue
|
|
287
|
+
behind the filter.
|
|
288
|
+
- Age sort remains a toggle in the rail header (`oldest` / `newest`), persisted
|
|
289
|
+
in `plica.queueSort`. Severity still decides the order first — the toggle only
|
|
290
|
+
flips which of two equally urgent items leads, so grouping by Severity with
|
|
291
|
+
newest first works as one view.
|
|
292
|
+
- Every group in the rail folds from its header, not just Later.
|
|
293
|
+
|
|
294
|
+
### Internal
|
|
295
|
+
|
|
296
|
+
- `PlicaListControls` factored out of the queue's own header. `PlicaFoldGroup`
|
|
297
|
+
and `PlicaCompanyGroup` are gone with the rail they served — the Portfolio
|
|
298
|
+
chart and the routine exceptions have nothing to fold.
|
|
299
|
+
- The projects rail's grouping and sorting helpers (`groupProjects`,
|
|
300
|
+
`compareProjectEntries`, `projectDueBucket`, `projectHealth`) removed with it;
|
|
301
|
+
a chart ordered worst-first has nothing left for them to choose between.
|
|
302
|
+
- Test timezone pinned to UTC. The queue's age buckets cut at *local* midnight
|
|
303
|
+
by design, so the suite has to agree on which local.
|
|
304
|
+
|
|
305
|
+
### Project
|
|
306
|
+
|
|
307
|
+
- **Requests have one path now**, written down in `docs/intake.md`: capture,
|
|
308
|
+
deduplicate, clarify, scope, propose a priority, build, review, merge,
|
|
309
|
+
changelog. Two steps are the repository owner's — the priority band and the
|
|
310
|
+
merge — and the document says so rather than leaving it to be discovered.
|
|
311
|
+
- Three issue templates (feature request, bug report, core limitation) produce
|
|
312
|
+
the *Problem / Proposed scope / Acceptance criteria / Open questions* shape
|
|
313
|
+
triage needs, so triage fills gaps instead of restructuring prose. Blank
|
|
314
|
+
issues stay enabled on purpose.
|
|
315
|
+
- The **core limitation** template is the sanctioned exit from the
|
|
316
|
+
no-core-changes rule and the only one: it asks which extension point comes
|
|
317
|
+
closest, why it falls short, and what Plica ships in the meantime — then parks
|
|
318
|
+
the work for the owner rather than routing around core.
|
|
319
|
+
- A state label is now mandatory on every issue, because an issue with no state
|
|
320
|
+
label is the one failure mode nothing else in this repository has an alarm on.
|
|
321
|
+
|
|
322
|
+
## 0.2.0
|
|
323
|
+
|
|
324
|
+
### Board
|
|
325
|
+
|
|
326
|
+
- Rebuilt the company ledger around what is waiting on you. Columns are now
|
|
327
|
+
`Need you · Questions · Blocked · Review · Open · Runs/d · Tokens`, with the
|
|
328
|
+
first four counted off the attention feed so they can never disagree with
|
|
329
|
+
their own total. Routines and Spend columns dropped — routines duplicate the
|
|
330
|
+
rail beside the board, and dollars were the least actionable figure on the row.
|
|
331
|
+
- **Capacity strip** replaces the old `0 / 4` count: one square per agent, in
|
|
332
|
+
org order (chief first, each manager followed by their reports), showing
|
|
333
|
+
working / queued / stalled / error / idle. A run that holds a runner while
|
|
334
|
+
reporting nothing for 20 minutes now reads as stalled — previously invisible.
|
|
335
|
+
- Agents that cannot take work (paused, terminated, pending approval) no longer
|
|
336
|
+
occupy squares; drawing them as idle overstated available capacity.
|
|
337
|
+
- Heat is computed and used to order the board, and deliberately never drawn.
|
|
338
|
+
- SCADA-influenced palette: `--plica-live` / `--plica-wait` / `--plica-alarm` /
|
|
339
|
+
`--plica-rest`, low-chroma, one meaning each. Company brand colour is the only
|
|
340
|
+
saturated thing on the board and never encodes a value.
|
|
341
|
+
- Header totals removed, along with the per-company summary fan-out behind them.
|
|
342
|
+
|
|
343
|
+
### Rails
|
|
344
|
+
|
|
345
|
+
- Routines and Projects group by company, following the board's own company
|
|
346
|
+
order, each foldable to a one-line summary. No more `+n more` truncation.
|
|
347
|
+
- Routines read in calendar order, Sunday through Saturday, and colour by where
|
|
348
|
+
each sits in its cycle: warming toward live over the day before it fires, live
|
|
349
|
+
for the hour it runs, then straight back to rest.
|
|
350
|
+
- Every routine carries an outcome mark for its last run (ok / blocked / failed /
|
|
351
|
+
working / skipped) that links to the issue that stopped it.
|
|
352
|
+
|
|
353
|
+
### Fixed
|
|
354
|
+
|
|
355
|
+
- **Host navigation could wedge while Plica was open** — the URL changed and the
|
|
356
|
+
view never followed. `needsBreakdown` was rebuilt on every render while sitting
|
|
357
|
+
in an effect dependency array, producing a render loop that starved React
|
|
358
|
+
Router 7's `startTransition`. Memoised, and every `?? []` fallback in the same
|
|
359
|
+
hook replaced with shared constants to close the whole class.
|
|
360
|
+
- Radix modal dialogs unmounted by a queue refresh could strand
|
|
361
|
+
`pointer-events: none` on `<body>`, disabling every click in the app.
|
|
362
|
+
|
|
363
|
+
### Performance
|
|
364
|
+
|
|
365
|
+
- Polls paced per dataset (5s live, 15s approvals, 30s agents, 60s issues and
|
|
366
|
+
projects) instead of everything at 5s, and none refetch in a hidden tab. The
|
|
367
|
+
issue list — the heaviest payload on the page — was being refetched twelve
|
|
368
|
+
times a minute per company.
|
|
369
|
+
- Dropped the sidebar-badges query entirely; nothing had rendered it since the
|
|
370
|
+
Inbox column came out.
|
|
371
|
+
|
|
372
|
+
### Removed
|
|
373
|
+
|
|
374
|
+
- The CEO nudge. An overdue heartbeat now offers "Open CEO" instead.
|
|
375
|
+
|
|
376
|
+
## 0.1.0
|
|
377
|
+
|
|
378
|
+
Initial release.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nick Allevato
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Plica
|
|
2
|
+
|
|
3
|
+
A cross-org HUD for [Paperclip](https://github.com/paperclipai/paperclip). One page that
|
|
4
|
+
answers "what needs me, across every org, right now" — and lets you say *when* you will deal
|
|
5
|
+
with each thing — instead of visiting each org's dashboard in turn.
|
|
6
|
+
|
|
7
|
+
Plica is UI-only. It contributes one page (mounted at `/:companyPrefix/plica`) and a toolbar
|
|
8
|
+
launcher that navigates there. Its worker is a deliberate no-op.
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
> Every screenshot in this repository is Plica's own [demo mode](docs/configuration.md#demo-mode) —
|
|
13
|
+
> invented orgs, tickets and agents, not a real instance. Try it on your own install: add
|
|
14
|
+
> `?demo=1` to the Plica page's URL (e.g. `/ACME/plica?demo=1`). Nothing you click in demo mode
|
|
15
|
+
> reaches the server.
|
|
16
|
+
|
|
17
|
+
**Documentation:** [install](docs/install.md) · [configuration](docs/configuration.md) ·
|
|
18
|
+
[the board](docs/board.md) · [the queue](docs/queue.md) ·
|
|
19
|
+
[troubleshooting](docs/troubleshooting.md) · [release notes](docs/releases/)
|
|
20
|
+
|
|
21
|
+
## What it shows
|
|
22
|
+
|
|
23
|
+
**Queue** — the main column. Every item across every org that wants a human, in one list:
|
|
24
|
+
approvals, questions and confirmations awaiting a response, blockers, failed runs, overdue
|
|
25
|
+
heartbeats and routine exceptions. Actions are inline — Approve, Reject, Reply — so you rarely
|
|
26
|
+
need to open the org.
|
|
27
|
+
|
|
28
|
+
By default it groups by **when you said you'd decide**: Today (and anything overdue), Unsorted,
|
|
29
|
+
This week, Alerts, Whenever and Snoozed. New items land in Unsorted with **Today · This week ·
|
|
30
|
+
Whenever** right on the row, and every row has a menu to set a day, snooze or archive it. These
|
|
31
|
+
are Paperclip's own decision-triage records, so a day set in Plica is the day Paperclip's
|
|
32
|
+
Decisions page shows — and it works on stock Paperclip, through its existing web API.
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
It can also group by severity, org, kind, project or age — by project is how you find the one
|
|
37
|
+
project quietly generating half the noise.
|
|
38
|
+
|
|
39
|
+
**Orgs** — the left column: one line per org with who is working, runs per day and how much is
|
|
40
|
+
waiting on you. Hover a name for everything else (questions, blockers, review, open work, token
|
|
41
|
+
burn, a sparkline of recent runs, the lead agent). Orgs can be watched, sorted by heat, and
|
|
42
|
+
clicked to filter the queue.
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
Each org's capacity is a row of squares, one per agent — working, stalled, queued, errored or
|
|
47
|
+
idle. Hovering one says who it is and what they are actually doing, which is the thing a bare
|
|
48
|
+
"3 running" count cannot tell you.
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
**Portfolio and Routines** — projects by how much is moving, waiting or blocked, and the
|
|
53
|
+
routines that failed or stopped firing.
|
|
54
|
+
|
|
55
|
+
**Briefing** — what changed since your last visit.
|
|
56
|
+
|
|
57
|
+
**On a phone** — the page stacks Orgs, the queue, then Portfolio and Routines, and each queue
|
|
58
|
+
row puts its actions on a line of their own.
|
|
59
|
+
|
|
60
|
+
<img src="docs/screenshots/phone.png" alt="Plica at phone width: the Orgs list above the queue" width="320">
|
|
61
|
+
|
|
62
|
+
Full tours: [the board](docs/board.md), [the queue](docs/queue.md).
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
Plica is published to npm as `paperclip-plugin-plica`. In Paperclip, open the **Plugin
|
|
67
|
+
Manager** (Settings → Plugins, at `/company/settings/instance/plugins`), click **Install
|
|
68
|
+
Plugin**, and enter `paperclip-plugin-plica` as the **npm Package Name**. Or from the CLI:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx paperclipai plugin install paperclip-plugin-plica
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Either way needs an instance admin. The package is prebuilt and carries nothing tied to a
|
|
75
|
+
particular Paperclip build, so upgrading Paperclip later needs nothing from Plica.
|
|
76
|
+
|
|
77
|
+
### From source
|
|
78
|
+
|
|
79
|
+
For working on Plica, install it from a clone instead:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/nickallevato/paperclip-plica.git
|
|
83
|
+
cd paperclip-plica
|
|
84
|
+
pnpm install
|
|
85
|
+
pnpm build
|
|
86
|
+
npx paperclipai plugin install /absolute/path/to/paperclip-plica --local
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
[docs/install.md](docs/install.md) covers both routes: upgrading, the directory layout a clone
|
|
90
|
+
needs for its `link:` dependencies, and how to check the plugin actually loaded.
|
|
91
|
+
|
|
92
|
+
## Demo mode
|
|
93
|
+
|
|
94
|
+
Plica can serve the whole HUD from a bundled fixture instead of your instance, so the page can
|
|
95
|
+
be screenshotted or demoed without putting real company names, ticket titles or agent chatter
|
|
96
|
+
on screen. Turn it on with `?demo=1` or the **Demo mode** checkbox on the plugin's settings
|
|
97
|
+
page; the header carries a **DEMO DATA** badge the whole time it is on. It fails closed — a
|
|
98
|
+
fixture that will not load is an error, never a silent fall back to real data.
|
|
99
|
+
|
|
100
|
+
Details, including how to edit the fixture:
|
|
101
|
+
[docs/configuration.md](docs/configuration.md#demo-mode).
|
|
102
|
+
|
|
103
|
+
The screenshots in `docs/screenshots/` are demo mode with nothing else done to them, captured by
|
|
104
|
+
`scripts/capture-screenshots.mjs`. See [docs/screenshots/README.md](docs/screenshots/README.md).
|
|
105
|
+
|
|
106
|
+
## Why Plica subtracts the host's selectors
|
|
107
|
+
|
|
108
|
+
Plica compiles its own Tailwind sheet and injects it via `<style>` appended to `<head>` — after
|
|
109
|
+
the host's. Tailwind emits every class it scans, including ones Paperclip already defines, and a
|
|
110
|
+
duplicate that lands later wins on document order. A stray `.hidden{display:none}` is enough to
|
|
111
|
+
beat Paperclip's `@media(min-width:40rem){.sm\:flex{...}}` and pin the whole app — not just the
|
|
112
|
+
Plica page — in its mobile layout.
|
|
113
|
+
|
|
114
|
+
Ordering cannot fix this, in either direction. Appended last, Plica's duplicates beat the host's
|
|
115
|
+
responsive variants. Inserted first, Plica's `@layer` declarations come before the host's, which
|
|
116
|
+
pushes the host's `base`/`components` layers after `utilities` and breaks spacing app-wide.
|
|
117
|
+
Subtraction is the only approach that works.
|
|
118
|
+
|
|
119
|
+
So at injection, `src/ui/styles.ts` walks the document's other stylesheets through the CSSOM,
|
|
120
|
+
collects every selector they define, and deletes each of Plica's class rules the host already
|
|
121
|
+
has — trimming shared selector lists and dropping `@media`/`@layer`/`@supports` groups left
|
|
122
|
+
empty (`src/ui/lib/host-subtract.ts`). Against Paperclip's real sheet that drops about 480
|
|
123
|
+
selectors; Plica-only classes are untouched. Cross-origin sheets, which the browser will not let
|
|
124
|
+
a page read, are skipped — they are web-font CSS, not host utilities.
|
|
125
|
+
|
|
126
|
+
This used to be done once, at build time, against whichever Paperclip UI build was on the
|
|
127
|
+
builder's disk — which went stale on every Paperclip upgrade and meant rebuilding Plica after
|
|
128
|
+
each one. Subtracting against the sheets the page actually loaded leaves nothing to go stale: a
|
|
129
|
+
Paperclip upgrade needs no Plica rebuild, the build needs no Paperclip UI build, and one
|
|
130
|
+
published package fits whichever Paperclip stylesheet it lands next to.
|
|
131
|
+
|
|
132
|
+
## Vendored host components
|
|
133
|
+
|
|
134
|
+
`src/ui/host/` holds read-only copies of Paperclip internals Plica depends on — the ui-kit
|
|
135
|
+
primitives, `useCompanyOrder`, API client shapes. They are copies rather than imports because
|
|
136
|
+
Paperclip does not export them to plugins.
|
|
137
|
+
|
|
138
|
+
Keep them byte-identical to their upstream originals apart from import paths. Three documented
|
|
139
|
+
exceptions:
|
|
140
|
+
|
|
141
|
+
- `ui-kit/dialog.tsx` — plain Tailwind positioning, since the host's version leans on theme-only
|
|
142
|
+
CSS variables the plugin sheet does not carry.
|
|
143
|
+
- `useCompanyOrder.ts` — read path only; the host's mutation and `persistOrder` are omitted
|
|
144
|
+
because Plica never reorders.
|
|
145
|
+
- `ui-kit/hover-card.tsx` — a Plica original, not a copy. The host ships no HoverCard component,
|
|
146
|
+
so there is nothing upstream to keep it identical to.
|
|
147
|
+
|
|
148
|
+
Anything else that drifts is a bug. `CompanyPatternIcon.tsx` in particular must match exactly:
|
|
149
|
+
Paperclip draws company avatars with its own copy, so any change here gives one company two
|
|
150
|
+
different identities on screen.
|
|
151
|
+
|
|
152
|
+
`pnpm check:vendored` compares every whole-file copy (and the route-root sets in `util.ts`)
|
|
153
|
+
against the Paperclip checkout, ignoring imports. Run it after each Paperclip upgrade;
|
|
154
|
+
`--diff` prints what moved.
|
|
155
|
+
|
|
156
|
+
## Development
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
pnpm dev # esbuild watch + CSS rebuild
|
|
160
|
+
pnpm test # vitest — needs a prior `pnpm build` on a fresh clone
|
|
161
|
+
pnpm typecheck # tsc --noEmit
|
|
162
|
+
pnpm build # CSS then bundle
|
|
163
|
+
pnpm check:surface # the no-core-changes guardrail
|
|
164
|
+
pnpm hooks:install # pre-commit: surface check, typecheck, test
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Tests run in jsdom, which implements neither `HTMLCanvasElement.getContext` nor navigation. Both
|
|
168
|
+
log "Not implemented" errors during a passing run. That output is expected noise, not failure —
|
|
169
|
+
check the summary line.
|
|
170
|
+
|
|
171
|
+
## Layout
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
src/
|
|
175
|
+
manifest.ts plugin id, capabilities, entrypoints
|
|
176
|
+
worker.ts no-op
|
|
177
|
+
ui/
|
|
178
|
+
PlicaHud.tsx root: owns the roster, sort mode, pins, token settings
|
|
179
|
+
PlicaPage.tsx host-mounted page slot
|
|
180
|
+
PlicaToolbarButton.tsx toolbar launcher
|
|
181
|
+
components/ company lines, queue, recent tasks, portfolio, briefing
|
|
182
|
+
lib/ capacity, queue grouping, run derivation, drafts
|
|
183
|
+
host/ vendored Paperclip internals (read-only)
|
|
184
|
+
styles.ts injects the compiled sheet, minus host duplicates, idempotently
|
|
185
|
+
scripts/
|
|
186
|
+
build-css.mjs Tailwind compile (host duplicates are subtracted at runtime)
|
|
187
|
+
capture-screenshots.mjs the images in docs/, from a running instance
|
|
188
|
+
gen-demo-data.mjs the demo fixture
|
|
189
|
+
check-plugin-surface.mjs the no-core-changes guardrail
|
|
190
|
+
docs/ the documentation set
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Reporting a bug, or asking for a feature
|
|
194
|
+
|
|
195
|
+
Open an issue from one of the three templates — feature request, bug report, or
|
|
196
|
+
core limitation. [docs/intake.md](docs/intake.md) is the whole path a request
|
|
197
|
+
takes from there to a merged change, including the two points where the
|
|
198
|
+
repository owner decides: the priority band, and the merge.
|
|
199
|
+
|
|
200
|
+
You will get an answer either way. A request that turns out to be a duplicate is
|
|
201
|
+
closed pointing at the original and its evidence is moved there first; one that
|
|
202
|
+
is real but not now is *parked*, not closed, and reopens on a sentence.
|
|
203
|
+
|
|
204
|
+
## Contributing
|
|
205
|
+
|
|
206
|
+
[CONTRIBUTING.md](CONTRIBUTING.md). The rule to read before anything else:
|
|
207
|
+
**Plica never modifies Paperclip core.** Everything lands here, through a plugin
|
|
208
|
+
extension point. If the plugin surface cannot express a change, file it as a
|
|
209
|
+
core limitation rather than working around it — CI enforces this, with no bypass.
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT
|