pindeck 3.1.0-beta.1 → 3.2.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/README.md +142 -58
- package/cli.mjs +19 -9
- package/front.mjs +138 -43
- package/lib/agent-process.mjs +4 -1
- package/lib/agent-tools.mjs +5 -2
- package/lib/asset-roots.mjs +22 -0
- package/lib/capabilities.mjs +2 -2
- package/lib/claude.mjs +10 -2
- package/lib/deck-files.mjs +5 -3
- package/lib/deck-list.mjs +28 -5
- package/lib/deck-target.mjs +21 -3
- package/lib/eids.mjs +15 -6
- package/lib/login.mjs +15 -1
- package/lib/models.mjs +10 -4
- package/lib/pdf.mjs +18 -2
- package/lib/platform-notice.mjs +2 -2
- package/lib/servers.mjs +91 -0
- package/package.json +2 -2
- package/public/bridge.js +56 -7
- package/public/editor.css +8 -2
- package/public/editor.js +191 -83
- package/public/events-worker.js +47 -0
- package/public/index.html +1 -1
- package/server.mjs +452 -155
package/README.md
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# PinDeck
|
|
2
2
|
|
|
3
|
-
> **macOS
|
|
4
|
-
>
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
> releases (`npx pindeck`) stay on 2.x. See installation below.
|
|
3
|
+
> **macOS and Linux · Version 3** (`3.2.0`). On Linux, PinDeck runs as a headless server that you use
|
|
4
|
+
> from your Mac's browser through an SSH tunnel (see [Running on a Linux server](#running-on-a-linux-server)).
|
|
5
|
+
> Windows is not supported. Coming from PinDeck 2: version 3 keeps its settings and chats in
|
|
6
|
+
> `~/.pindeck-v3`, apart from 2.x (see [Models, providers and configuration](#models-providers-and-configuration)).
|
|
8
7
|
|
|
9
8
|
**Pin it. Say it. Done.** PinDeck is a local editor for HTML slide decks (reveal.js): the slides on
|
|
10
9
|
the left, the slide in the middle, and a chat with Claude Code or OpenAI Codex on the right. You click elements to
|
|
@@ -32,39 +31,39 @@ checked the layout; the next request, still being typed, refers to the new pins
|
|
|
32
31
|
|
|
33
32
|
## Quick start
|
|
34
33
|
|
|
35
|
-
Runs on macOS
|
|
34
|
+
Runs on macOS and Linux. The npm package declares `"os": ["darwin", "linux"]`, so normal
|
|
36
35
|
npm installation rejects other operating systems. Overriding that check does not make those platforms
|
|
37
36
|
supported. Running the server from a cloned repository on another OS shows a local support notice
|
|
38
37
|
instead of opening the deck or starting a backend.
|
|
39
38
|
|
|
40
|
-
Install
|
|
39
|
+
Install from npm:
|
|
41
40
|
|
|
42
41
|
```bash
|
|
43
|
-
npx pindeck
|
|
44
|
-
# Or select this exact beta:
|
|
45
|
-
npx pindeck@3.1.0-beta.1 /path/to/deck
|
|
42
|
+
npx pindeck /path/to/deck
|
|
46
43
|
```
|
|
47
44
|
|
|
48
|
-
Or run it from
|
|
45
|
+
Or run it from source, which includes the example deck:
|
|
49
46
|
|
|
50
47
|
```bash
|
|
51
|
-
git clone
|
|
52
|
-
cd PinDeck
|
|
48
|
+
git clone https://github.com/ehabets/PinDeck.git
|
|
49
|
+
cd PinDeck
|
|
53
50
|
node front.mjs ocean-example
|
|
54
51
|
```
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
Releases, with notes for each
|
|
53
|
+
PinDeck 2 stays available as `npx pindeck@2 /path/to/deck` (source: the
|
|
54
|
+
[`2.x`](https://github.com/ehabets/PinDeck/tree/2.x) branch). Releases, with notes for each version, are on
|
|
55
|
+
[GitHub](https://github.com/ehabets/PinDeck/releases).
|
|
58
56
|
|
|
59
57
|
Then open the login link PinDeck prints (`PinDeck: http://127.0.0.1:5180/login?code=...`). It works
|
|
60
|
-
once and logs this browser in; for a new one, run `pindeck login` (or `node front.mjs login`).
|
|
58
|
+
once and logs this browser in; for a new one, run `pindeck login` (or `node front.mjs login`). On a Mac,
|
|
59
|
+
pressing Enter in the terminal where PinDeck runs opens a new link in your default browser.
|
|
61
60
|
|
|
62
|
-
The deck is
|
|
63
|
-
one, the current folder. Several decks can share a folder, each with its own chat and undo history;
|
|
61
|
+
The deck is an `.html` file (`pindeck path/to/talk.html`) or a folder, which opens its `index.html`;
|
|
62
|
+
without one, the current folder. Several decks can share a folder, each with its own chat and undo history;
|
|
64
63
|
they share the folder's `theme.css` and `brand.css`, and the assistant edits only the deck that is open.
|
|
65
64
|
PinDeck adds element ids to the deck file when it opens it (see below), so try it on a copy of a deck
|
|
66
65
|
first. Options: `--port 5180`, `--provider claude|codex`, `--model <name>` (for this run only; otherwise the
|
|
67
|
-
|
|
66
|
+
deck's own choice, see [Models, providers and configuration](#models-providers-and-configuration)), `--asset-root <folder>` (see [Files outside the deck folder](#files-outside-the-deck-folder)),
|
|
68
67
|
`--help`. Runtime files (chat history, screenshots, backups) are kept in `~/.pindeck-v3/` (change with
|
|
69
68
|
`PINDECK_HOME`), not in the deck. `ocean-example/` is a complete example deck to start from.
|
|
70
69
|
|
|
@@ -75,9 +74,16 @@ the asset roots, and in their folders one level down (`lecture/index.html`). A d
|
|
|
75
74
|
tab, or with ⌘-click in a new one, on the same port and login, so one SSH tunnel serves them all. Each keeps
|
|
76
75
|
its own chat and undo history while it is open, and the assistant finishes a turn in a deck you leave. A
|
|
77
76
|
file PinDeck cannot open is greyed out with the reason; listing a deck changes nothing, and only opening it
|
|
78
|
-
adds its element ids.
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
adds its element ids. Symlinked decks and folders are listed too; a deck file that links to a deck in
|
|
78
|
+
another folder is greyed out (open that deck itself). Started with a folder that has no `index.html`,
|
|
79
|
+
PinDeck shows the list of its decks. A deck with no editor open for 30 minutes is closed (its undo history
|
|
80
|
+
goes, as on a restart) and opens again when you choose it. Open as many decks in as many tabs as you like:
|
|
81
|
+
the tabs of a browser share one connection for their live updates.
|
|
82
|
+
|
|
83
|
+
A deck is open in one PinDeck at a time: started again for a deck that another PinDeck (another port, or
|
|
84
|
+
`server.mjs` on its own) has open, PinDeck says where it is open and stops, so their chats and undo
|
|
85
|
+
histories never overwrite each other. `pindeck login <deck>` and `cli.mjs` find the PinDeck that serves
|
|
86
|
+
the deck, whichever port it runs on.
|
|
81
87
|
|
|
82
88
|
## Compatibility and requirements
|
|
83
89
|
|
|
@@ -86,11 +92,11 @@ again when you choose it.
|
|
|
86
92
|
The corresponding executable must be on `PATH`; `CLAUDE_BIN` and `CODEX_BIN` can override its path.
|
|
87
93
|
Only the selected backend is required for editing. Model and effort availability comes from that
|
|
88
94
|
backend and account, and may differ from the provider’s website or desktop app.
|
|
89
|
-
* **Platforms:** macOS
|
|
95
|
+
* **Platforms:** macOS and Linux (see [Running on a Linux server](#running-on-a-linux-server)).
|
|
90
96
|
Windows is not supported. The npm package declares `"os": ["darwin", "linux"]`, so normal npm
|
|
91
97
|
installation rejects other operating systems. This check can be overridden; bypassing it does not make
|
|
92
98
|
those platforms supported. Source launches on unsupported platforms show a local support page without
|
|
93
|
-
opening the deck or starting a backend. Native Windows support is a possible v4 feature, not part of
|
|
99
|
+
opening the deck or starting a backend. Native Windows support is a possible v4 feature, not part of version 3.
|
|
94
100
|
* **Screenshots and PDF export:** require Chrome, Chromium, Edge or Brave where the server runs.
|
|
95
101
|
* **PDF input through Codex:** pages are rendered with macOS PDFKit, or Poppler on Linux. Page-text
|
|
96
102
|
extraction uses `osascript` and is macOS-only; on Linux Codex reads the rendered page image. Claude uses
|
|
@@ -220,7 +226,9 @@ and Haiku model in each family. Claude versions are compared numerically from di
|
|
|
220
226
|
a rolling family alias wins ties, avoiding duplicate entries. **Show all available models** reveals
|
|
221
227
|
the full discovered catalog; this display preference is remembered in the browser. A currently selected
|
|
222
228
|
older model remains visible and is never switched automatically by the filter.
|
|
223
|
-
**Refresh models**
|
|
229
|
+
**Refresh models** asks the backends again; otherwise the lists are shared by the decks you open for 10 minutes
|
|
230
|
+
(`models.json` in the state folder), so opening a deck starts no backend just to list models. A missing CLI,
|
|
231
|
+
missing sign-in, or discovery failure is shown in its provider group.
|
|
224
232
|
These are backend-reported choices, not a guarantee of current quota or entitlement; a later rejected
|
|
225
233
|
request reports its error. Older CLIs may expose fewer models than a provider's website.
|
|
226
234
|
|
|
@@ -234,7 +242,9 @@ additional model-generated summary. It excludes tool output, needs no extra infe
|
|
|
234
242
|
sent with the first message to the new session. Earlier messages may be omitted. **Start fresh** sends
|
|
235
243
|
no conversation digest; the assistant still receives PinDeck instructions and the current deck context.
|
|
236
244
|
|
|
237
|
-
|
|
245
|
+
Each deck keeps its own provider, model and effort with its conversation (in its `chat.json`), so a choice in
|
|
246
|
+
one deck never moves another deck's conversation to another backend. The last choice is also saved in
|
|
247
|
+
`~/.pindeck-v3/config.json` (or `$PINDECK_HOME/config.json`), as the start for decks that have none yet:
|
|
238
248
|
|
|
239
249
|
```json
|
|
240
250
|
{
|
|
@@ -244,13 +254,22 @@ Settings are saved when changed in `~/.pindeck-v3/config.json` (or `$PINDECK_HOM
|
|
|
244
254
|
}
|
|
245
255
|
```
|
|
246
256
|
|
|
247
|
-
Legacy configuration without `provider` is interpreted as Claude
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
257
|
+
Legacy configuration without `provider` is interpreted as Claude; a provider without a model gets that
|
|
258
|
+
provider's default model. Once the backend has listed its models, a saved model it no longer offers gives way
|
|
259
|
+
to its default model (the chat says so), and an effort the model does not offer to its saved or default one,
|
|
260
|
+
before the first message. config.json is read again and merged whenever a choice is saved, so decks open at
|
|
261
|
+
the same time keep each other's effort preferences. Provider-tagged chat/session records prevent one backend
|
|
262
|
+
from resuming the other's IDs. `--provider` and `--model` override the deck's settings for that run; a
|
|
263
|
+
`--provider` other than the deck's starts a new conversation (the chat says so), and the next run without it
|
|
264
|
+
is back on the deck's own choice. A later menu selection is saved. `CLAUDE_BIN` and `CODEX_BIN` override
|
|
265
|
+
executable paths. `CLAUDE_MODEL`, which PinDeck 2 read, is not used: PinDeck warns and names `--model`.
|
|
266
|
+
|
|
267
|
+
PinDeck 3 defaults to **`~/.pindeck-v3`**, keeping v2 settings and conversations separate. It does
|
|
268
|
+
not copy the v2 directory automatically; `config.json` and `decks/*/chat.json` can be copied over by hand
|
|
269
|
+
(asset roots too: they are in config.json). Never give both versions the same `PINDECK_HOME`: they keep files
|
|
270
|
+
of the same names in different formats and overwrite each other's settings and chats. PinDeck 3 warns at
|
|
271
|
+
start when its folder holds a chat that PinDeck 2 wrote. To run both versions at once, use another port, for
|
|
272
|
+
example:
|
|
254
273
|
|
|
255
274
|
```bash
|
|
256
275
|
node front.mjs /path/to/a/deck-copy --port 5183 --provider codex
|
|
@@ -261,16 +280,17 @@ node front.mjs /path/to/a/deck-copy --port 5183 --provider codex
|
|
|
261
280
|
Claude uses its native Read/Edit tools with PinDeck's narrow allowlist, safe mode, and no inherited
|
|
262
281
|
MCP configuration. Codex runs with a read-only sandbox, command execution disabled, and no approval
|
|
263
282
|
grants. Inherited MCP servers and plugins are disabled in the thread configuration. Codex receives
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
283
|
+
four host-controlled tools: `pindeck_read`, `pindeck_edit`, `pindeck_write` and `pindeck_command`.
|
|
284
|
+
Both assistants may edit and create the files of the deck folder: the deck file, `theme.css` and its other
|
|
285
|
+
files. Never `brand.css`, `vendor/`, `.git/`, or the other decks in the folder (its other `.html` files, and
|
|
286
|
+
subfolders that hold a deck of their own). Linked writable files and paths outside the allowed roots are
|
|
287
|
+
rejected. Commands are restricted to PinDeck's layout, shot, slides, pdf and pdf-figure helpers, executed
|
|
288
|
+
with argument arrays rather than a shell. `brand.css` also retains the server's post-turn restoration safeguard.
|
|
269
289
|
|
|
270
290
|
Codex reads text, PNG/JPEG/WebP/GIF images and screenshots through the bridge. SVG is read as text.
|
|
271
|
-
Attached PDFs are handled page by page
|
|
272
|
-
|
|
273
|
-
|
|
291
|
+
Attached PDFs are handled page by page: a rendered page image (PDFKit on macOS, Poppler on Linux), plus the
|
|
292
|
+
page's text on macOS. Audio is embedded by path and is not transcribed. Read operations have a 12 MB limit;
|
|
293
|
+
long text can be read in chunks.
|
|
274
294
|
|
|
275
295
|
### Files outside the deck folder
|
|
276
296
|
|
|
@@ -283,8 +303,10 @@ exports. Claude may read those files but does not edit them.
|
|
|
283
303
|
Symlinks: PinDeck serves a file only if, with symlinks followed, it lies inside the deck folder or an
|
|
284
304
|
asset root. A symlink in the deck that leads anywhere else is refused (403). To use a symlinked
|
|
285
305
|
library folder, add the folder it points to as an asset root; it does not have to contain the deck.
|
|
306
|
+
PinDeck never writes or deletes through a symlink out of the deck folder: with a `figures/` or `export/`
|
|
307
|
+
that links elsewhere, uploads, exports and deleting a picture's file are refused with the reason.
|
|
286
308
|
|
|
287
|
-
## Running on a Linux server
|
|
309
|
+
## Running on a Linux server
|
|
288
310
|
|
|
289
311
|
PinDeck can run on a Linux machine where the deck lives, with the editor in your Mac's browser. The
|
|
290
312
|
deck, PinDeck, the backend (Claude Code or Codex) and the deck's git clone all stay on the server; the browser only shows the
|
|
@@ -312,10 +334,10 @@ message twice. If PinDeck restarts, the editor asks you to log in again: run `no
|
|
|
312
334
|
path/to/deck` on the server for a new link.
|
|
313
335
|
|
|
314
336
|
Other users of a shared server cannot open the editor or read the deck through PinDeck: the token that
|
|
315
|
-
protects it is only in your browser's cookie and in PinDeck's own files in `~/.pindeck` (readable only by
|
|
337
|
+
protects it is only in your browser's cookie and in PinDeck's own files in `~/.pindeck-v3` (readable only by
|
|
316
338
|
you), never in a page or on a command line.
|
|
317
339
|
|
|
318
|
-
What works on Linux
|
|
340
|
+
What works on Linux: editing by hand, speaker notes, slides, pins, the chat with Claude or Codex,
|
|
319
341
|
Undo/Redo, live reload when files change on the server, layout checks, attaching figures, audio and
|
|
320
342
|
PDFs, `git-setup` and the PowerPoint import. Some features use programs on the server, and are on when
|
|
321
343
|
they are installed (on Debian or Ubuntu: `sudo apt install poppler-utils libreoffice-impress ffmpeg`):
|
|
@@ -327,13 +349,16 @@ they are installed (on Debian or Ubuntu: `sudo apt install poppler-utils libreof
|
|
|
327
349
|
| Pictures of PowerPoint slides in the import (thumbnails, diagrams) | LibreOffice (`soffice`) and Poppler |
|
|
328
350
|
| Waveforms of audio other than WAV in the import | ffmpeg |
|
|
329
351
|
|
|
330
|
-
Without them the editor says what is missing (hover over "Server: Linux
|
|
352
|
+
Without them the editor says what is missing (hover over "Server: Linux"), and the assistant is told
|
|
331
353
|
which commands are not available. LibreOffice may draw some slides a little differently from PowerPoint;
|
|
332
354
|
the pictures are references and figures, the slides themselves are rebuilt from the file. Chromium from snap may not be
|
|
333
355
|
allowed to use hidden folders in your home folder such as `~/.pindeck-v3`; if screenshots fail with it, set
|
|
334
|
-
`PINDECK_HOME` to a folder that is not hidden, or install Chrome or Chromium from
|
|
356
|
+
`PINDECK_HOME` to a folder that is not hidden (not the one PinDeck 2 uses), or install Chrome or Chromium from
|
|
357
|
+
a package. Run as root (in a container, say), PinDeck starts Chrome with `--no-sandbox`, which Chrome needs
|
|
358
|
+
there; a screenshot or PDF that fails gives Chrome's own reason.
|
|
335
359
|
|
|
336
|
-
|
|
360
|
+
One PinDeck serves all your decks on one port, and a deck can be open in only one PinDeck at a time (a
|
|
361
|
+
second one says where it is open). While PinDeck or the assistant is working on a deck, do not edit it with other tools
|
|
337
362
|
or switch git branches at the same time. Stop first, or wait until the assistant has finished. PinDeck notices
|
|
338
363
|
changes made by other programs and reloads, and it refuses Undo, Redo or an edit that would overwrite
|
|
339
364
|
them. Its checks cannot rule out every race with a program that writes at the same moment.
|
|
@@ -361,10 +386,10 @@ show and commit as usual. Clones without the filter configured simply see the fi
|
|
|
361
386
|
| Undo, redo | `⌘Z` / `⇧⌘Z` or the toolbar arrows. One history for your hand edits and the assistant's changes. |
|
|
362
387
|
| Pin elements | Press `P` (or the Pin button), click elements; each click gets a number. Click a marker to remove it, `Esc` to stop. |
|
|
363
388
|
| Ask the assistant | Write in the sidebar and refer to pins by number: "1: align with 2, make 3 smaller". The selected element is sent too, so "make this smaller" works. `Enter` sends, `Shift+Enter` adds a new line. |
|
|
364
|
-
| Visual questions | **+** in the chat, then **Screenshot**: the current slide with
|
|
365
|
-
| Review | Each answer ends with the changed files
|
|
366
|
-
| Stop | **Stop** interrupts the assistant; the conversation continues. **New chat** starts
|
|
367
|
-
| New slide | **+ New slide** above the slide list: a **content slide** (title and bullets), a **section divider**, or a **duplicate** of the current slide. It is added after the current slide, modelled on the deck's own slides
|
|
389
|
+
| Visual questions | **+** in the chat, then **Screenshot**: the current slide with the pins of that message is attached when you send. If Chrome cannot take it, the assistant is told. **Stop** during the screenshot stops at once. |
|
|
390
|
+
| Review | Each answer ends with the changed files and a **Diff** button; the most recent change still in effect also has an **Undo** button. After a restart, earlier changes keep their *undone* mark but have no Diff or Undo (the undo history ends with the run). |
|
|
391
|
+
| Stop | **Stop** interrupts the assistant; the conversation continues. **New chat** starts a new conversation; your slides, Undo and Redo stay as they are. |
|
|
392
|
+
| New slide | **+ New slide** above the slide list: a **content slide** (title and bullets), a **section divider**, or a **duplicate** of the current slide. It is added after the current slide, modelled on the deck's own slides; a new content slide or divider opens its title for typing. |
|
|
368
393
|
| Import from PowerPoint | **+ New slide** → **Import from PowerPoint…**, then choose a `.pptx` file and tick the slides you want (hidden PowerPoint slides start unticked). They are added after the current slide in this deck's own layouts, and the assistant can improve the complex ones; see [PowerPoint import](#powerpoint-import). `⌘Z` removes them again, with their figures. |
|
|
369
394
|
| Speaker notes | The **Notes** field under the slide shows the current slide's notes (the speaker view, `S`, shows them when presenting). Type to change them; they are saved when you click elsewhere or press `⌘Enter`, and `Esc` puts back what was there. A slide without notes gets them; emptying the field removes them. Notes with formatting other than line breaks are edited as HTML. Drag the line above the notes to give them more or less room (double-click it for the default size); collapse them with their header. |
|
|
370
395
|
| Move a slide | Drag it up or down in the slide list; an orange line shows where it will go. It moves with its notes and the comment above it, and `⌘Z` puts it back. Slides inside vertical stacks cannot be moved yet. |
|
|
@@ -373,10 +398,12 @@ show and commit as usual. Clones without the filter configured simply see the fi
|
|
|
373
398
|
| Attach figures and audio | **+** in the chat, then **File…**, drag and drop onto the chat or a slide, or paste an image. Files are saved in `<deck>/figures/` straight away; audio also gets a waveform SVG. Then ask the assistant, e.g. "put this figure on a new slide after 4". Removing an attachment before sending deletes the file again. |
|
|
374
399
|
| Attach a PDF | The same way: a figure or table to take over, or a paper or report with more details. PDFs stay outside the deck (in `~/.pindeck-v3`); the assistant reads them, rebuilds tables as HTML, and renders a figure (a page or a cropped part of one) into `<deck>/figures/` as PNG with `cli.mjs pdf-figure` (macOS, or Linux with Poppler). E.g. "put Fig. 3 of this paper on slide 7" or "add the results of Table 2 to slide 9". |
|
|
375
400
|
| Export PDF | **Export ▾** in the toolbar. **Handout PDF**: one page per slide, build steps shown complete. **Presentation PDF**: one page per click, so a slide with two build steps gives three pages. Files go to `<deck>/export/`. Needs Chrome or Chromium. |
|
|
376
|
-
| Navigate | Slide list, `←` `→`, or the toolbar. **Present** opens the deck in a new tab. |
|
|
401
|
+
| Navigate | Slide list, `←` `→`, or the toolbar. **Present** opens the deck in a new tab, at the current slide. |
|
|
402
|
+
| Check from a terminal | `node cli.mjs layout 3 --issues`, `slides`, `shot 3` or `pdf handout`, in the deck's folder (or with `--deck <folder or file.html>`): asks the PinDeck that serves the deck. |
|
|
377
403
|
|
|
378
404
|
You can also edit `index.html` or `theme.css` in any editor; the slide reloads, and the assistant is told
|
|
379
|
-
the files changed. CSS changes are swapped in without a reload.
|
|
405
|
+
the files changed. CSS changes are swapped in without a reload. Typing in the slide is not lost meanwhile:
|
|
406
|
+
when you finish, PinDeck refuses to save it over the other change and offers the text to copy.
|
|
380
407
|
|
|
381
408
|
## PowerPoint import
|
|
382
409
|
|
|
@@ -425,7 +452,17 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
425
452
|
* **One port, a server per deck.** `pindeck` starts the front (`front.mjs`): it holds the port, the login
|
|
426
453
|
and the deck list, and serves each open deck at `/d/<deck>/`. Every deck runs its own deck server
|
|
427
454
|
(`server.mjs`) on a private port of 127.0.0.1 with a token of its own; the front passes each request on
|
|
428
|
-
with that token. A deck's server, its assistant and its undo history are those of that deck alone.
|
|
455
|
+
with that token. A deck's server, its assistant and its undo history are those of that deck alone. The
|
|
456
|
+
editor tabs of a browser share one event stream from the front (a shared worker), since browsers open
|
|
457
|
+
only six connections to one port; if a deck server stops, the front opens the deck again and the tab
|
|
458
|
+
catches up. Each PinDeck process notes its address in `~/.pindeck-v3/servers/` for `pindeck login` and
|
|
459
|
+
`cli.mjs`, and a deck server holds its deck's `open.json`, so a deck opens in one PinDeck only.
|
|
460
|
+
* **Deck pages are sandboxed.** The deck page (in the editor's frames, and in Present) runs with a sandbox
|
|
461
|
+
policy in an origin of its own, at a per-run address that serves the deck's files and nothing else. A
|
|
462
|
+
script in a deck, a template, or written by the assistant cannot reach the login cookie, the API, the
|
|
463
|
+
chat or other decks. The editor and its bridge in the slide frame talk by `postMessage`. Headless Chrome
|
|
464
|
+
(screenshots, layout, PDFs) does not log in at all; the page it asks for is served without the sandbox,
|
|
465
|
+
which its screenshot and print modes cannot handle, only with a key made for that one run.
|
|
429
466
|
* **Element ids.** On start, the server gives every slide and every visible element a readable
|
|
430
467
|
`data-eid` attribute (`summary`, `summary/callout`, `summary/li-2`). Only the attribute is
|
|
431
468
|
inserted; the rest of the file stays as it was. A backup of the file before the first change is
|
|
@@ -461,13 +498,15 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
461
498
|
so no allow rule in your own, the deck's or a parent folder's settings widens this. Codex has no shell
|
|
462
499
|
and no file access of its own: it reads and edits through PinDeck's own tools, which apply the same
|
|
463
500
|
rules and refuse symlinks out of the deck. If `brand.css` changes during a turn anyway, the server
|
|
464
|
-
restores it and says so in the chat.
|
|
501
|
+
restores it and says so in the chat. Subfolders that hold a deck of their own count as other decks.
|
|
465
502
|
* **Undo.** The server keeps a copy of every file a change touched, from before and after it (an AI
|
|
466
503
|
turn, which may change, create or delete several files of the deck, or a hand edit). Files over 2 MB
|
|
467
504
|
are not copied: the chat says when a turn changed one, and Undo leaves it as it is. Hidden files,
|
|
468
505
|
`vendor/` and `export/` are not part of undo. Undo and redo walk that history and tell the assistant on
|
|
469
506
|
the next message. They first check that the files are still as that change left them; if something
|
|
470
507
|
else changed them since, they do nothing and say which file differs, rather than overwrite that work.
|
|
508
|
+
Decks that share a folder share its files: while another deck's assistant works there too, a turn keeps
|
|
509
|
+
only the files its own assistant said it wrote, and says which it left out.
|
|
471
510
|
* **Saving.** Every file PinDeck writes into the deck is written to a temporary file next to it and then
|
|
472
511
|
renamed into place, so other programs never see half a file. Each change from the editor carries the
|
|
473
512
|
revision of the files it was made on; if the files have changed since, the change is refused, the
|
|
@@ -480,8 +519,9 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
480
519
|
| `front.mjs` | What `pindeck` starts (127.0.0.1 only, random token per run, one-time login links): the login, the deck list and one deck server per open deck at `/d/<deck>/`; `login`. |
|
|
481
520
|
| `server.mjs` | The server for one deck: UI, deck files, events, backend session, undo, CLI endpoints. Behind the front, or on its own (`node server.mjs <deck>`). |
|
|
482
521
|
| `lib/login.mjs`, `lib/deck-target.mjs`, `lib/deck-list.mjs` | Login links and cookies, which deck a path names (and its state folder), and the decks the menu lists. |
|
|
522
|
+
| `lib/servers.mjs` | The PinDecks running for this user, and which one serves a deck (`pindeck login`, `cli.mjs`). |
|
|
483
523
|
| `cli.mjs` | `layout`, `shot`, `slides`, `pdf handout` / `pdf presentation` and `pdf-figure` commands for the backends (and for you), and `git-setup`. |
|
|
484
|
-
| `public/` | The editor page
|
|
524
|
+
| `public/` | The editor page; `bridge.js`, which is injected into the deck in edit mode (never saved to it); `events-worker.js`, the event stream the tabs of a browser share. |
|
|
485
525
|
| `lib/pptx.mjs`, `lib/zip.mjs`, `lib/xml.mjs` | Reading `.pptx` files (no dependencies): slides, text, shapes and their positions, notes. |
|
|
486
526
|
| `lib/pptx-import.mjs` | Turns PowerPoint slides into slides of the deck: figures, tables, build steps, audio, layout, HTML in the deck's style. |
|
|
487
527
|
| `lib/waveform.mjs` | Waveform SVGs for imported audio. |
|
|
@@ -511,11 +551,50 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
511
551
|
* The undo history lives on the server and starts fresh when PinDeck restarts, or when a deck closes after
|
|
512
552
|
30 minutes without an open editor.
|
|
513
553
|
* One writer at a time: PinDeck is not made for editing the same deck from two editors or tools at once.
|
|
514
|
-
*
|
|
515
|
-
|
|
554
|
+
* A deck's own scripts run sandboxed in the editor and in Present: they cannot use `localStorage`, cookies
|
|
555
|
+
or the editor page. A deck that needs them for its slides to work should catch the error.
|
|
556
|
+
* Decks are `.html` files; `.htm` files are not listed or opened as decks.
|
|
557
|
+
* Linux: pictures of PDF pages and PowerPoint slides, and waveforms of non-WAV audio, need
|
|
558
|
+
Poppler, LibreOffice and ffmpeg on the server (see [Running on a Linux server](#running-on-a-linux-server)).
|
|
516
559
|
|
|
517
560
|
## Versions
|
|
518
561
|
|
|
562
|
+
* **3.2.0**: PinDeck 3, the first stable release of version 3: everything from the 3.0, 3.1 and 3.2 betas
|
|
563
|
+
below. Compared with 2.11:
|
|
564
|
+
- OpenAI Codex as a second assistant next to Claude Code, with the models and efforts each backend
|
|
565
|
+
offers; each deck keeps its own provider, model and effort.
|
|
566
|
+
- Several decks on one port: a deck menu above the slide, each deck with its own chat, assistant
|
|
567
|
+
session and Undo.
|
|
568
|
+
- Deck pages run sandboxed, so a deck's script cannot use the API or read other decks.
|
|
569
|
+
- Linux is no longer a beta.
|
|
570
|
+
- Settings and chats are kept in `~/.pindeck-v3`, apart from PinDeck 2's `~/.pindeck`; nothing is copied
|
|
571
|
+
over (see [Models, providers and configuration](#models-providers-and-configuration)). PinDeck 2 stays
|
|
572
|
+
on npm as `pindeck@2`.
|
|
573
|
+
|
|
574
|
+
* **3.2.0-beta.1**: fixes from a code review and a round of user tests.
|
|
575
|
+
- Security: deck pages run sandboxed, so a deck's script can no longer use the API, read other decks or
|
|
576
|
+
send messages; the login link's `next` stays on PinDeck. A deck's own script cannot use `localStorage`
|
|
577
|
+
there either (it throws).
|
|
578
|
+
- Typing in a bullet that cannot be saved because the deck changed meanwhile can be copied, as other text
|
|
579
|
+
can; a deck that never chose a model keeps the one its conversation started with.
|
|
580
|
+
- Several decks in one folder: a turn no longer records or undoes another deck's files, and deleting a
|
|
581
|
+
picture keeps a file another deck uses. Subfolder decks are locked for the assistant.
|
|
582
|
+
- Each deck keeps its provider, model and effort; config.json is merged, not overwritten; unusable saved
|
|
583
|
+
settings are made usable before the first message.
|
|
584
|
+
- Many tabs on one port; a deck server that stops reconnects; `pindeck login` and `cli.mjs` find the right
|
|
585
|
+
PinDeck; a deck opens in one PinDeck only.
|
|
586
|
+
- Screenshots show the pins of their own message; Stop during a screenshot; failures reach the assistant.
|
|
587
|
+
- New chat keeps Undo; undone marks survive a restart; only the latest change offers Undo.
|
|
588
|
+
- A deck page that cannot start says why, and Send no longer hangs; typing survives an outside save; the
|
|
589
|
+
deck menu at every width; keyboard use of the model menus; Enter in a bullet leaves no copied ids.
|
|
590
|
+
- Large decks get their ids in linear time; symlinked decks; a deck that is gone; Chrome's own errors,
|
|
591
|
+
and `--no-sandbox` as root; a warning when PinDeck 2 writes to the same state folder.
|
|
592
|
+
- On a Mac, Enter in the terminal opens PinDeck in the browser.
|
|
593
|
+
- From the code review: locked paths regardless of case (macOS) and `.git/config` restored after each
|
|
594
|
+
turn; Codex reads PDFs of a deck reached through a symlink; "not signed in" only when Claude says so;
|
|
595
|
+
betas tested before they are staged; model lists shared between decks; a faster deck list; smaller
|
|
596
|
+
status updates; asset roots read alike by the front and the deck servers.
|
|
597
|
+
|
|
519
598
|
* **3.1.0-beta.1**: several decks on one port, and screenshots you can open from the chat.
|
|
520
599
|
- A deck menu: click the deck's name above the slide to open another deck from its folder or the
|
|
521
600
|
asset roots (and one folder down). Each open deck keeps its own chat, assistant session and Undo;
|
|
@@ -552,6 +631,11 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
552
631
|
switching with optional handover, curated model lists, a separate effort selector with per-model
|
|
553
632
|
preferences, restricted Codex tools, and separate v3 runtime state. On npm as `pindeck@beta`.
|
|
554
633
|
|
|
634
|
+
* **2.11**: screenshots in the chat. A screenshot sent with a message, and one Claude reads, shows as
|
|
635
|
+
a small picture that opens larger with a click (Esc or a click closes it). PinDeck keeps the 40
|
|
636
|
+
newest screenshots of a deck; an older one says "no longer kept". Chats from before 2.11 keep their
|
|
637
|
+
plain label. (In 3.x since 3.1.0-beta.1.)
|
|
638
|
+
|
|
555
639
|
* **2.10**: decks with their own file names and shared files, decks made without reveal.js, and Claude
|
|
556
640
|
working on the whole deck.
|
|
557
641
|
- A deck file by name: `pindeck path/to/talk.html` (a folder still opens its `index.html`). Several
|
package/cli.mjs
CHANGED
|
@@ -15,14 +15,20 @@
|
|
|
15
15
|
|
|
16
16
|
node cli.mjs git-setup [deck] keep PinDeck's data-eid ids out of git (no server needed; a folder or deck file)
|
|
17
17
|
|
|
18
|
-
<slide> is a slide id (data-eid), a slide number (1-based) or "current".
|
|
18
|
+
<slide> is a slide id (data-eid), a slide number (1-based) or "current". The assistant's commands reach its
|
|
19
|
+
own deck server (DECK_EDITOR_URL); run from a terminal, they reach the PinDeck that serves the deck in the
|
|
20
|
+
current folder (its index.html), or the deck named with --deck <folder | file.html>. */
|
|
19
21
|
|
|
20
22
|
import fs from "node:fs";
|
|
21
|
-
import os from "node:os";
|
|
22
23
|
import path from "node:path";
|
|
23
24
|
import { execFileSync } from "node:child_process";
|
|
25
|
+
import { deckTarget, homeDir } from "./lib/deck-target.mjs";
|
|
26
|
+
import { serverFor } from "./lib/servers.mjs";
|
|
24
27
|
|
|
25
|
-
const
|
|
28
|
+
const args = process.argv.slice(2);
|
|
29
|
+
const deckAt = args.indexOf("--deck");
|
|
30
|
+
const deckArg = deckAt >= 0 ? args.splice(deckAt, 2)[1] : null;
|
|
31
|
+
const [cmd, ...rest] = args;
|
|
26
32
|
const arg = rest[0];
|
|
27
33
|
|
|
28
34
|
/* git-setup: a git "clean" filter strips PinDeck's data-eid attributes whenever git reads the deck's
|
|
@@ -68,13 +74,17 @@ function figureQuery(args) {
|
|
|
68
74
|
|
|
69
75
|
let url = process.env.DECK_EDITOR_URL, token = process.env.DECK_EDITOR_TOKEN;
|
|
70
76
|
if (!url || !token) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
// from a terminal: the deck's own server if it is open, else a front that lists it (which opens it)
|
|
78
|
+
const deck = deckTarget(deckArg || process.cwd());
|
|
79
|
+
if (!fs.existsSync(path.join(deck.dir, deck.file))) {
|
|
80
|
+
console.error(`No ${deck.file} in ${deck.dir}: run this in a deck's folder, or name the deck with --deck <folder | file.html>.`);
|
|
81
|
+
process.exit(2);
|
|
82
|
+
}
|
|
83
|
+
const found = await serverFor(homeDir(), deck);
|
|
84
|
+
if (!found) { console.error(`No running PinDeck serves ${path.join(deck.dir, deck.file)} (start it with: pindeck ${deckArg || "."}).`); process.exit(1); }
|
|
85
|
+
({ url, token } = found.own || found.front);
|
|
86
|
+
if (!found.own) url = `${url}/d/${found.key}`;
|
|
76
87
|
}
|
|
77
|
-
if (!url) { console.error("The PinDeck server is not running (start it with: pindeck <deck-folder>)."); process.exit(1); }
|
|
78
88
|
|
|
79
89
|
/* layout and shot take several slides, so the assistant needs no shell loop or pipe (which PinDeck refuses) */
|
|
80
90
|
const queries = cmd === "pdf-figure" ? [figureQuery([...rest])]
|