@plurnk/plurnk-web 0.0.0-stage → 1.1.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/LICENSE +21 -0
- package/README.md +337 -2
- package/SPEC.md +869 -0
- package/ai.plurnk/.env.defaults +38 -0
- package/ai.plurnk/assets.json +193 -0
- package/ai.plurnk/creations.js +65 -0
- package/ai.plurnk/diagram-compiler.js +15 -0
- package/ai.plurnk/diagrams.js +130 -0
- package/ai.plurnk/directory-addresses.js +35 -0
- package/ai.plurnk/dist/assets/Temml-CCjoacWt.woff2 +0 -0
- package/ai.plurnk/dist/assets/index-B4w6iDKw.css +1 -0
- package/ai.plurnk/dist/assets/index-B4w6iDKw.css.br +0 -0
- package/ai.plurnk/dist/assets/index-B4w6iDKw.css.gz +0 -0
- package/ai.plurnk/dist/assets/index-CGRGblLU.js +2 -0
- package/ai.plurnk/dist/assets/index-CGRGblLU.js.br +0 -0
- package/ai.plurnk/dist/assets/index-CGRGblLU.js.gz +0 -0
- package/ai.plurnk/dist/assets/math-renderer-CZ_XtOMq.css +1 -0
- package/ai.plurnk/dist/assets/math-renderer-CZ_XtOMq.css.br +0 -0
- package/ai.plurnk/dist/assets/math-renderer-CZ_XtOMq.css.gz +0 -0
- package/ai.plurnk/dist/assets/math-renderer-CnlgS6FH.js +96 -0
- package/ai.plurnk/dist/assets/math-renderer-CnlgS6FH.js.br +0 -0
- package/ai.plurnk/dist/assets/math-renderer-CnlgS6FH.js.gz +0 -0
- package/ai.plurnk/dist/assets/overview-DEhW9HUG.js +1 -0
- package/ai.plurnk/dist/assets/overview-DEhW9HUG.js.br +0 -0
- package/ai.plurnk/dist/assets/overview-DEhW9HUG.js.gz +0 -0
- package/ai.plurnk/dist/assets/preload-helper-BjS5LQBu.js +1 -0
- package/ai.plurnk/dist/assets/preload-helper-BjS5LQBu.js.br +0 -0
- package/ai.plurnk/dist/assets/preload-helper-BjS5LQBu.js.gz +0 -0
- package/ai.plurnk/dist/assets/session-BcdGbgAa.js +4 -0
- package/ai.plurnk/dist/assets/session-BcdGbgAa.js.br +0 -0
- package/ai.plurnk/dist/assets/session-BcdGbgAa.js.gz +0 -0
- package/ai.plurnk/dist/assets/session-agent-DwY8S586.js +111 -0
- package/ai.plurnk/dist/assets/session-agent-DwY8S586.js.br +0 -0
- package/ai.plurnk/dist/assets/session-agent-DwY8S586.js.gz +0 -0
- package/ai.plurnk/dist/assets/src-Du01yeMu.js +1 -0
- package/ai.plurnk/dist/assets/src-Du01yeMu.js.br +0 -0
- package/ai.plurnk/dist/assets/src-J2qT9xpv.js +6 -0
- package/ai.plurnk/dist/assets/src-J2qT9xpv.js.br +0 -0
- package/ai.plurnk/dist/assets/src-J2qT9xpv.js.gz +0 -0
- package/ai.plurnk/dist/icons/APACHE-2.0.txt +202 -0
- package/ai.plurnk/dist/icons/APACHE-2.0.txt.br +0 -0
- package/ai.plurnk/dist/icons/APACHE-2.0.txt.gz +0 -0
- package/ai.plurnk/dist/icons/NOTO-NOTICE.txt +10 -0
- package/ai.plurnk/dist/icons/NOTO-NOTICE.txt.br +0 -0
- package/ai.plurnk/dist/icons/NOTO-NOTICE.txt.gz +0 -0
- package/ai.plurnk/dist/icons/plurnk-maskable.svg +64 -0
- package/ai.plurnk/dist/icons/plurnk-maskable.svg.br +0 -0
- package/ai.plurnk/dist/icons/plurnk-maskable.svg.gz +0 -0
- package/ai.plurnk/dist/icons/plurnk.svg +63 -0
- package/ai.plurnk/dist/icons/plurnk.svg.br +0 -0
- package/ai.plurnk/dist/icons/plurnk.svg.gz +0 -0
- package/ai.plurnk/dist/index.html +421 -0
- package/ai.plurnk/dist/manifest.webmanifest +27 -0
- package/ai.plurnk/dist/manifest.webmanifest.br +0 -0
- package/ai.plurnk/dist/manifest.webmanifest.gz +0 -0
- package/ai.plurnk/dist/vendor/CFWORKER-JSON-SCHEMA-LICENSE.txt +25 -0
- package/ai.plurnk/dist/vendor/CFWORKER-JSON-SCHEMA-LICENSE.txt.br +0 -0
- package/ai.plurnk/dist/vendor/CFWORKER-JSON-SCHEMA-LICENSE.txt.gz +0 -0
- package/ai.plurnk/dist/vendor/DEPENDENCIES-LICENSE.txt +571 -0
- package/ai.plurnk/dist/vendor/DEPENDENCIES-LICENSE.txt.br +0 -0
- package/ai.plurnk/dist/vendor/DEPENDENCIES-LICENSE.txt.gz +0 -0
- package/ai.plurnk/dist/vendor/MARKED-FOOTNOTE-LICENSE.txt +25 -0
- package/ai.plurnk/dist/vendor/MARKED-FOOTNOTE-LICENSE.txt.br +0 -0
- package/ai.plurnk/dist/vendor/MARKED-FOOTNOTE-LICENSE.txt.gz +0 -0
- package/ai.plurnk/dist/vendor/OTM-LICENSE.txt +21 -0
- package/ai.plurnk/dist/vendor/OTM-LICENSE.txt.br +0 -0
- package/ai.plurnk/dist/vendor/OTM-LICENSE.txt.gz +0 -0
- package/ai.plurnk/dist/vendor/PICO-LICENSE.txt +21 -0
- package/ai.plurnk/dist/vendor/PICO-LICENSE.txt.br +0 -0
- package/ai.plurnk/dist/vendor/PICO-LICENSE.txt.gz +0 -0
- package/ai.plurnk/documents.js +483 -0
- package/ai.plurnk/http.js +69 -0
- package/ai.plurnk/index-document.js +5 -0
- package/ai.plurnk/module.js +326 -0
- package/ai.plurnk/session.js +319 -0
- package/ai.plurnk/static-assets.js +40 -0
- package/package.json +92 -5
- package/plugin.json +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Plurnk contributors
|
|
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
CHANGED
|
@@ -1,3 +1,338 @@
|
|
|
1
|
-
#
|
|
1
|
+
# plurnk-web
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Plurnk daemon plugin serving native OTM documents at `/`.
|
|
4
|
+
Pico Classless Green supplies the styling, with #148800 brand accents and system
|
|
5
|
+
monospace typography. It follows the browser's light/dark preference.
|
|
6
|
+
Conversation cards use a subtle green user tint, ordinary cards for model replies,
|
|
7
|
+
and neutral backgrounds for operations, notes and reasoning.
|
|
8
|
+
Requires a current stable browser; no legacy-browser compatibility layer is shipped.
|
|
9
|
+
No additional server. When signed in (or on an anonymous daemon), the root `/`
|
|
10
|
+
shows a live daemon-wide session overview ordered by most recent delivered reply,
|
|
11
|
+
and links to the daemon's workspace directory at `/~/`; workspace pages show the
|
|
12
|
+
same live session overview for that workspace, with native collapsed child
|
|
13
|
+
branches, on-demand completed-reply disclosures and a “Background work” section
|
|
14
|
+
for branches beneath internal actors. Bookkeeping sessions are omitted. Session pages show identity,
|
|
15
|
+
breadcrumbs, their actual parent, live status and conversation, without a
|
|
16
|
+
duplicate page heading. A native message form sends text; Stop explicitly cancels
|
|
17
|
+
the session's current work. Pending operations have native Accept/Reject review forms;
|
|
18
|
+
questions and MCP input share the same review and resume path.
|
|
19
|
+
The message box also accepts `/help`, `/models [search]`, `/model [selector] [effort]`,
|
|
20
|
+
`/effort [policy]`, `/capabilities [json]`, `/yolo`, and `/stop`. Commands never go
|
|
21
|
+
to the model: their results appear separately from conversation. Model, effort
|
|
22
|
+
and capability changes use daemon actions and retain its validation and active-work
|
|
23
|
+
restrictions. `/capabilities` shows service, workspace and effective policy; a JSON
|
|
24
|
+
argument replaces the workspace policy. `/yolo` or the 🔥/🐹 status toggle changes only this page's automatic
|
|
25
|
+
approval preference, including pending proposals; questions still require answers.
|
|
26
|
+
Reload restores the page's starting mode. Commands remain available during pending review.
|
|
27
|
+
`/models` lists aliases and a bounded catalog page; narrow its search for more matches.
|
|
28
|
+
Click the status model or effort to open its form below the conversation. Model
|
|
29
|
+
search offers native suggestions, or accepts an exact alias/provider-model.
|
|
30
|
+
Select Model / Select Effort applies the choice and closes the form; Cancel dismisses it.
|
|
31
|
+
Session cards on `/` and workspace pages show the session's lifecycle, parent/name
|
|
32
|
+
and workspace, ordered with the most recently delivered reply first, and stay live
|
|
33
|
+
over the ACP overview subscription while preserving open disclosures.
|
|
34
|
+
Click the ant to visit the session, or expand the card to see its child tree and
|
|
35
|
+
latest completed reply (loaded on demand when opened); parent and workspace links
|
|
36
|
+
navigate independently. Leaves without a completed reply have no empty disclosure.
|
|
37
|
+
The workspace list marks folderless workspaces with ☁️ and folder-backed ones with 🗂️.
|
|
38
|
+
On a workspace page, matching workspace/folder labels share one 🗂️ breadcrumb;
|
|
39
|
+
differing labels keep ☁️ on the workspace name and show 🗂️ on a separate folder line.
|
|
40
|
+
Folder labels use the daemon's home abbreviation, not the browser's.
|
|
41
|
+
The workspace list, workspace pages and session pages offer native header actions alongside the breadcrumbs:
|
|
42
|
+
- On `/~/`: `🗃️` followed by `➕` opens a native `<dialog>` modal to create a new folderless workspace; left unnamed, the daemon names it ({§web-workspace-creation}).
|
|
43
|
+
- On `/<workspace>/`: `🗃️` › `☁️ <workspace>` followed by `✏️`, `🗑️` and `➕` open native `<dialog>` modals to rename the current workspace ({§web-workspace-rename}), archive the workspace ({§web-workspace-archive}), or create an independent model session; left unnamed, the daemon names it ({§web-session-creation}).
|
|
44
|
+
- On `/<workspace>@<session>/`: breadcrumb navigation carries `🗑️` to archive the session and its descendants ({§web-session-archive}).
|
|
45
|
+
Modals offer Cancel and Confirm, dismiss on Escape or backdrop click without mutating state, and render in normal flow at the end of `<main>` when JavaScript is disabled; with JavaScript a closed modal shows nothing.
|
|
46
|
+
Creation forms carry a hidden token so a retried submission converges on the created place instead of re-executing.
|
|
47
|
+
Anonymous daemons refuse cross-site form posts, but a page that makes the browser reach
|
|
48
|
+
the daemon by a name of its choosing (DNS rebinding) passes that guard: run `PLURNK_AUTH=0` only where trusted parties alone reach the listener.
|
|
49
|
+
Sessions share full-width article lists and a stationary header around scrolling
|
|
50
|
+
main content. Session status and the Stop / multiline message / Send row stay at
|
|
51
|
+
the bottom. The message field and buttons grow together; Enter remains a newline,
|
|
52
|
+
and Ctrl+Enter sends through the same form as Send.
|
|
53
|
+
Page titles, breadcrumbs and empty/error documents support ordinary browser
|
|
54
|
+
navigation with or without JavaScript.
|
|
55
|
+
Header controls: 🗃️ workspace breadcrumb, ⚙️ Account, ✖ Sign out.
|
|
56
|
+
Breadcrumbs fit between the mascot and menu, or center below them when space is short.
|
|
57
|
+
|
|
58
|
+
Directories select their `index.html`: `/` and `/index.html` serve the same
|
|
59
|
+
document, as do the two spellings for any admitted nested index. Directory links
|
|
60
|
+
include the trailing slash. Missing documents and assets return 404, not the
|
|
61
|
+
home page. Navigation never creates workspaces or sessions, claims control, or
|
|
62
|
+
starts inference. Folderless workspaces work the same way as project workspaces.
|
|
63
|
+
|
|
64
|
+
The [directory address contract](SPEC.md#web-directory-addresses-named-directory-addresses)
|
|
65
|
+
maps workspace names to `/~/<workspace>/` and sessions to `/~/<workspace>@<session>/`,
|
|
66
|
+
preserving slashes and encoding name punctuation. Names remain separate from
|
|
67
|
+
project folders; URLs do not publish workspace files.
|
|
68
|
+
|
|
69
|
+
## Sign-in
|
|
70
|
+
|
|
71
|
+
Web uses the daemon's shared `PLURNK_AUTH` and `PLURNK_PASS` configuration.
|
|
72
|
+
There is one local operator account and no username setting. With authentication
|
|
73
|
+
enabled, set a password; an empty password does not admit a browser,
|
|
74
|
+
including on localhost. The daemon owns the sign-in form and credential validation.
|
|
75
|
+
Set `PLURNK_AUTH_ISSUER` to the public origin when a proxy fronts the daemon.
|
|
76
|
+
`PLURNK_AUTH=0` explicitly makes directories anonymous too.
|
|
77
|
+
|
|
78
|
+
The daemon's native sign-in and setup/error pages use the same compiled Pico
|
|
79
|
+
stylesheet as web. Authentication remains daemon-owned; web supplies no login form.
|
|
80
|
+
|
|
81
|
+
The browser receives an HttpOnly session cookie; no access token, refresh token,
|
|
82
|
+
password or operator secret is embedded in a page or browser storage. **Sign out**
|
|
83
|
+
ends this browser's sign-in and its module credentials together. Revisiting requires
|
|
84
|
+
sign-in. **Account → Sessions** lists the authority's live sign-ins, marks this session,
|
|
85
|
+
and offers native forms to revoke one or all other sessions. No device or last-activity
|
|
86
|
+
information is invented. Other sessions and independently authorized clients remain
|
|
87
|
+
intact. A daemon restart invalidates sessions. Remotely, use HTTPS.
|
|
88
|
+
|
|
89
|
+
The same-origin `POST /auth/token` connection primitive supplies short-lived
|
|
90
|
+
ACP access credentials to a signed-in browser. OAuth refresh credentials stay
|
|
91
|
+
server-side; rotation and revocation use the daemon's authority.
|
|
92
|
+
|
|
93
|
+
Session pages passively connect through the official ACP client. A compact footer
|
|
94
|
+
above the message field shows approval mode, lifecycle, model/effort, latest-loop
|
|
95
|
+
elapsed time, and cumulative session-and-descendant tokens and cost. Unknown totals
|
|
96
|
+
stay `?`, not zero; known partial amounts retain `+ ?`. Field descriptions preserve
|
|
97
|
+
exact accounting behind the compact figures. A finished loop leaves the page watching
|
|
98
|
+
for the next one. Closing, refreshing or navigating away never cancels work.
|
|
99
|
+
Connection failure stops observation and marks the displayed values as stale;
|
|
100
|
+
use **Reconnect** or, after revocation, **Sign in**. Reconnect preserves the current
|
|
101
|
+
draft without resubmitting it; full page reloads do not persist drafts.
|
|
102
|
+
No automatic work retries occur.
|
|
103
|
+
Context occupancy/capacity, pending input, preparation, indexing and the daemon's `wait`
|
|
104
|
+
countdown appear only when relevant. The countdown is an observation deadline, not
|
|
105
|
+
a promise of completion. A collapsed session-count disclosure opens the live
|
|
106
|
+
descendant tree; no empty tree or metadata inventory occupies the page.
|
|
107
|
+
Workspace names and folder labels
|
|
108
|
+
follow supplied state without changing the observed session or rewriting the URL.
|
|
109
|
+
Daemon notices and nonterminal Problems appear separately under **Observed diagnostics**,
|
|
110
|
+
as literal messages and recovery guidance. Distinct observations remain through reconnects
|
|
111
|
+
on that page; they are not an archive or an indication that the session has stopped.
|
|
112
|
+
**Observed activity** exposes non-conversation log rows and text emitted outside
|
|
113
|
+
operations, retaining source coordinates and supplied session attribution as entry
|
|
114
|
+
semantics and accessible names. These observations survive reconnects on the same page, not
|
|
115
|
+
reloads; they are not replies or a complete activity history.
|
|
116
|
+
Operations show their glyph and aside above the addressed selection, returned count
|
|
117
|
+
and any failure. An immediate receipt completes that summary rather than adding
|
|
118
|
+
another article. Authored bodies appear below it; `read` results are not fetched
|
|
119
|
+
automatically. Reasoning stays collapsed until opened. Fetched bodies are literal text and are never added
|
|
120
|
+
to client-uploaded conversation history or saved in browser storage.
|
|
121
|
+
|
|
122
|
+
**Observed stream outcomes** retains conclusions seen on this page, separately
|
|
123
|
+
from session completion and conversation receipts. **Read output** explicitly
|
|
124
|
+
fetches a literal snapshot of all channels; click again to refresh it. Neither
|
|
125
|
+
inspection nor navigation cancels execution.
|
|
126
|
+
|
|
127
|
+
Live reasoning appears in one temporary plain-text preview, cleared when the
|
|
128
|
+
attempt ends or delivery disconnects. `PLURNK_WEB_REASONING_PREVIEW_CHARS` bounds
|
|
129
|
+
its retained tail (4096 Unicode code points by default). Completed turns keep
|
|
130
|
+
their reasoning in collapsed disclosures headed by `<session> > Loop <loop> > Turn <turn>`;
|
|
131
|
+
opening one retrieves the full trace when visible, without adding it to later prompt submissions.
|
|
132
|
+
Loops in the conversation transcript use open `Loop <loop>` disclosures with folded operation runs and a live open-task checklist at the tail of an active loop.
|
|
133
|
+
|
|
134
|
+
**Send** also supports follow-ups while the session is running. The draft clears
|
|
135
|
+
only after the daemon acknowledges it; newer typing is preserved. A failed or
|
|
136
|
+
uncertain submission is never retried automatically. **Stop** preserves unsent
|
|
137
|
+
text; closing the page is not Stop. Browser approval defaults to manual review
|
|
138
|
+
(`PLURNK_WEB_YOLO=0`). `PLURNK_WEB_YOLO=1` accepts proposals automatically, subject to daemon
|
|
139
|
+
permissions, on a session page the person opened themselves; one reached from another site
|
|
140
|
+
starts in manual review, as does every page on a plain-HTTP origin other than localhost (its
|
|
141
|
+
browser reports no navigation source). The session page shows the active mode. In manual mode, each approval
|
|
142
|
+
names its requesting session and shows the exact operation and review evidence.
|
|
143
|
+
Choose Accept or Reject for every presented operation, then **Submit responses**;
|
|
144
|
+
neither choice is preselected. Questions and MCP input always need a human answer.
|
|
145
|
+
Other authorized clients can settle the same request; every view withdraws the
|
|
146
|
+
answered controls and follows the work. Refresh rediscovers what remains pending.
|
|
147
|
+
An answer overtaken by another answer is reported as refused while observation
|
|
148
|
+
continues. Failed or uncertain decisions are reported, never automatically retried;
|
|
149
|
+
an actual connection failure requires **Reconnect**. Unimplemented interactions remain pending with
|
|
150
|
+
an explicit notice, never an automatic decision.
|
|
151
|
+
|
|
152
|
+
Questions show their request, full response schema, and requesting session ID when
|
|
153
|
+
the daemon supplies it. Simple fields use native
|
|
154
|
+
controls; nested or conditional answers use an **Answer (JSON)** editor without
|
|
155
|
+
discarding schema rules. Optional fields have an inclusion checkbox. Answers are
|
|
156
|
+
validated before submission and by the daemon; local errors preserve your input.
|
|
157
|
+
**Cancel this request** cancels that question, not the session's other work.
|
|
158
|
+
Refresh rediscovers pending questions but does not retain unsubmitted answers.
|
|
159
|
+
|
|
160
|
+
The daemon supplies the recent conversation window. **Load previous loop** reads
|
|
161
|
+
older history without adding it to model requests. Loaded pages remain for this
|
|
162
|
+
visit; any gap after reconnection has the same explicit loading control. Prepending
|
|
163
|
+
history preserves your reading position. New output follows the bottom only while
|
|
164
|
+
you are there. Reloading starts from the current daemon window.
|
|
165
|
+
|
|
166
|
+
Messages preserve daemon chronology; unknown history is not shown as empty.
|
|
167
|
+
Content and calls are direct semantic entries with accessible names and
|
|
168
|
+
presentation-relevant metadata, not nested protocol inspectors. Bodies use native
|
|
169
|
+
disclosures: user messages and delivered replies start open; notes, tool evidence
|
|
170
|
+
and completed reasoning start closed. Headers, diagnostics and operation details
|
|
171
|
+
remain visible. Opening a body does not start work or add `read` receipt readback.
|
|
172
|
+
Markdown is sanitized, raw
|
|
173
|
+
HTML stays text and images become links. `send` bodies use that same Markdown renderer;
|
|
174
|
+
`note`, reasoning and ordinary operation evidence remain literal preformatted text.
|
|
175
|
+
Long lines wrap and settled entries grow with their content; explicit code, tables,
|
|
176
|
+
formulas and diagrams scroll locally when wider than the viewport.
|
|
177
|
+
`note` retains attribution semantics without an enclosing assistant
|
|
178
|
+
article, a duplicate arguments view or a body copy in attributes.
|
|
179
|
+
The ACP client owns live messages; archival pages are read-only presentation. Neither
|
|
180
|
+
is saved in browser storage.
|
|
181
|
+
|
|
182
|
+
Markdown footnotes use native reference and back-links within each rich message or `send`.
|
|
183
|
+
Repeated references retain separate return links; definitions never leak between
|
|
184
|
+
messages. Code and unresolved references remain readable source.
|
|
185
|
+
|
|
186
|
+
Math uses locally bundled Temml and native MathML: `$…$`, `$$…$$`, `\(…\)` and
|
|
187
|
+
`\[…\]` outside code. Unsupported formulas keep their source and a short error;
|
|
188
|
+
raw HTML and TeX link/media extensions cannot create controls or fetch content.
|
|
189
|
+
The math renderer and its styles load only when needed.
|
|
190
|
+
|
|
191
|
+
Mermaid fences become static SVG images compiled by the web module's pinned
|
|
192
|
+
[Ondine](https://github.com/wevm/ondine) dependency, within its supported syntax.
|
|
193
|
+
The compiler runs in bounded Node threads; no compiler or WebAssembly is
|
|
194
|
+
sent to the browser. Compilation uses the existing browser session (or the daemon's
|
|
195
|
+
explicitly unauthenticated mode). `PLURNK_WEB_DIAGRAM_*` limits are documented in
|
|
196
|
+
`ai.plurnk/.env.defaults`.
|
|
197
|
+
The renderer loads only when needed. Source remains available in a disclosure;
|
|
198
|
+
unsupported or invalid diagrams keep their source and a short error. There are no
|
|
199
|
+
interactive diagrams, remote rendering services or external font requests.
|
|
200
|
+
Prose reflows on narrow screens; wide code, tables, formulas and diagrams scroll locally
|
|
201
|
+
without shrinking the text or widening the page. Native zoom remains available.
|
|
202
|
+
|
|
203
|
+
English is rendered in the document, not filled in by JavaScript. The current
|
|
204
|
+
page needs no duplicate English dictionary or browser storage, and has no language
|
|
205
|
+
picker or stored preferences. Ordinary navigation and forms
|
|
206
|
+
remain native HTML; live session status and conversation require JavaScript.
|
|
207
|
+
|
|
208
|
+
## Install
|
|
209
|
+
|
|
210
|
+
Requires Node.js 26+ and Plurnk service 5.3+ with its module-client credential and
|
|
211
|
+
workspace-label APIs
|
|
212
|
+
([credential authority](https://github.com/plurnk/plurnk-service/blob/main/plurnk-core/SPEC.md),
|
|
213
|
+
including sign-in inventory, shared browser/module revocation, password-only login,
|
|
214
|
+
and registered authorization-page styles, plus daemon-supplied folder labels).
|
|
215
|
+
`@plurnk/plurnk-service` includes `@plurnk/plurnk-web` by default; it can also be
|
|
216
|
+
installed beside the service directly from npm or a local build:
|
|
217
|
+
|
|
218
|
+
```sh
|
|
219
|
+
npm install --no-audit --no-fund @plurnk/plurnk-web
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
To build and verify a candidate archive from source:
|
|
223
|
+
|
|
224
|
+
```sh
|
|
225
|
+
npm ci --no-audit --no-fund
|
|
226
|
+
npm run test:candidate -- /path/to/packed-platform-packages
|
|
227
|
+
npm pack
|
|
228
|
+
npm install --no-audit --no-fund /path/to/plurnk-plurnk-web-1.1.0.tgz
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Restart that daemon and visit its root URL, normally `http://localhost:1066/`.
|
|
232
|
+
Native extension trust applies; the standard policy admits `@plurnk/*` packages.
|
|
233
|
+
The plugin inherits the daemon's host and port, and leaves more-specific routes
|
|
234
|
+
alone. It does not install or start a service.
|
|
235
|
+
|
|
236
|
+
Set `PLURNK_WEB_ENABLED=0` in the service environment and restart to disable the
|
|
237
|
+
module without uninstalling it. Module settings, browser approval mode and the sign-in time limit are documented in
|
|
238
|
+
[ai.plurnk/.env.defaults](ai.plurnk/.env.defaults).
|
|
239
|
+
|
|
240
|
+
## Install as an app
|
|
241
|
+
|
|
242
|
+
Use the browser's **Install app**, **Add to Home Screen** or **Add to Dock** action,
|
|
243
|
+
where supported. The manifest supplies Plurnk's name, icons and standalone window.
|
|
244
|
+
Localhost works over HTTP; remote installation requires HTTPS, normally supplied
|
|
245
|
+
by your reverse proxy. Installation does not install or start the daemon.
|
|
246
|
+
|
|
247
|
+
The app requires its daemon to be reachable. It does not register an offline cache
|
|
248
|
+
or provide offline operation. Browser and OS support varies.
|
|
249
|
+
|
|
250
|
+
## Development
|
|
251
|
+
|
|
252
|
+
Read [ARCHITECTURE.md](ARCHITECTURE.md) for ownership, configuration and verification
|
|
253
|
+
boundaries. Web follows the platform's engineering discipline through public contracts.
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
npm ci --no-audit --no-fund
|
|
257
|
+
npm run dev
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Open the loopback URL Vite prints (normally `http://127.0.0.1:5173/`).
|
|
261
|
+
HTML edits reload the page; CSS edits update it in place. This serves the frontend
|
|
262
|
+
only and neither starts nor restarts the daemon. Directory and sign-in requests
|
|
263
|
+
need the daemon; Vite does not emulate its data or authentication.
|
|
264
|
+
|
|
265
|
+
`npm run build` compiles the frontend into `ai.plurnk/dist/`. The plugin serves
|
|
266
|
+
that build on the daemon's existing port; restart the daemon to load a new build.
|
|
267
|
+
`npm run preview` previews the last build locally without a daemon. It is not the
|
|
268
|
+
production server. Vite is development tooling only.
|
|
269
|
+
|
|
270
|
+
`npm test` builds the frontend and checks specification tags and witnesses using
|
|
271
|
+
Plurnk's shared development checker, server and browser JavaScript, OTM's
|
|
272
|
+
HTML/JavaScript/CSS contracts, the module, and the three-engine browser component
|
|
273
|
+
suites. `npm run test:installation` packs and installs the plugin with packed
|
|
274
|
+
platform packages and the terminal client in a temporary directory. These may be published
|
|
275
|
+
archives obtained with `npm pack` or locally built candidates. `test:candidate`
|
|
276
|
+
gates the committed HEAD in a throwaway clone: `npm ci` from the lockfile, the
|
|
277
|
+
archives installed beside it without saving, then `npm test` and
|
|
278
|
+
`npm run test:installation` with `PLURNK_WEB_TEST_PACKAGES` naming the archive directory. The checkout is only read.
|
|
279
|
+
The installed test uses an
|
|
280
|
+
isolated configuration, database and dynamically assigned port, plus Playwright
|
|
281
|
+
Chromium. Component coverage also exercises native conversation behavior in Firefox
|
|
282
|
+
and WebKit. Install the test browsers with `npx playwright install chromium firefox webkit`
|
|
283
|
+
if necessary. The operator's daemon and configuration are not used.
|
|
284
|
+
The gate exercises the shipped session page and native input/review forms against that daemon and a
|
|
285
|
+
deterministic local model; no paid inference is involved and no ACP traffic is mocked.
|
|
286
|
+
Shared review journeys drive the installed terminal through a PTY alongside the
|
|
287
|
+
browser, covering both clients' manual/YOLO combinations and either manual responder.
|
|
288
|
+
The terminal emulator and PTY driver are test-only dependencies.
|
|
289
|
+
It exercises synchronization, observer/control handoff with one ACP history,
|
|
290
|
+
admitted work surviving request abortion, navigation and page close, explicit
|
|
291
|
+
cancellation, approval and question interruption and rediscovery,
|
|
292
|
+
shutdown and the real browser sign-in/access-token lifecycle. Held directory and OAuth
|
|
293
|
+
requests verify that module shutdown settles admitted work before releasing resources.
|
|
294
|
+
Cross-client prompt
|
|
295
|
+
delivery, exact `read` operands and real command stdout/stderr results are compared live and after
|
|
296
|
+
refresh through the client's messages, without custom-row reconstruction. Standard success,
|
|
297
|
+
cancellation, failure and reported token usage are checked separately. No ACP traffic is
|
|
298
|
+
mocked and no client-owned replay cache hides differences from the daemon's history.
|
|
299
|
+
Stream journeys also exercise silent executors, never-written channels, explicit
|
|
300
|
+
authenticated output inspection, completion during absence, cancellation and nonzero exit.
|
|
301
|
+
Browser journeys also check console warnings/errors and uncaught exceptions;
|
|
302
|
+
deliberately tested failures require explicit diagnostic expectations.
|
|
303
|
+
Adversarial content checks exercise rich-text roles, `note` bodies, literal tool data,
|
|
304
|
+
streaming and replay against the production content policy in all three engines.
|
|
305
|
+
|
|
306
|
+
`web/index.html` and `web/app.js` are the document and browser entry point.
|
|
307
|
+
Vite bundles OTM from its npm entry and compiles the CSS. Build preparation copies
|
|
308
|
+
Pico's readable pinned substrate and dependency licenses, and derives a maskable SVG
|
|
309
|
+
from the mascot. The ACP client loads only on session and overview pages; Vite includes the bundled
|
|
310
|
+
dependencies' license notices. Production prunes unused CSS rules, variables and keyframes from
|
|
311
|
+
the browser and server-rendered document sources, plus the authority's publicly
|
|
312
|
+
exported document specimens, before minification. The auth package supplies those
|
|
313
|
+
specimens at build time only; no daemon code enters the browser bundle.
|
|
314
|
+
Browser type checking uses the public runtime-neutral client entry without Node
|
|
315
|
+
globals. The module's server-side port types use their separate public entry;
|
|
316
|
+
type declarations are erased, not bundled.
|
|
317
|
+
The generated asset inventory tells the plugin which production files to serve.
|
|
318
|
+
Static assets negotiate build-time Brotli/gzip representations when smaller, with
|
|
319
|
+
identity delivery available. Private documents and ACP streams are not compressed
|
|
320
|
+
by the plugin; no request-time compression or additional browser dependency is added.
|
|
321
|
+
Build output is packed but not committed. [SPEC.md](SPEC.md) defines the contract.
|
|
322
|
+
|
|
323
|
+
The `web/styles/index.css` import entry composes the four source layers in order
|
|
324
|
+
before production pruning, so references between layers remain visible:
|
|
325
|
+
|
|
326
|
+
| File | Concern |
|
|
327
|
+
|---|---|
|
|
328
|
+
| `app-vendor.css` | Generated, unmodified Pico substrate. |
|
|
329
|
+
| `app-structure.css` | Reading width, viewport grid, composer sizing, gutters and wrapping. |
|
|
330
|
+
| `app-style.css` | Substrate token overrides; brand accents, system monospace and conversation surface colors. |
|
|
331
|
+
| `app-state.css` | Directory/session width, semantic background selection, glyphs, connection state and native focus visibility. |
|
|
332
|
+
|
|
333
|
+
Authored CSS is checked with OTM's Stylelint rules. Content-renderer dependencies
|
|
334
|
+
load their own vendor styles separately; sign-in uses only the page stylesheet.
|
|
335
|
+
No remote fonts are required.
|
|
336
|
+
|
|
337
|
+
Code: MIT. The hamster artwork derives from Google's Noto Emoji under Apache-2.0,
|
|
338
|
+
with glasses and a green bow added. See [artwork attribution](web/public/icons/NOTO-NOTICE.txt).
|