pindeck 3.0.0-beta.3 → 3.2.0-beta.1
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 +136 -38
- package/cli.mjs +19 -9
- package/front.mjs +413 -0
- package/lib/agent-process.mjs +4 -1
- package/lib/agent-tools.mjs +5 -2
- package/lib/asset-roots.mjs +22 -0
- package/lib/claude.mjs +10 -2
- package/lib/deck-files.mjs +5 -3
- package/lib/deck-list.mjs +72 -0
- package/lib/deck-target.mjs +43 -0
- package/lib/eids.mjs +15 -6
- package/lib/login.mjs +75 -0
- package/lib/models.mjs +10 -4
- package/lib/pdf.mjs +18 -2
- package/lib/servers.mjs +91 -0
- package/lib/usage.mjs +15 -0
- package/package.json +4 -3
- package/public/bridge.js +56 -7
- package/public/editor.css +30 -3
- package/public/editor.js +260 -99
- package/public/events-worker.js +47 -0
- package/public/front.css +14 -0
- package/public/index.html +10 -2
- package/server.mjs +493 -235
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PinDeck
|
|
2
2
|
|
|
3
|
-
> **macOS, and Linux as a beta · Version 3 beta preview** (`3.
|
|
3
|
+
> **macOS, and Linux as a beta · Version 3 beta preview** (`3.2.0-beta.1`). On Linux, PinDeck runs as a
|
|
4
4
|
> headless server that you use from your Mac's browser through an SSH tunnel (see
|
|
5
5
|
> [Running on a Linux server](#running-on-a-linux-server-beta)). Windows is not supported. The beta is on
|
|
6
6
|
> npm’s `beta` channel and the [`v3-beta`](https://github.com/ehabets/PinDeck/tree/v3-beta) branch; stable
|
|
@@ -42,7 +42,7 @@ Install the beta from npm:
|
|
|
42
42
|
```bash
|
|
43
43
|
npx pindeck@beta /path/to/deck
|
|
44
44
|
# Or select this exact beta:
|
|
45
|
-
npx pindeck@3.
|
|
45
|
+
npx pindeck@3.2.0-beta.1 /path/to/deck
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Or run it from the `v3-beta` branch, which includes the example deck:
|
|
@@ -50,24 +50,43 @@ Or run it from the `v3-beta` branch, which includes the example deck:
|
|
|
50
50
|
```bash
|
|
51
51
|
git clone --branch v3-beta --single-branch https://github.com/ehabets/PinDeck.git PinDeck-v3
|
|
52
52
|
cd PinDeck-v3
|
|
53
|
-
node
|
|
53
|
+
node front.mjs ocean-example
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Use `npx pindeck@latest /path/to/deck` for the stable release; the beta channel does not replace it.
|
|
57
57
|
Releases, with notes for each beta, are on [GitHub](https://github.com/ehabets/PinDeck/releases).
|
|
58
58
|
|
|
59
59
|
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
|
|
60
|
+
once and logs this browser in; for a new one, run `pindeck login` (or `node front.mjs login`). On a Mac,
|
|
61
|
+
pressing Enter in the terminal where PinDeck runs opens a new link in your default browser.
|
|
61
62
|
|
|
62
|
-
The deck is
|
|
63
|
-
one, the current folder. Several decks can share a folder, each with its own chat and undo history;
|
|
63
|
+
The deck is an `.html` file (`pindeck path/to/talk.html`) or a folder, which opens its `index.html`;
|
|
64
|
+
without one, the current folder. Several decks can share a folder, each with its own chat and undo history;
|
|
64
65
|
they share the folder's `theme.css` and `brand.css`, and the assistant edits only the deck that is open.
|
|
65
66
|
PinDeck adds element ids to the deck file when it opens it (see below), so try it on a copy of a deck
|
|
66
67
|
first. Options: `--port 5180`, `--provider claude|codex`, `--model <name>` (for this run only; otherwise the
|
|
67
|
-
|
|
68
|
+
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
69
|
`--help`. Runtime files (chat history, screenshots, backups) are kept in `~/.pindeck-v3/` (change with
|
|
69
70
|
`PINDECK_HOME`), not in the deck. `ocean-example/` is a complete example deck to start from.
|
|
70
71
|
|
|
72
|
+
### Several decks
|
|
73
|
+
|
|
74
|
+
Click the deck's name above the slide for the other decks: the `.html` files in the deck's folder and in
|
|
75
|
+
the asset roots, and in their folders one level down (`lecture/index.html`). A deck opens in the same
|
|
76
|
+
tab, or with ⌘-click in a new one, on the same port and login, so one SSH tunnel serves them all. Each keeps
|
|
77
|
+
its own chat and undo history while it is open, and the assistant finishes a turn in a deck you leave. A
|
|
78
|
+
file PinDeck cannot open is greyed out with the reason; listing a deck changes nothing, and only opening it
|
|
79
|
+
adds its element ids. Symlinked decks and folders are listed too; a deck file that links to a deck in
|
|
80
|
+
another folder is greyed out (open that deck itself). Started with a folder that has no `index.html`,
|
|
81
|
+
PinDeck shows the list of its decks. A deck with no editor open for 30 minutes is closed (its undo history
|
|
82
|
+
goes, as on a restart) and opens again when you choose it. Open as many decks in as many tabs as you like:
|
|
83
|
+
the tabs of a browser share one connection for their live updates.
|
|
84
|
+
|
|
85
|
+
A deck is open in one PinDeck at a time: started again for a deck that another PinDeck (another port, or
|
|
86
|
+
`server.mjs` on its own) has open, PinDeck says where it is open and stops, so their chats and undo
|
|
87
|
+
histories never overwrite each other. `pindeck login <deck>` and `cli.mjs` find the PinDeck that serves
|
|
88
|
+
the deck, whichever port it runs on.
|
|
89
|
+
|
|
71
90
|
## Compatibility and requirements
|
|
72
91
|
|
|
73
92
|
* **Runtime:** Node.js 20 or later, plus a modern browser. The release workflow uses Node.js 24.
|
|
@@ -209,7 +228,9 @@ and Haiku model in each family. Claude versions are compared numerically from di
|
|
|
209
228
|
a rolling family alias wins ties, avoiding duplicate entries. **Show all available models** reveals
|
|
210
229
|
the full discovered catalog; this display preference is remembered in the browser. A currently selected
|
|
211
230
|
older model remains visible and is never switched automatically by the filter.
|
|
212
|
-
**Refresh models**
|
|
231
|
+
**Refresh models** asks the backends again; otherwise the lists are shared by the decks you open for 10 minutes
|
|
232
|
+
(`models.json` in the state folder), so opening a deck starts no backend just to list models. A missing CLI,
|
|
233
|
+
missing sign-in, or discovery failure is shown in its provider group.
|
|
213
234
|
These are backend-reported choices, not a guarantee of current quota or entitlement; a later rejected
|
|
214
235
|
request reports its error. Older CLIs may expose fewer models than a provider's website.
|
|
215
236
|
|
|
@@ -223,7 +244,9 @@ additional model-generated summary. It excludes tool output, needs no extra infe
|
|
|
223
244
|
sent with the first message to the new session. Earlier messages may be omitted. **Start fresh** sends
|
|
224
245
|
no conversation digest; the assistant still receives PinDeck instructions and the current deck context.
|
|
225
246
|
|
|
226
|
-
|
|
247
|
+
Each deck keeps its own provider, model and effort with its conversation (in its `chat.json`), so a choice in
|
|
248
|
+
one deck never moves another deck's conversation to another backend. The last choice is also saved in
|
|
249
|
+
`~/.pindeck-v3/config.json` (or `$PINDECK_HOME/config.json`), as the start for decks that have none yet:
|
|
227
250
|
|
|
228
251
|
```json
|
|
229
252
|
{
|
|
@@ -233,16 +256,25 @@ Settings are saved when changed in `~/.pindeck-v3/config.json` (or `$PINDECK_HOM
|
|
|
233
256
|
}
|
|
234
257
|
```
|
|
235
258
|
|
|
236
|
-
Legacy configuration without `provider` is interpreted as Claude
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
259
|
+
Legacy configuration without `provider` is interpreted as Claude; a provider without a model gets that
|
|
260
|
+
provider's default model. Once the backend has listed its models, a saved model it no longer offers gives way
|
|
261
|
+
to its default model (the chat says so), and an effort the model does not offer to its saved or default one,
|
|
262
|
+
before the first message. config.json is read again and merged whenever a choice is saved, so decks open at
|
|
263
|
+
the same time keep each other's effort preferences. Provider-tagged chat/session records prevent one backend
|
|
264
|
+
from resuming the other's IDs. `--provider` and `--model` override the deck's settings for that run; a
|
|
265
|
+
`--provider` other than the deck's starts a new conversation (the chat says so), and the next run without it
|
|
266
|
+
is back on the deck's own choice. A later menu selection is saved. `CLAUDE_BIN` and `CODEX_BIN` override
|
|
267
|
+
executable paths. `CLAUDE_MODEL`, which PinDeck 2 read, is not used: PinDeck warns and names `--model`.
|
|
240
268
|
|
|
241
269
|
The v3 preview defaults to **`~/.pindeck-v3`**, keeping v2 settings and conversations separate. It does
|
|
242
|
-
not copy the v2 directory automatically.
|
|
270
|
+
not copy the v2 directory automatically; `config.json` and `decks/*/chat.json` can be copied over by hand
|
|
271
|
+
(asset roots too: they are in config.json). Never give both versions the same `PINDECK_HOME`: they keep files
|
|
272
|
+
of the same names in different formats and overwrite each other's settings and chats. PinDeck 3 warns at
|
|
273
|
+
start when its folder holds a chat that PinDeck 2 wrote. To run both versions at once, use another port, for
|
|
274
|
+
example:
|
|
243
275
|
|
|
244
276
|
```bash
|
|
245
|
-
node
|
|
277
|
+
node front.mjs /path/to/a/deck-copy --port 5183 --provider codex
|
|
246
278
|
```
|
|
247
279
|
|
|
248
280
|
## Backend permissions and attachments
|
|
@@ -250,16 +282,17 @@ node server.mjs /path/to/a/deck-copy --port 5183 --provider codex
|
|
|
250
282
|
Claude uses its native Read/Edit tools with PinDeck's narrow allowlist, safe mode, and no inherited
|
|
251
283
|
MCP configuration. Codex runs with a read-only sandbox, command execution disabled, and no approval
|
|
252
284
|
grants. Inherited MCP servers and plugins are disabled in the thread configuration. Codex receives
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
285
|
+
four host-controlled tools: `pindeck_read`, `pindeck_edit`, `pindeck_write` and `pindeck_command`.
|
|
286
|
+
Both assistants may edit and create the files of the deck folder: the deck file, `theme.css` and its other
|
|
287
|
+
files. Never `brand.css`, `vendor/`, `.git/`, or the other decks in the folder (its other `.html` files, and
|
|
288
|
+
subfolders that hold a deck of their own). Linked writable files and paths outside the allowed roots are
|
|
289
|
+
rejected. Commands are restricted to PinDeck's layout, shot, slides, pdf and pdf-figure helpers, executed
|
|
290
|
+
with argument arrays rather than a shell. `brand.css` also retains the server's post-turn restoration safeguard.
|
|
258
291
|
|
|
259
292
|
Codex reads text, PNG/JPEG/WebP/GIF images and screenshots through the bridge. SVG is read as text.
|
|
260
|
-
Attached PDFs are handled page by page
|
|
261
|
-
|
|
262
|
-
|
|
293
|
+
Attached PDFs are handled page by page: a rendered page image (PDFKit on macOS, Poppler on Linux), plus the
|
|
294
|
+
page's text on macOS. Audio is embedded by path and is not transcribed. Read operations have a 12 MB limit;
|
|
295
|
+
long text can be read in chunks.
|
|
263
296
|
|
|
264
297
|
### Files outside the deck folder
|
|
265
298
|
|
|
@@ -272,6 +305,8 @@ exports. Claude may read those files but does not edit them.
|
|
|
272
305
|
Symlinks: PinDeck serves a file only if, with symlinks followed, it lies inside the deck folder or an
|
|
273
306
|
asset root. A symlink in the deck that leads anywhere else is refused (403). To use a symlinked
|
|
274
307
|
library folder, add the folder it points to as an asset root; it does not have to contain the deck.
|
|
308
|
+
PinDeck never writes or deletes through a symlink out of the deck folder: with a `figures/` or `export/`
|
|
309
|
+
that links elsewhere, uploads, exports and deleting a picture's file are refused with the reason.
|
|
275
310
|
|
|
276
311
|
## Running on a Linux server (beta)
|
|
277
312
|
|
|
@@ -284,7 +319,7 @@ the `claude` or `codex` CLI installed and logged in under your account there, if
|
|
|
284
319
|
editing by hand still works. Then, in one SSH session on the server:
|
|
285
320
|
|
|
286
321
|
```bash
|
|
287
|
-
node
|
|
322
|
+
node front.mjs path/to/deck --port 5180
|
|
288
323
|
```
|
|
289
324
|
|
|
290
325
|
and on your Mac, in another terminal (`myserver` is your usual SSH host):
|
|
@@ -297,11 +332,11 @@ Open the login link PinDeck printed on the server in the Mac's browser. The loca
|
|
|
297
332
|
the server's: with `-L 127.0.0.1:8080:127.0.0.1:5180`, change 5180 in the link to 8080. PinDeck accepts any
|
|
298
333
|
port, as long as the address is `127.0.0.1` or `localhost`. If the tunnel drops, a message you have already sent keeps running on the
|
|
299
334
|
server. Restart the tunnel and the editor reconnects and shows the files as they are then; it never sends a
|
|
300
|
-
message twice. If PinDeck restarts, the editor asks you to log in again: run `node
|
|
335
|
+
message twice. If PinDeck restarts, the editor asks you to log in again: run `node front.mjs login
|
|
301
336
|
path/to/deck` on the server for a new link.
|
|
302
337
|
|
|
303
338
|
Other users of a shared server cannot open the editor or read the deck through PinDeck: the token that
|
|
304
|
-
protects it is only in your browser's cookie and in PinDeck's own files in `~/.pindeck` (readable only by
|
|
339
|
+
protects it is only in your browser's cookie and in PinDeck's own files in `~/.pindeck-v3` (readable only by
|
|
305
340
|
you), never in a page or on a command line.
|
|
306
341
|
|
|
307
342
|
What works on Linux in this beta: editing by hand, speaker notes, slides, pins, the chat with Claude or Codex,
|
|
@@ -320,9 +355,12 @@ Without them the editor says what is missing (hover over "Server: Linux (beta)")
|
|
|
320
355
|
which commands are not available. LibreOffice may draw some slides a little differently from PowerPoint;
|
|
321
356
|
the pictures are references and figures, the slides themselves are rebuilt from the file. Chromium from snap may not be
|
|
322
357
|
allowed to use hidden folders in your home folder such as `~/.pindeck-v3`; if screenshots fail with it, set
|
|
323
|
-
`PINDECK_HOME` to a folder that is not hidden, or install Chrome or Chromium from
|
|
358
|
+
`PINDECK_HOME` to a folder that is not hidden (not the one PinDeck 2 uses), or install Chrome or Chromium from
|
|
359
|
+
a package. Run as root (in a container, say), PinDeck starts Chrome with `--no-sandbox`, which Chrome needs
|
|
360
|
+
there; a screenshot or PDF that fails gives Chrome's own reason.
|
|
324
361
|
|
|
325
|
-
|
|
362
|
+
One PinDeck serves all your decks on one port, and a deck can be open in only one PinDeck at a time (a
|
|
363
|
+
second one says where it is open). While PinDeck or the assistant is working on a deck, do not edit it with other tools
|
|
326
364
|
or switch git branches at the same time. Stop first, or wait until the assistant has finished. PinDeck notices
|
|
327
365
|
changes made by other programs and reloads, and it refuses Undo, Redo or an edit that would overwrite
|
|
328
366
|
them. Its checks cannot rule out every race with a program that writes at the same moment.
|
|
@@ -350,10 +388,10 @@ show and commit as usual. Clones without the filter configured simply see the fi
|
|
|
350
388
|
| Undo, redo | `⌘Z` / `⇧⌘Z` or the toolbar arrows. One history for your hand edits and the assistant's changes. |
|
|
351
389
|
| Pin elements | Press `P` (or the Pin button), click elements; each click gets a number. Click a marker to remove it, `Esc` to stop. |
|
|
352
390
|
| 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. |
|
|
353
|
-
| Visual questions | **+** in the chat, then **Screenshot**: the current slide with
|
|
354
|
-
| Review | Each answer ends with the changed files
|
|
355
|
-
| Stop | **Stop** interrupts the assistant; the conversation continues. **New chat** starts
|
|
356
|
-
| 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
|
|
391
|
+
| 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. |
|
|
392
|
+
| 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). |
|
|
393
|
+
| Stop | **Stop** interrupts the assistant; the conversation continues. **New chat** starts a new conversation; your slides, Undo and Redo stay as they are. |
|
|
394
|
+
| 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. |
|
|
357
395
|
| 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. |
|
|
358
396
|
| 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. |
|
|
359
397
|
| 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. |
|
|
@@ -362,10 +400,12 @@ show and commit as usual. Clones without the filter configured simply see the fi
|
|
|
362
400
|
| 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. |
|
|
363
401
|
| 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". |
|
|
364
402
|
| 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. |
|
|
365
|
-
| Navigate | Slide list, `←` `→`, or the toolbar. **Present** opens the deck in a new tab. |
|
|
403
|
+
| Navigate | Slide list, `←` `→`, or the toolbar. **Present** opens the deck in a new tab, at the current slide. |
|
|
404
|
+
| 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. |
|
|
366
405
|
|
|
367
406
|
You can also edit `index.html` or `theme.css` in any editor; the slide reloads, and the assistant is told
|
|
368
|
-
the files changed. CSS changes are swapped in without a reload.
|
|
407
|
+
the files changed. CSS changes are swapped in without a reload. Typing in the slide is not lost meanwhile:
|
|
408
|
+
when you finish, PinDeck refuses to save it over the other change and offers the text to copy.
|
|
369
409
|
|
|
370
410
|
## PowerPoint import
|
|
371
411
|
|
|
@@ -411,6 +451,20 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
411
451
|
|
|
412
452
|
## How it works
|
|
413
453
|
|
|
454
|
+
* **One port, a server per deck.** `pindeck` starts the front (`front.mjs`): it holds the port, the login
|
|
455
|
+
and the deck list, and serves each open deck at `/d/<deck>/`. Every deck runs its own deck server
|
|
456
|
+
(`server.mjs`) on a private port of 127.0.0.1 with a token of its own; the front passes each request on
|
|
457
|
+
with that token. A deck's server, its assistant and its undo history are those of that deck alone. The
|
|
458
|
+
editor tabs of a browser share one event stream from the front (a shared worker), since browsers open
|
|
459
|
+
only six connections to one port; if a deck server stops, the front opens the deck again and the tab
|
|
460
|
+
catches up. Each PinDeck process notes its address in `~/.pindeck-v3/servers/` for `pindeck login` and
|
|
461
|
+
`cli.mjs`, and a deck server holds its deck's `open.json`, so a deck opens in one PinDeck only.
|
|
462
|
+
* **Deck pages are sandboxed.** The deck page (in the editor's frames, and in Present) runs with a sandbox
|
|
463
|
+
policy in an origin of its own, at a per-run address that serves the deck's files and nothing else. A
|
|
464
|
+
script in a deck, a template, or written by the assistant cannot reach the login cookie, the API, the
|
|
465
|
+
chat or other decks. The editor and its bridge in the slide frame talk by `postMessage`. Headless Chrome
|
|
466
|
+
(screenshots, layout, PDFs) does not log in at all; the page it asks for is served without the sandbox,
|
|
467
|
+
which its screenshot and print modes cannot handle, only with a key made for that one run.
|
|
414
468
|
* **Element ids.** On start, the server gives every slide and every visible element a readable
|
|
415
469
|
`data-eid` attribute (`summary`, `summary/callout`, `summary/li-2`). Only the attribute is
|
|
416
470
|
inserted; the rest of the file stays as it was. A backup of the file before the first change is
|
|
@@ -446,13 +500,15 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
446
500
|
so no allow rule in your own, the deck's or a parent folder's settings widens this. Codex has no shell
|
|
447
501
|
and no file access of its own: it reads and edits through PinDeck's own tools, which apply the same
|
|
448
502
|
rules and refuse symlinks out of the deck. If `brand.css` changes during a turn anyway, the server
|
|
449
|
-
restores it and says so in the chat.
|
|
503
|
+
restores it and says so in the chat. Subfolders that hold a deck of their own count as other decks.
|
|
450
504
|
* **Undo.** The server keeps a copy of every file a change touched, from before and after it (an AI
|
|
451
505
|
turn, which may change, create or delete several files of the deck, or a hand edit). Files over 2 MB
|
|
452
506
|
are not copied: the chat says when a turn changed one, and Undo leaves it as it is. Hidden files,
|
|
453
507
|
`vendor/` and `export/` are not part of undo. Undo and redo walk that history and tell the assistant on
|
|
454
508
|
the next message. They first check that the files are still as that change left them; if something
|
|
455
509
|
else changed them since, they do nothing and say which file differs, rather than overwrite that work.
|
|
510
|
+
Decks that share a folder share its files: while another deck's assistant works there too, a turn keeps
|
|
511
|
+
only the files its own assistant said it wrote, and says which it left out.
|
|
456
512
|
* **Saving.** Every file PinDeck writes into the deck is written to a temporary file next to it and then
|
|
457
513
|
renamed into place, so other programs never see half a file. Each change from the editor carries the
|
|
458
514
|
revision of the files it was made on; if the files have changed since, the change is refused, the
|
|
@@ -462,9 +518,12 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
462
518
|
|
|
463
519
|
| File | Purpose |
|
|
464
520
|
|---|---|
|
|
465
|
-
| `
|
|
521
|
+
| `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`. |
|
|
522
|
+
| `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>`). |
|
|
523
|
+
| `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. |
|
|
524
|
+
| `lib/servers.mjs` | The PinDecks running for this user, and which one serves a deck (`pindeck login`, `cli.mjs`). |
|
|
466
525
|
| `cli.mjs` | `layout`, `shot`, `slides`, `pdf handout` / `pdf presentation` and `pdf-figure` commands for the backends (and for you), and `git-setup`. |
|
|
467
|
-
| `public/` | The editor page
|
|
526
|
+
| `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. |
|
|
468
527
|
| `lib/pptx.mjs`, `lib/zip.mjs`, `lib/xml.mjs` | Reading `.pptx` files (no dependencies): slides, text, shapes and their positions, notes. |
|
|
469
528
|
| `lib/pptx-import.mjs` | Turns PowerPoint slides into slides of the deck: figures, tables, build steps, audio, layout, HTML in the deck's style. |
|
|
470
529
|
| `lib/waveform.mjs` | Waveform SVGs for imported audio. |
|
|
@@ -491,13 +550,52 @@ Without PowerPoint or Keynote (or on other systems than macOS) only the text and
|
|
|
491
550
|
* Parts of an inline SVG move with the whole SVG; inline text (bold, spans) moves with its block.
|
|
492
551
|
* No indenting or outdenting of bullets with `Tab` yet, and `Backspace` at the start of a bullet does not merge it with the one above; ask the assistant for those.
|
|
493
552
|
* Moves are offsets (`translate`), so the space an element came from stays reserved. Ask the assistant to turn hand edits into proper CSS when a layout should really change.
|
|
494
|
-
* The undo history lives on the server and starts fresh when PinDeck restarts
|
|
553
|
+
* The undo history lives on the server and starts fresh when PinDeck restarts, or when a deck closes after
|
|
554
|
+
30 minutes without an open editor.
|
|
495
555
|
* One writer at a time: PinDeck is not made for editing the same deck from two editors or tools at once.
|
|
556
|
+
* A deck's own scripts run sandboxed in the editor and in Present: they cannot use `localStorage`, cookies
|
|
557
|
+
or the editor page. A deck that needs them for its slides to work should catch the error.
|
|
558
|
+
* Decks are `.html` files; `.htm` files are not listed or opened as decks.
|
|
496
559
|
* Linux (beta): pictures of PDF pages and PowerPoint slides, and waveforms of non-WAV audio, need
|
|
497
560
|
Poppler, LibreOffice and ffmpeg on the server (see [Running on a Linux server](#running-on-a-linux-server-beta)).
|
|
498
561
|
|
|
499
562
|
## Versions
|
|
500
563
|
|
|
564
|
+
* **3.2.0-beta.1**: fixes from a code review and a round of user tests.
|
|
565
|
+
- Security: deck pages run sandboxed, so a deck's script can no longer use the API, read other decks or
|
|
566
|
+
send messages; the login link's `next` stays on PinDeck. A deck's own script cannot use `localStorage`
|
|
567
|
+
there either (it throws).
|
|
568
|
+
- Typing in a bullet that cannot be saved because the deck changed meanwhile can be copied, as other text
|
|
569
|
+
can; a deck that never chose a model keeps the one its conversation started with.
|
|
570
|
+
- Several decks in one folder: a turn no longer records or undoes another deck's files, and deleting a
|
|
571
|
+
picture keeps a file another deck uses. Subfolder decks are locked for the assistant.
|
|
572
|
+
- Each deck keeps its provider, model and effort; config.json is merged, not overwritten; unusable saved
|
|
573
|
+
settings are made usable before the first message.
|
|
574
|
+
- Many tabs on one port; a deck server that stops reconnects; `pindeck login` and `cli.mjs` find the right
|
|
575
|
+
PinDeck; a deck opens in one PinDeck only.
|
|
576
|
+
- Screenshots show the pins of their own message; Stop during a screenshot; failures reach the assistant.
|
|
577
|
+
- New chat keeps Undo; undone marks survive a restart; only the latest change offers Undo.
|
|
578
|
+
- A deck page that cannot start says why, and Send no longer hangs; typing survives an outside save; the
|
|
579
|
+
deck menu at every width; keyboard use of the model menus; Enter in a bullet leaves no copied ids.
|
|
580
|
+
- Large decks get their ids in linear time; symlinked decks; a deck that is gone; Chrome's own errors,
|
|
581
|
+
and `--no-sandbox` as root; a warning when PinDeck 2 writes to the same state folder.
|
|
582
|
+
- On a Mac, Enter in the terminal opens PinDeck in the browser.
|
|
583
|
+
- From the code review: locked paths regardless of case (macOS) and `.git/config` restored after each
|
|
584
|
+
turn; Codex reads PDFs of a deck reached through a symlink; "not signed in" only when Claude says so;
|
|
585
|
+
betas tested before they are staged; model lists shared between decks; a faster deck list; smaller
|
|
586
|
+
status updates; asset roots read alike by the front and the deck servers.
|
|
587
|
+
|
|
588
|
+
* **3.1.0-beta.1**: several decks on one port, and screenshots you can open from the chat.
|
|
589
|
+
- A deck menu: click the deck's name above the slide to open another deck from its folder or the
|
|
590
|
+
asset roots (and one folder down). Each open deck keeps its own chat, assistant session and Undo;
|
|
591
|
+
listing decks changes no file. `pindeck` now starts a small front that holds the port and the
|
|
592
|
+
login and runs one deck server per open deck. A deck with no editor open for 30 minutes closes
|
|
593
|
+
(its Undo history goes, as on a restart) and reopens when chosen again.
|
|
594
|
+
- A folder without `index.html` opens a page listing its decks instead of failing.
|
|
595
|
+
- `pindeck login talk.html` prints a link that opens that deck.
|
|
596
|
+
- Screenshots the assistant took show as a small picture on the chat line; click it to see it large.
|
|
597
|
+
A screenshot PinDeck no longer keeps says so.
|
|
598
|
+
|
|
501
599
|
* **3.0.0-beta.3**: everything from 2.10.0, for both assistants.
|
|
502
600
|
- Decks made without reveal.js: a deck that names its slides with `<meta name="pindeck:slides">`
|
|
503
601
|
and their size with `<meta name="pindeck:size">` is edited like a reveal.js deck (contributed by
|
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])]
|