klypix-mcp 1.43.0 → 1.44.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/FORMAT.md +148 -19
- package/NOTICE +6 -0
- package/README.md +449 -107
- package/bin/klypix-conformance.mjs +4 -0
- package/bin/klypix-doctor.mjs +10 -1
- package/bin/klypix-install.mjs +5 -0
- package/bin/klypix-link.mjs +28 -1
- package/bin/klypix-mcp.mjs +32 -1
- package/bin/klypix-uninstall.mjs +194 -0
- package/bin/klypix-worker.mjs +46 -12
- package/examples/showcase-brain.klypix +0 -0
- package/examples/showcase-wedding.klypix +0 -0
- package/package.json +14 -7
- package/src/agent-presence.mjs +37 -4
- package/src/mcp-presence.mjs +75 -13
- package/src/uninstall.mjs +548 -0
package/FORMAT.md
CHANGED
|
@@ -5,21 +5,35 @@
|
|
|
5
5
|
your.klypix`), and parseable with the Apache-2.0 library in this package. You own it;
|
|
6
6
|
any agent or app can read and write it.
|
|
7
7
|
|
|
8
|
+
Two working examples ship in this package under [`examples/`](examples/). Both are
|
|
9
|
+
text-and-arrows only (14 cards, no `assets/` entry), so they demonstrate the card /
|
|
10
|
+
container / connection model, not the embedded-binary half described below.
|
|
11
|
+
|
|
8
12
|
## Container layout
|
|
9
13
|
|
|
10
14
|
```
|
|
11
|
-
your.klypix
|
|
12
|
-
├── manifest.json
|
|
13
|
-
├── canvas.json
|
|
15
|
+
your.klypix (a ZIP archive)
|
|
16
|
+
├── manifest.json metadata + stats; read FIRST
|
|
17
|
+
├── canvas.json spatial layout: order, positions, connections, lines, strokes, view, settings
|
|
14
18
|
├── items/
|
|
15
|
-
│ └── <
|
|
16
|
-
└── assets/
|
|
17
|
-
|
|
19
|
+
│ └── <shard>/<id>.json one file per item (content only; geometry lives in canvas.json)
|
|
20
|
+
└── assets/ embedded binaries — any non-directory entry here is an asset
|
|
21
|
+
├── images/<shard>/<sha256>.<ext>
|
|
22
|
+
├── files/<shard>/<sha256>.bin
|
|
23
|
+
└── thumbs/<itemId>.png
|
|
18
24
|
```
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
`<shard>` is the **first two characters of the id (or sha) after its namespace
|
|
27
|
+
prefix is stripped**, lowercased, left-padded with `_` if shorter — e.g.
|
|
28
|
+
`txt_hto5hb3r_0_0` → `items/ht/txt_hto5hb3r_0_0.json`, and sha `a3f9…` →
|
|
29
|
+
`assets/images/a3/a3f9….png`. Ids are base36-ish, not strictly hex, so treat the
|
|
30
|
+
shard as "two characters", not "two hex digits". Sharding bounds files-per-directory
|
|
31
|
+
and lets a canvas with thousands of items be read partially.
|
|
32
|
+
|
|
33
|
+
Readers should treat the `assets/` sub-layout as **convention, not contract**: this
|
|
34
|
+
package's parser counts and reads *any* non-directory entry under `assets/`, so a
|
|
35
|
+
writer that flattens to `assets/<assetId>` still parses. Only the KLYPIX app's own
|
|
36
|
+
writer guarantees the content-addressed `images/ files/ thumbs/` split.
|
|
23
37
|
|
|
24
38
|
## `manifest.json`
|
|
25
39
|
|
|
@@ -28,13 +42,30 @@ to read partially.
|
|
|
28
42
|
"format": "klypix",
|
|
29
43
|
"version": 4,
|
|
30
44
|
"schemaVersion": 4,
|
|
45
|
+
"kind": "brain",
|
|
31
46
|
"createdAt": "ISO-8601",
|
|
32
47
|
"updatedAt": "ISO-8601",
|
|
33
48
|
"title": "My board",
|
|
34
|
-
"stats": { "itemCount": 12, "assetCount": 3, "totalBytes": 0 }
|
|
49
|
+
"stats": { "itemCount": 12, "assetCount": 3, "totalBytes": 0 },
|
|
50
|
+
"sync": { "enabled": false, "lastSyncRev": null, "lastSyncAt": null, "deviceId": "dev_…" }
|
|
35
51
|
}
|
|
36
52
|
```
|
|
37
53
|
|
|
54
|
+
- `version` — on-disk **layout** version (the container shape).
|
|
55
|
+
- `schemaVersion` — **document** version (item/connection shapes).
|
|
56
|
+
- **`kind: "brain"`** — optional and additive; present only on a **project brain**.
|
|
57
|
+
A brain is the co-owned agent/human memory file, and it gets stricter write
|
|
58
|
+
semantics: union-merge-on-save under a capture lock, tombstone-only deletes. It is
|
|
59
|
+
detected as `manifest.kind === "brain"` **OR** a `brain.*` basename — the filename
|
|
60
|
+
convention keeps working forever, and the flag makes those semantics survive a
|
|
61
|
+
rename. Plain canvases omit `kind` entirely, and older readers ignore it.
|
|
62
|
+
- `stats` is **informational only.** `totalBytes` is an uncompressed estimate (the
|
|
63
|
+
on-disk size depends on compression), and `itemCount` is derived from
|
|
64
|
+
`canvas.json.order`, which can disagree with the number of files actually under
|
|
65
|
+
`items/`. Never use `stats` as an integrity check.
|
|
66
|
+
- `sync` records whether the file is opted into the app's cloud sync; it carries no
|
|
67
|
+
content and no credentials.
|
|
68
|
+
|
|
38
69
|
## `canvas.json`
|
|
39
70
|
|
|
40
71
|
```json
|
|
@@ -46,21 +77,34 @@ to read partially.
|
|
|
46
77
|
"<id>": { "x": 0, "y": 0, "w": 280, "h": 80, "zKey": "a001", "zIndex": 1, "parentId": null }
|
|
47
78
|
},
|
|
48
79
|
"connections": [ // arrows between items
|
|
49
|
-
{ "id": "con_…", "fromId": "<id>", "toId": "<id>",
|
|
80
|
+
{ "id": "con_…", "fromId": "<id>", "toId": "<id>",
|
|
81
|
+
"relationship": "conflicts_with", "label": "corrects", // both optional
|
|
82
|
+
"arrowHead": true, "width": 2, "color": "#10b981", "style": "solid" }
|
|
50
83
|
],
|
|
51
84
|
"lines": [], "strokes": [], // freehand drawing
|
|
52
|
-
"
|
|
85
|
+
"nextGroupNumber": 4, // container auto-naming counter
|
|
86
|
+
"settings": { "background": "#0a0a0f", "gridStyle": "dots", "gridColor": "…" } // all optional
|
|
53
87
|
}
|
|
54
88
|
```
|
|
55
89
|
|
|
56
90
|
Position/geometry is kept in `canvas.json.positions`, **not** in the item file —
|
|
57
91
|
so moving an item never rewrites its content, and the spatial layout can be read
|
|
58
|
-
without loading every item.
|
|
92
|
+
without loading every item. `zKey` is a fractional index and is the source of truth
|
|
93
|
+
for z-order; `zIndex` is a numeric cache kept in step with the `order[]` index.
|
|
94
|
+
`settings` is optional and captures the *sender's* visual context, so a recipient
|
|
95
|
+
does not see someone else's canvas in their own theme.
|
|
96
|
+
|
|
97
|
+
`order` and `positions` are the two indexes a reader walks. A tolerant reader skips
|
|
98
|
+
an `order` entry with no `positions` row and an entry with no file under `items/`
|
|
99
|
+
(this package's parser does both) — but note that a writer which then re-serializes
|
|
100
|
+
that state can make the omission permanent.
|
|
59
101
|
|
|
60
102
|
## Item files — `items/<shard>/<id>.json`
|
|
61
103
|
|
|
62
|
-
Content only (no x/y/w/h
|
|
63
|
-
|
|
104
|
+
Content only — no `id` (it is in the path) and no `x/y/w/h/zIndex/zKey/parentId`
|
|
105
|
+
(those are in `canvas.json.positions`). The `type` field is one of exactly eleven
|
|
106
|
+
strings: `text`, `box`, `image`, `file`, `container`, `approval`, `link`,
|
|
107
|
+
`canvas-link`, `video`, `audio`, `code`. Example text item:
|
|
64
108
|
|
|
65
109
|
```json
|
|
66
110
|
{
|
|
@@ -70,12 +114,44 @@ Content only (no x/y/w/h). Common types: `text`, `box`, `image`, `file`,
|
|
|
70
114
|
"color": "#e8e8ed",
|
|
71
115
|
"border": true,
|
|
72
116
|
"heading": false,
|
|
73
|
-
"createdBy": "agent"
|
|
117
|
+
"createdBy": "agent",
|
|
118
|
+
"createdVia": "claude-code"
|
|
74
119
|
}
|
|
75
120
|
```
|
|
76
121
|
|
|
77
|
-
|
|
78
|
-
|
|
122
|
+
`createdBy` (`user` | `agent`) and the optional `createdVia` (which agent/channel
|
|
123
|
+
captured it) are the provenance bits the brain surfaces as badges and lenses.
|
|
124
|
+
|
|
125
|
+
## Bytes: when they are embedded vs referenced
|
|
126
|
+
|
|
127
|
+
**Embedded** — the bytes live inside the ZIP under `assets/`, and the item JSON
|
|
128
|
+
references them by key/sha:
|
|
129
|
+
|
|
130
|
+
| Item type | What is embedded |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `image` | the original image (plus an optional downscaled `thumbnailAssetId`). Non-destructive crop/rotate/annotation data lives in the item JSON; the original asset stays canonical. |
|
|
133
|
+
| `file` | the original file bytes. A **folder card** (`isFolder: true`) embeds the whole directory as one ZIP asset, with a `folderManifest` listing what's inside so the card renders without unzipping. |
|
|
134
|
+
| `video`, `audio` | the media bytes, streamed from the asset at render time rather than loaded whole. |
|
|
135
|
+
|
|
136
|
+
**Referenced, never embedded** — nothing is copied into the file:
|
|
137
|
+
|
|
138
|
+
| Item type | What it points at |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `link` | a remote `url` (+ cached Open Graph title/description; the OG image is fetched live, not stored) |
|
|
141
|
+
| `canvas-link` | another `.klypix` file by **absolute path on disk** — so it breaks if you email the file alone |
|
|
142
|
+
| `text`, `code`, `box`, `container`, `approval` | content is inline in the item JSON; there is no asset at all |
|
|
143
|
+
|
|
144
|
+
`file` / `video` / `audio` items may also carry `originalPath` — a convenience
|
|
145
|
+
pointer for "open in the OS app". The bytes are still embedded; the path is not the
|
|
146
|
+
source of truth.
|
|
147
|
+
|
|
148
|
+
Legacy files may carry an `image` item's bytes as an inline base64 `src` data URL
|
|
149
|
+
instead of an asset. New writers use `assetId` and leave `src` empty.
|
|
150
|
+
|
|
151
|
+
**This package reads assets but does not create them.** `create_canvas`,
|
|
152
|
+
`add_to_canvas` and `buildKlypix` write `manifest.json`, `canvas.json` and item
|
|
153
|
+
files — cards and arrows. Embedding binaries is done by the KLYPIX app when you drop
|
|
154
|
+
a file onto a canvas.
|
|
79
155
|
|
|
80
156
|
## Connections, links, tags
|
|
81
157
|
|
|
@@ -85,10 +161,56 @@ Items can reference an embedded binary in `assets/` (e.g. an `image`/`file`/
|
|
|
85
161
|
- **`[[wikilinks]]`** inside text content cross-link cards (and auto-draw edges).
|
|
86
162
|
- **`#tags`** inside text content group cards.
|
|
87
163
|
|
|
164
|
+
## Versioning — and a real limitation
|
|
165
|
+
|
|
166
|
+
`manifest.version` is the layout version and `manifest.schemaVersion` the document
|
|
167
|
+
version. Both are `4` today.
|
|
168
|
+
|
|
169
|
+
**There is no migration path registered for v4, and the v4 load path does not run
|
|
170
|
+
one.** Be precise about what that means, because it is a live limitation, not a
|
|
171
|
+
to-do that is quietly handled:
|
|
172
|
+
|
|
173
|
+
- The migration framework exists and works, but its table contains exactly two
|
|
174
|
+
steps, `1 → 2` and `2 → 3`. Only the legacy `.any` (v1–v3) read path walks it; the
|
|
175
|
+
v4 path never enters the migration runner.
|
|
176
|
+
- Both this package's parser and the KLYPIX app's v4 reader treat
|
|
177
|
+
`manifest.version >= 4` as "this is v4" and dispatch on nothing else — the app's
|
|
178
|
+
deserializer never reads `manifest.version`, `manifest.schemaVersion` or
|
|
179
|
+
`canvas.json.version` at all.
|
|
180
|
+
- So a hypothetical v5 or v6 file **opens as v4**: fields the reader does not know
|
|
181
|
+
are dropped, with no "this build is too old to open it" error anywhere. Saving it
|
|
182
|
+
from the app then rewrites `version: 4` — a silent downgrade. (This package's
|
|
183
|
+
`appendToKlypix` is non-destructive by construction: it mutates the parsed
|
|
184
|
+
manifest and `canvas.json` in place and leaves every existing item file byte-for-byte
|
|
185
|
+
untouched, so unknown fields survive a round trip through it.)
|
|
186
|
+
|
|
187
|
+
Consequences for anyone implementing against this format: do not assume a future
|
|
188
|
+
version will be rejected for you, and if you write `.klypix` files, do not bump
|
|
189
|
+
`manifest.version` past 4 expecting existing readers to refuse them safely. If you
|
|
190
|
+
extend the format, prefer **additive** optional fields (the way `manifest.kind` was
|
|
191
|
+
added) over a version bump.
|
|
192
|
+
|
|
88
193
|
## Legacy `.any` (v1–v3)
|
|
89
194
|
|
|
90
195
|
Older files keep an inline `items` array at the root of `canvas.json` instead of
|
|
91
|
-
the `items/` folder + `positions` map. The parser in this package handles both
|
|
196
|
+
the `items/` folder + `positions` map. The parser in this package handles both, and
|
|
197
|
+
detects the older shape by the absence of `positions` even if the manifest is
|
|
198
|
+
missing. Legacy files are migrated `1 → 2 → 3` on open by the app.
|
|
199
|
+
|
|
200
|
+
## Practical size limits
|
|
201
|
+
|
|
202
|
+
The format itself imposes no size limit — a `.klypix` is a ZIP. The limits below are
|
|
203
|
+
**guards in the KLYPIX app**, not properties of the format, and this package's
|
|
204
|
+
parser enforces none of them:
|
|
205
|
+
|
|
206
|
+
| Limit | Value | Where it applies |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| Per-file (leaf) on folder ingest | **200 MB** | a single file inside a dropped folder; anything larger is skipped and recorded in the card's `folderSkipped` list so you can see what was left out |
|
|
209
|
+
| Per folder card, total | **1 GB** | ingestion stops once a dropped folder would push the card past this |
|
|
210
|
+
| Per cloud share | **50 MB** | sharing a canvas through the app's cloud; a larger canvas is refused with a `too-large` result rather than truncated |
|
|
211
|
+
|
|
212
|
+
Nothing stops you writing a larger file locally with this library; expect the app's
|
|
213
|
+
share and folder-ingest paths to refuse it.
|
|
92
214
|
|
|
93
215
|
## Read / write it
|
|
94
216
|
|
|
@@ -102,4 +224,11 @@ const buf = await buildKlypix({ title: 'Plan', cards: [{ text: 'kickoff' }] });
|
|
|
102
224
|
fs.writeFileSync('plan.klypix', buf);
|
|
103
225
|
```
|
|
104
226
|
|
|
227
|
+
Or from a shell, against one of the examples in the tarball:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npm i klypix-mcp
|
|
231
|
+
npx klypix-read node_modules/klypix-mcp/examples/showcase-brain.klypix
|
|
232
|
+
```
|
|
233
|
+
|
|
105
234
|
That's the whole contract: **a ZIP you own, that any model can read and write.**
|
package/NOTICE
ADDED