yamlover 0.3.56 → 0.3.58
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 +48 -5
- package/bin/yamlover.js +41 -4
- package/dist/agent-docs/AGENTS.md +20 -333
- package/dist/agent-docs/AGENTS.yo +621 -0
- package/dist/builtin-taxonomy/$defs/.yo/meta.yo +0 -2
- package/dist/builtin-taxonomy/$defs/decision +34 -0
- package/dist/builtin-taxonomy/$defs/edit +60 -0
- package/dist/builtin-taxonomy/$defs/edit-answer +21 -0
- package/dist/builtin-taxonomy/$defs/edit-batch +31 -0
- package/dist/builtin-taxonomy/$defs/envelope +169 -0
- package/dist/builtin-taxonomy/$defs/event +85 -0
- package/dist/builtin-taxonomy/$defs/link +58 -0
- package/dist/builtin-taxonomy/$defs/task +28 -19
- package/dist/builtin-taxonomy/$defs/workflow +3 -0
- package/dist/builtin-taxonomy/ontos/.yo/body.yo +7 -1
- package/dist/client/assets/{decoded-CytDRqwJ.js → decoded-Bj1qJCo_.js} +1 -1
- package/dist/client/assets/{djvu-Da-iyAV_.js → djvu-lnurzbzN.js} +1 -1
- package/dist/client/assets/{docx-CX_gHuMq.js → docx-DpN_PtM8.js} +1 -1
- package/dist/client/assets/{heic-Bf9423pJ.js → heic-BqJutS0N.js} +1 -1
- package/dist/client/assets/imagemap-rdhcPlWy.js +1 -0
- package/dist/client/assets/index-0ALNONIF.js +962 -0
- package/dist/client/assets/index-BiETmvLO.css +1 -0
- package/dist/client/assets/map-Btm4SlVs.js +1 -0
- package/dist/client/assets/paged-Cjy3svw2.js +1 -0
- package/dist/client/assets/{openable-D48EbC_P.js → panzoom-BXEAw479.js} +2 -2
- package/dist/client/assets/{pdf-Dj6UMm-B.js → pdf-DvC2sbDN.js} +1 -1
- package/dist/client/assets/psd-BKmCWsdC.js +11 -0
- package/dist/client/assets/{spreadsheet-BmqsAKDF.js → spreadsheet-Coy5sooG.js} +1 -1
- package/dist/client/assets/tiff-IcWiNdYs.js +1 -0
- package/dist/client/assets/video-YC-ZvXg7.js +1 -0
- package/dist/client/assets/xyflow-CFNcu5cT.js +23 -0
- package/dist/client/index.html +2 -2
- package/dist/server.js +8818 -5114
- package/dist/wire/openapi.yo +935 -0
- package/package.json +6 -1
- package/dist/agent-docs/CLAUDE.md +0 -7
- package/dist/builtin-taxonomy/$defs/board +0 -15
- package/dist/client/assets/imagemap-BaCsSWT2.js +0 -1
- package/dist/client/assets/index-CLllgDtO.js +0 -765
- package/dist/client/assets/index-CYdxG8JF.css +0 -1
- package/dist/client/assets/map-C0h_m0kt.js +0 -1
- package/dist/client/assets/paged-YrFta0Z1.js +0 -1
- package/dist/client/assets/psd-vtV8RE5t.js +0 -11
- package/dist/client/assets/tiff-DTjYlW1c.js +0 -1
- package/dist/client/assets/xyflow-DLSA3Qi6.js +0 -23
- /package/dist/client/assets/{openable-CIGW-MKW.css → panzoom-CIGW-MKW.css} +0 -0
|
@@ -0,0 +1,935 @@
|
|
|
1
|
+
# THE OPENAPI DOCUMENT of the yamlover wire (docs/server/wire) — authored in yamlover (OpenAPI is
|
|
2
|
+
# YAML, and yamlover reads it), served as JSON at `GET /api/openapi` and printed by
|
|
3
|
+
# `npx yamlover --print-openapi`. Two things are filled in when it is served (wire-openapi.ts):
|
|
4
|
+
# `info.version` from wire-version.ts, and `components.schemas` from the `$defs` meta files this
|
|
5
|
+
# document names in `x-yamlover-defs` — the schemas live ONCE, in `$defs/`, and this document
|
|
6
|
+
# only refers to them. The routes are the CONTRACT and CONVENIENCE families of the inventory
|
|
7
|
+
# (docs/server/wire, the routes); the private surface (doctor, reindex, tasks, config,
|
|
8
|
+
# agent-docs) is deliberately absent. Status codes are quoted — a bare integer key is a position
|
|
9
|
+
# in yamlover, not a string.
|
|
10
|
+
openapi: 3.1.0
|
|
11
|
+
info:
|
|
12
|
+
title: the yamlover wire
|
|
13
|
+
version: '0' # replaced by WIRE_VERSION when served
|
|
14
|
+
description: >
|
|
15
|
+
The HTTP protocol between a yamlover server and its clients. A node is read as a yamlover
|
|
16
|
+
document (the content envelope), edited by batches of surgical text edits, and every change -
|
|
17
|
+
a client's or an external one - is pushed as a diff on one event stream. Paths in parameters
|
|
18
|
+
and bodies are colon paths (`:a:b:0`); only `/api/content/{path}` takes a slash path.
|
|
19
|
+
x-yamlover-defs:
|
|
20
|
+
- envelope
|
|
21
|
+
- link
|
|
22
|
+
- edit
|
|
23
|
+
- edit-batch
|
|
24
|
+
- edit-answer
|
|
25
|
+
- event
|
|
26
|
+
servers:
|
|
27
|
+
- url: /
|
|
28
|
+
description: the local server (`npx yamlover <root>`), or the deployment's `--base-path`
|
|
29
|
+
tags:
|
|
30
|
+
- name: contract
|
|
31
|
+
description: the model - what any client needs and any server answers
|
|
32
|
+
- name: convenience
|
|
33
|
+
description: derived helpers a second client may skip or compute for itself
|
|
34
|
+
components:
|
|
35
|
+
parameters:
|
|
36
|
+
path:
|
|
37
|
+
name: path
|
|
38
|
+
in: query
|
|
39
|
+
description: a colon path (`:a:b:0`); absent or `:` is the root
|
|
40
|
+
schema:
|
|
41
|
+
type: string
|
|
42
|
+
depth:
|
|
43
|
+
name: depth
|
|
44
|
+
in: query
|
|
45
|
+
description: the document-boundary budget - an integer, or `.inf`; absent picks the node's default (unlimited for a text document, 1 for a directory or a binary)
|
|
46
|
+
schema:
|
|
47
|
+
type: string
|
|
48
|
+
responses:
|
|
49
|
+
refused:
|
|
50
|
+
description: the request was refused or needs recovery; an explicit recovery conflict preserves its journal and competing external bytes
|
|
51
|
+
content:
|
|
52
|
+
application/json:
|
|
53
|
+
schema:
|
|
54
|
+
type: object
|
|
55
|
+
properties:
|
|
56
|
+
error:
|
|
57
|
+
type: string
|
|
58
|
+
example:
|
|
59
|
+
error: 'unknown edit op: frobnicate'
|
|
60
|
+
notFound:
|
|
61
|
+
description: the path names no node
|
|
62
|
+
content:
|
|
63
|
+
application/json:
|
|
64
|
+
schema:
|
|
65
|
+
type: object
|
|
66
|
+
properties:
|
|
67
|
+
error:
|
|
68
|
+
type: string
|
|
69
|
+
paths:
|
|
70
|
+
/api/info:
|
|
71
|
+
get:
|
|
72
|
+
tags: [contract]
|
|
73
|
+
summary: the root title, the read-only flag and the wire version
|
|
74
|
+
responses:
|
|
75
|
+
'200':
|
|
76
|
+
description: ok
|
|
77
|
+
content:
|
|
78
|
+
application/json:
|
|
79
|
+
schema:
|
|
80
|
+
type: object
|
|
81
|
+
properties:
|
|
82
|
+
root:
|
|
83
|
+
type: string
|
|
84
|
+
readOnly:
|
|
85
|
+
type: boolean
|
|
86
|
+
wire:
|
|
87
|
+
type: integer
|
|
88
|
+
example:
|
|
89
|
+
root: yamlover
|
|
90
|
+
readOnly: false
|
|
91
|
+
wire: 1
|
|
92
|
+
'/api/content/{path}':
|
|
93
|
+
get:
|
|
94
|
+
tags: [contract]
|
|
95
|
+
summary: THE ONE WIRE - the node as a content envelope
|
|
96
|
+
description: >
|
|
97
|
+
Answers `text/yamlover`: the node's authored text under a store-derived header, with the
|
|
98
|
+
sidecar and the relations panel - `$defs/envelope`. `path` is a SLASH path here (the URL);
|
|
99
|
+
`/api/content` alone is the root.
|
|
100
|
+
parameters:
|
|
101
|
+
- name: path
|
|
102
|
+
in: path
|
|
103
|
+
required: true
|
|
104
|
+
description: 'the node''s slash path, segments percent-encoded; a position that is the slot of a pull link walks THROUGH it (`host/11` is the card `- *:: elsewhere: card.yo` names, `host/11/0` its first element) - the envelope''s `path` is then the walked path and `canonical` where the node lives'
|
|
105
|
+
schema:
|
|
106
|
+
type: string
|
|
107
|
+
- $ref: '#/components/parameters/depth'
|
|
108
|
+
- name: editing
|
|
109
|
+
in: query
|
|
110
|
+
description: use 1 to reconcile source and return a revision for guarded saves
|
|
111
|
+
schema:
|
|
112
|
+
type: string
|
|
113
|
+
- name: range
|
|
114
|
+
in: query
|
|
115
|
+
description: 'the window over the top node''s rendered entries - `A-B`, `A-`, `-B`, `.len-(N)-` (the range grammar minus `.`); a node past 1000 entries auto-windows to `0-500` without it'
|
|
116
|
+
schema:
|
|
117
|
+
type: string
|
|
118
|
+
responses:
|
|
119
|
+
'200':
|
|
120
|
+
description: the content envelope
|
|
121
|
+
headers:
|
|
122
|
+
X-Yamlover-Revision:
|
|
123
|
+
description: project SHA-256 revision, only when editing=1
|
|
124
|
+
schema:
|
|
125
|
+
type: string
|
|
126
|
+
content:
|
|
127
|
+
text/yamlover:
|
|
128
|
+
schema:
|
|
129
|
+
$ref: '#/components/schemas/envelope'
|
|
130
|
+
example: |
|
|
131
|
+
wire: 2
|
|
132
|
+
path: :notes:todo.yo
|
|
133
|
+
documentPath: :notes:todo.yo
|
|
134
|
+
type: object
|
|
135
|
+
hasKeyed: true
|
|
136
|
+
hasOrdinal: false
|
|
137
|
+
concrete: file/yamlover
|
|
138
|
+
title: todo
|
|
139
|
+
depth: .inf
|
|
140
|
+
source: |
|
|
141
|
+
title: todo
|
|
142
|
+
items: *: items
|
|
143
|
+
side:
|
|
144
|
+
"": {}
|
|
145
|
+
\/items:
|
|
146
|
+
member: true
|
|
147
|
+
stub:
|
|
148
|
+
$yamloverLink: {kind: array, type: array, hasKeyed: false, hasOrdinal: true, path: :notes:todo.yo:items, concrete: yamlover, hasChildren: true, count: 3}
|
|
149
|
+
relations:
|
|
150
|
+
..:
|
|
151
|
+
$yamloverLink: {kind: omni, type: omni, path: :notes, format: x-yamlover-chapter, concrete: dir/index.yo, hasChildren: true, count: 2, title: Notes}
|
|
152
|
+
':: ...: ?#: pet: $':
|
|
153
|
+
$yamloverLink: {kind: omni, type: omni, path: :team:alice, concrete: yamlover, hasChildren: true, count: 3}
|
|
154
|
+
'404':
|
|
155
|
+
$ref: '#/components/responses/notFound'
|
|
156
|
+
'400':
|
|
157
|
+
$ref: '#/components/responses/refused'
|
|
158
|
+
/api/blob:
|
|
159
|
+
get:
|
|
160
|
+
tags: [contract]
|
|
161
|
+
summary: the raw bytes of a file-backed node, with single byte-range support
|
|
162
|
+
parameters:
|
|
163
|
+
- $ref: '#/components/parameters/path'
|
|
164
|
+
- name: Range
|
|
165
|
+
in: header
|
|
166
|
+
schema: {type: string}
|
|
167
|
+
- name: If-Range
|
|
168
|
+
in: header
|
|
169
|
+
schema: {type: string}
|
|
170
|
+
responses:
|
|
171
|
+
'200':
|
|
172
|
+
description: the bytes, Content-Type from the format; Accept-Ranges, Content-Length and ETag
|
|
173
|
+
content:
|
|
174
|
+
'*/*':
|
|
175
|
+
schema: {type: string, format: binary}
|
|
176
|
+
'206':
|
|
177
|
+
description: the requested byte range, with Content-Range
|
|
178
|
+
'416':
|
|
179
|
+
description: invalid or unsatisfiable byte range
|
|
180
|
+
'404':
|
|
181
|
+
$ref: '#/components/responses/notFound'
|
|
182
|
+
head:
|
|
183
|
+
tags: [contract]
|
|
184
|
+
summary: file headers without the body
|
|
185
|
+
parameters:
|
|
186
|
+
- $ref: '#/components/parameters/path'
|
|
187
|
+
responses:
|
|
188
|
+
'200':
|
|
189
|
+
description: Content-Type, Content-Length, Accept-Ranges and ETag
|
|
190
|
+
'404':
|
|
191
|
+
$ref: '#/components/responses/notFound'
|
|
192
|
+
/api/tree:
|
|
193
|
+
get:
|
|
194
|
+
tags: [contract]
|
|
195
|
+
summary: the TOC projection of a subtree
|
|
196
|
+
parameters:
|
|
197
|
+
- $ref: '#/components/parameters/path'
|
|
198
|
+
- name: depth
|
|
199
|
+
in: query
|
|
200
|
+
description: levels of the tree (default 3)
|
|
201
|
+
schema:
|
|
202
|
+
type: integer
|
|
203
|
+
responses:
|
|
204
|
+
'200':
|
|
205
|
+
description: a TreeNode - label, path, type, children; a truncation as `notLoaded`
|
|
206
|
+
content:
|
|
207
|
+
application/json:
|
|
208
|
+
schema:
|
|
209
|
+
type: object
|
|
210
|
+
properties:
|
|
211
|
+
path:
|
|
212
|
+
type: string
|
|
213
|
+
label:
|
|
214
|
+
type: string
|
|
215
|
+
children:
|
|
216
|
+
type: array
|
|
217
|
+
items:
|
|
218
|
+
type: object
|
|
219
|
+
'404':
|
|
220
|
+
$ref: '#/components/responses/notFound'
|
|
221
|
+
/api/source:
|
|
222
|
+
get:
|
|
223
|
+
tags: [contract]
|
|
224
|
+
summary: the node's yamlover source, as authored
|
|
225
|
+
parameters:
|
|
226
|
+
- $ref: '#/components/parameters/path'
|
|
227
|
+
responses:
|
|
228
|
+
'200':
|
|
229
|
+
description: ok
|
|
230
|
+
content:
|
|
231
|
+
application/json:
|
|
232
|
+
schema:
|
|
233
|
+
type: object
|
|
234
|
+
properties:
|
|
235
|
+
source:
|
|
236
|
+
type: string
|
|
237
|
+
example:
|
|
238
|
+
source: "a: 1\nb: hello\n"
|
|
239
|
+
'404':
|
|
240
|
+
$ref: '#/components/responses/notFound'
|
|
241
|
+
/api/schema:
|
|
242
|
+
get:
|
|
243
|
+
tags: [contract]
|
|
244
|
+
summary: the projected instance schema of a node
|
|
245
|
+
parameters:
|
|
246
|
+
- $ref: '#/components/parameters/path'
|
|
247
|
+
- $ref: '#/components/parameters/depth'
|
|
248
|
+
responses:
|
|
249
|
+
'200':
|
|
250
|
+
description: the schema projection (yamlover meta as JSON)
|
|
251
|
+
content:
|
|
252
|
+
application/json:
|
|
253
|
+
schema:
|
|
254
|
+
type: object
|
|
255
|
+
/api/query:
|
|
256
|
+
get:
|
|
257
|
+
tags: [contract]
|
|
258
|
+
summary: evaluate a query
|
|
259
|
+
parameters:
|
|
260
|
+
- name: q
|
|
261
|
+
in: query
|
|
262
|
+
required: true
|
|
263
|
+
description: the query, in the colon grammar (docs/language/pointers/queries)
|
|
264
|
+
schema:
|
|
265
|
+
type: string
|
|
266
|
+
- $ref: '#/components/parameters/path'
|
|
267
|
+
- name: shape
|
|
268
|
+
in: query
|
|
269
|
+
description: absent - matching paths; `tree` - one TreeNode per match; `filter` - the tree filtered to the matches
|
|
270
|
+
schema:
|
|
271
|
+
type: string
|
|
272
|
+
enum: [tree, filter]
|
|
273
|
+
responses:
|
|
274
|
+
'200':
|
|
275
|
+
description: the matches
|
|
276
|
+
content:
|
|
277
|
+
application/json:
|
|
278
|
+
schema:
|
|
279
|
+
type: object
|
|
280
|
+
properties:
|
|
281
|
+
results:
|
|
282
|
+
type: array
|
|
283
|
+
root:
|
|
284
|
+
type: object
|
|
285
|
+
matches:
|
|
286
|
+
type: array
|
|
287
|
+
items:
|
|
288
|
+
type: string
|
|
289
|
+
truncated:
|
|
290
|
+
type: boolean
|
|
291
|
+
example:
|
|
292
|
+
results: [':notes:todo.yo', ':notes:done.yo']
|
|
293
|
+
'400':
|
|
294
|
+
$ref: '#/components/responses/refused'
|
|
295
|
+
/api/events:
|
|
296
|
+
get:
|
|
297
|
+
tags: [contract]
|
|
298
|
+
summary: the event stream - every change, as it lands
|
|
299
|
+
description: '`text/event-stream`: one `$defs/event` per `data:` frame; `: connected` then a `hello` frame on connect, `: ping` every 30 s. No replay - but a reconnect whose `hello` names the same `instance` and `seq` it last saw missed nothing and keeps what it holds; anything else means everything loaded is stale.'
|
|
300
|
+
responses:
|
|
301
|
+
'200':
|
|
302
|
+
description: the stream
|
|
303
|
+
content:
|
|
304
|
+
text/event-stream:
|
|
305
|
+
schema:
|
|
306
|
+
$ref: '#/components/schemas/event'
|
|
307
|
+
example: |
|
|
308
|
+
: connected
|
|
309
|
+
|
|
310
|
+
data: {"type":"diff","added":[],"changed":[":notes:todo.yo"],"removed":[],"moved":[]}
|
|
311
|
+
|
|
312
|
+
data: {"type":"task","task":{"id":"index","label":"indexing","state":"done","progress":{"done":12,"total":12},"startedAt":1756400000000,"finishedAt":1756400000400}}
|
|
313
|
+
/api/undo:
|
|
314
|
+
post:
|
|
315
|
+
tags: [contract]
|
|
316
|
+
summary: reverse a recorded operation; redo reverses the undo operation
|
|
317
|
+
description: >
|
|
318
|
+
Requires safety revision and request identity. Preserves files and references through
|
|
319
|
+
the mutation journal; conflicts rather than overwriting intervening changes. Receipts
|
|
320
|
+
and undo data expire after 30 days. The returned operationId identifies the inverse.
|
|
321
|
+
requestBody:
|
|
322
|
+
required: true
|
|
323
|
+
content:
|
|
324
|
+
application/json:
|
|
325
|
+
schema:
|
|
326
|
+
type: object
|
|
327
|
+
required: [operationId, safety]
|
|
328
|
+
properties:
|
|
329
|
+
operationId:
|
|
330
|
+
type: string
|
|
331
|
+
safety:
|
|
332
|
+
type: object
|
|
333
|
+
required: [revision, operationId]
|
|
334
|
+
properties:
|
|
335
|
+
revision:
|
|
336
|
+
type: string
|
|
337
|
+
operationId:
|
|
338
|
+
type: string
|
|
339
|
+
responses:
|
|
340
|
+
'200':
|
|
341
|
+
description: the inverse committed or its original result was replayed
|
|
342
|
+
content:
|
|
343
|
+
application/json:
|
|
344
|
+
schema:
|
|
345
|
+
$ref: '#/components/schemas/edit-answer'
|
|
346
|
+
'409':
|
|
347
|
+
description: changed source, reused identity or already reversed operation
|
|
348
|
+
'410':
|
|
349
|
+
description: undo history expired or unavailable
|
|
350
|
+
'428':
|
|
351
|
+
description: revision and request identity required
|
|
352
|
+
/api/edit:
|
|
353
|
+
post:
|
|
354
|
+
tags: [contract]
|
|
355
|
+
summary: a batch of surgical edits
|
|
356
|
+
requestBody:
|
|
357
|
+
required: true
|
|
358
|
+
content:
|
|
359
|
+
application/json:
|
|
360
|
+
schema:
|
|
361
|
+
$ref: '#/components/schemas/edit-batch'
|
|
362
|
+
example:
|
|
363
|
+
edits:
|
|
364
|
+
- {path: ':notes:todo.yo:title', op: emplace, yamlover: 'todo, revised'}
|
|
365
|
+
- {path: ':notes', op: insert, concrete: file/yamlover, name: done, yamlover: 'title: done'}
|
|
366
|
+
responses:
|
|
367
|
+
'200':
|
|
368
|
+
description: the batch folded
|
|
369
|
+
content:
|
|
370
|
+
application/json:
|
|
371
|
+
schema:
|
|
372
|
+
$ref: '#/components/schemas/edit-answer'
|
|
373
|
+
example:
|
|
374
|
+
ok: true
|
|
375
|
+
path: :notes:done.yo
|
|
376
|
+
'400':
|
|
377
|
+
$ref: '#/components/responses/refused'
|
|
378
|
+
'409':
|
|
379
|
+
description: stale source revision, reused identity with different payload, or recovery conflict
|
|
380
|
+
'410':
|
|
381
|
+
description: operation identity expired; reconcile before submitting a new operation
|
|
382
|
+
'428':
|
|
383
|
+
description: safety was supplied without a valid revision
|
|
384
|
+
/api/link:
|
|
385
|
+
post:
|
|
386
|
+
tags: [contract]
|
|
387
|
+
summary: link a node into a target's body - the node stays, the target gains a pointer element to it
|
|
388
|
+
requestBody:
|
|
389
|
+
required: true
|
|
390
|
+
content:
|
|
391
|
+
application/json:
|
|
392
|
+
schema:
|
|
393
|
+
type: object
|
|
394
|
+
members:
|
|
395
|
+
from:
|
|
396
|
+
type: string
|
|
397
|
+
description: the node to link (a file or directory path)
|
|
398
|
+
to:
|
|
399
|
+
type: string
|
|
400
|
+
description: the chapter, task or directory whose body gains the pointer
|
|
401
|
+
responses:
|
|
402
|
+
'200':
|
|
403
|
+
description: the target and the pointer text appended
|
|
404
|
+
content:
|
|
405
|
+
application/json:
|
|
406
|
+
schema:
|
|
407
|
+
type: object
|
|
408
|
+
'400':
|
|
409
|
+
$ref: '#/components/responses/refused'
|
|
410
|
+
/api/unlink:
|
|
411
|
+
post:
|
|
412
|
+
tags: [contract]
|
|
413
|
+
summary: delete a LINKED node's slot - the pointer entry goes, references to that place follow the node
|
|
414
|
+
requestBody:
|
|
415
|
+
required: true
|
|
416
|
+
content:
|
|
417
|
+
application/json:
|
|
418
|
+
schema:
|
|
419
|
+
type: object
|
|
420
|
+
members:
|
|
421
|
+
path:
|
|
422
|
+
type: string
|
|
423
|
+
description: the link's slot - the holder's path plus the pointer entry's position (or key)
|
|
424
|
+
responses:
|
|
425
|
+
'200':
|
|
426
|
+
description: the removed slot, the node's actual path, the references rewritten, the reindex diff
|
|
427
|
+
content:
|
|
428
|
+
application/json:
|
|
429
|
+
schema:
|
|
430
|
+
type: object
|
|
431
|
+
'400':
|
|
432
|
+
$ref: '#/components/responses/refused'
|
|
433
|
+
/api/mv:
|
|
434
|
+
post:
|
|
435
|
+
tags: [contract]
|
|
436
|
+
summary: move a file or directory, relinking what pointed at it
|
|
437
|
+
requestBody:
|
|
438
|
+
required: true
|
|
439
|
+
content:
|
|
440
|
+
application/json:
|
|
441
|
+
schema:
|
|
442
|
+
type: object
|
|
443
|
+
properties:
|
|
444
|
+
from:
|
|
445
|
+
type: string
|
|
446
|
+
to:
|
|
447
|
+
type: string
|
|
448
|
+
example:
|
|
449
|
+
from: :notes:todo.yo
|
|
450
|
+
to: :archive:todo.yo
|
|
451
|
+
responses:
|
|
452
|
+
'200':
|
|
453
|
+
description: the move report and the index diff
|
|
454
|
+
content:
|
|
455
|
+
application/json:
|
|
456
|
+
schema:
|
|
457
|
+
type: object
|
|
458
|
+
'400':
|
|
459
|
+
$ref: '#/components/responses/refused'
|
|
460
|
+
/api/rekey:
|
|
461
|
+
post:
|
|
462
|
+
tags: [contract]
|
|
463
|
+
summary: rename a key in place, relinking what pointed at it — keyless → keyed and back too
|
|
464
|
+
requestBody:
|
|
465
|
+
required: true
|
|
466
|
+
content:
|
|
467
|
+
application/json:
|
|
468
|
+
schema:
|
|
469
|
+
type: object
|
|
470
|
+
properties:
|
|
471
|
+
path:
|
|
472
|
+
type: string
|
|
473
|
+
description: the entry — by its key, or by its POSITION when a keyless chunk takes a key
|
|
474
|
+
key:
|
|
475
|
+
type: string
|
|
476
|
+
nullable: true
|
|
477
|
+
description: the new key; `null` DROPS it — the entry turns keyless in place (the key cell's dash); `title` and hidden overlay keys are refused
|
|
478
|
+
example:
|
|
479
|
+
path: :notes:todo.yo:title
|
|
480
|
+
key: heading
|
|
481
|
+
responses:
|
|
482
|
+
'200':
|
|
483
|
+
description: the new path, the relink report and the diff
|
|
484
|
+
content:
|
|
485
|
+
application/json:
|
|
486
|
+
schema:
|
|
487
|
+
type: object
|
|
488
|
+
properties:
|
|
489
|
+
path:
|
|
490
|
+
type: string
|
|
491
|
+
'400':
|
|
492
|
+
$ref: '#/components/responses/refused'
|
|
493
|
+
/api/paste:
|
|
494
|
+
post:
|
|
495
|
+
tags: [contract]
|
|
496
|
+
summary: file clipboard content beside a node
|
|
497
|
+
requestBody:
|
|
498
|
+
required: true
|
|
499
|
+
content:
|
|
500
|
+
application/json:
|
|
501
|
+
schema:
|
|
502
|
+
type: object
|
|
503
|
+
responses:
|
|
504
|
+
'201':
|
|
505
|
+
description: what was born
|
|
506
|
+
content:
|
|
507
|
+
application/json:
|
|
508
|
+
schema:
|
|
509
|
+
type: object
|
|
510
|
+
'400':
|
|
511
|
+
$ref: '#/components/responses/refused'
|
|
512
|
+
/api/annotations:
|
|
513
|
+
get:
|
|
514
|
+
tags: [contract]
|
|
515
|
+
summary: the annotations on a material
|
|
516
|
+
parameters:
|
|
517
|
+
- $ref: '#/components/parameters/path'
|
|
518
|
+
responses:
|
|
519
|
+
'200':
|
|
520
|
+
description: the tag applications, with their fragments
|
|
521
|
+
content:
|
|
522
|
+
application/json:
|
|
523
|
+
schema:
|
|
524
|
+
type: array
|
|
525
|
+
items:
|
|
526
|
+
type: object
|
|
527
|
+
/api/annotate:
|
|
528
|
+
post:
|
|
529
|
+
tags: [contract]
|
|
530
|
+
summary: apply a tag to a node or a fragment of it
|
|
531
|
+
requestBody:
|
|
532
|
+
required: true
|
|
533
|
+
content:
|
|
534
|
+
application/json:
|
|
535
|
+
schema:
|
|
536
|
+
type: object
|
|
537
|
+
properties:
|
|
538
|
+
target:
|
|
539
|
+
type: string
|
|
540
|
+
description: the NODE to tag — a walked path (`:session:5`, a card through its slot) resolves to the node it names; the bookmark lands in that node's own document, never in the host's
|
|
541
|
+
tag:
|
|
542
|
+
type: string
|
|
543
|
+
selector:
|
|
544
|
+
type: object
|
|
545
|
+
example:
|
|
546
|
+
target: :notes:todo.yo
|
|
547
|
+
tag: :yamlover:ontos:workflow:dev:ready
|
|
548
|
+
responses:
|
|
549
|
+
'201':
|
|
550
|
+
description: applied
|
|
551
|
+
content:
|
|
552
|
+
application/json:
|
|
553
|
+
schema:
|
|
554
|
+
type: object
|
|
555
|
+
properties:
|
|
556
|
+
ok:
|
|
557
|
+
type: boolean
|
|
558
|
+
'400':
|
|
559
|
+
$ref: '#/components/responses/refused'
|
|
560
|
+
delete:
|
|
561
|
+
tags: [contract]
|
|
562
|
+
summary: remove a tag application
|
|
563
|
+
parameters:
|
|
564
|
+
- name: target
|
|
565
|
+
in: query
|
|
566
|
+
required: true
|
|
567
|
+
schema:
|
|
568
|
+
type: string
|
|
569
|
+
- name: tag
|
|
570
|
+
in: query
|
|
571
|
+
required: true
|
|
572
|
+
schema:
|
|
573
|
+
type: string
|
|
574
|
+
- name: selector
|
|
575
|
+
in: query
|
|
576
|
+
description: the fragment's selector as JSON, when the application is on a fragment
|
|
577
|
+
schema:
|
|
578
|
+
type: string
|
|
579
|
+
responses:
|
|
580
|
+
'200':
|
|
581
|
+
description: removed
|
|
582
|
+
content:
|
|
583
|
+
application/json:
|
|
584
|
+
schema:
|
|
585
|
+
type: object
|
|
586
|
+
'400':
|
|
587
|
+
$ref: '#/components/responses/refused'
|
|
588
|
+
/api/fragment:
|
|
589
|
+
post:
|
|
590
|
+
tags: [contract]
|
|
591
|
+
summary: mark a region of a material, with no tag yet
|
|
592
|
+
requestBody:
|
|
593
|
+
required: true
|
|
594
|
+
content:
|
|
595
|
+
application/json:
|
|
596
|
+
schema:
|
|
597
|
+
type: object
|
|
598
|
+
properties:
|
|
599
|
+
target:
|
|
600
|
+
type: string
|
|
601
|
+
selector:
|
|
602
|
+
type: object
|
|
603
|
+
responses:
|
|
604
|
+
'201':
|
|
605
|
+
description: the fragment made
|
|
606
|
+
content:
|
|
607
|
+
application/json:
|
|
608
|
+
schema:
|
|
609
|
+
type: object
|
|
610
|
+
'400':
|
|
611
|
+
$ref: '#/components/responses/refused'
|
|
612
|
+
/api/tagged:
|
|
613
|
+
get:
|
|
614
|
+
tags: [contract]
|
|
615
|
+
summary: the materials filed under a tag
|
|
616
|
+
parameters:
|
|
617
|
+
- $ref: '#/components/parameters/path'
|
|
618
|
+
responses:
|
|
619
|
+
'200':
|
|
620
|
+
description: the targets
|
|
621
|
+
content:
|
|
622
|
+
application/json:
|
|
623
|
+
schema:
|
|
624
|
+
type: array
|
|
625
|
+
'404':
|
|
626
|
+
$ref: '#/components/responses/notFound'
|
|
627
|
+
/api/tag:
|
|
628
|
+
post:
|
|
629
|
+
tags: [contract]
|
|
630
|
+
summary: create a tag in the project taxonomy (or find it)
|
|
631
|
+
requestBody:
|
|
632
|
+
required: true
|
|
633
|
+
content:
|
|
634
|
+
application/json:
|
|
635
|
+
schema:
|
|
636
|
+
type: object
|
|
637
|
+
properties:
|
|
638
|
+
name:
|
|
639
|
+
type: string
|
|
640
|
+
responses:
|
|
641
|
+
'201':
|
|
642
|
+
description: the tag
|
|
643
|
+
content:
|
|
644
|
+
application/json:
|
|
645
|
+
schema:
|
|
646
|
+
type: object
|
|
647
|
+
properties:
|
|
648
|
+
path:
|
|
649
|
+
type: string
|
|
650
|
+
name:
|
|
651
|
+
type: string
|
|
652
|
+
color:
|
|
653
|
+
type: string
|
|
654
|
+
created:
|
|
655
|
+
type: boolean
|
|
656
|
+
'400':
|
|
657
|
+
$ref: '#/components/responses/refused'
|
|
658
|
+
/api/workflows:
|
|
659
|
+
get:
|
|
660
|
+
tags: [contract]
|
|
661
|
+
summary: every workflow the index holds
|
|
662
|
+
description: >-
|
|
663
|
+
Each `x-yamlover-workflow` node, the bundled taxonomy's included, projected as a tag ref -
|
|
664
|
+
the task page's workflow picker.
|
|
665
|
+
responses:
|
|
666
|
+
'200':
|
|
667
|
+
description: the workflows, in path order
|
|
668
|
+
content:
|
|
669
|
+
application/json:
|
|
670
|
+
schema:
|
|
671
|
+
type: object
|
|
672
|
+
properties:
|
|
673
|
+
workflows:
|
|
674
|
+
type: array
|
|
675
|
+
items:
|
|
676
|
+
type: object
|
|
677
|
+
properties:
|
|
678
|
+
path: { type: string }
|
|
679
|
+
name: { type: string }
|
|
680
|
+
color: { type: [string, 'null'] }
|
|
681
|
+
/api/board:
|
|
682
|
+
get:
|
|
683
|
+
tags: [contract]
|
|
684
|
+
summary: a task's board - its subtasks in lanes
|
|
685
|
+
parameters:
|
|
686
|
+
- $ref: '#/components/parameters/path'
|
|
687
|
+
responses:
|
|
688
|
+
'200':
|
|
689
|
+
description: the resolved board
|
|
690
|
+
content:
|
|
691
|
+
application/json:
|
|
692
|
+
schema:
|
|
693
|
+
type: object
|
|
694
|
+
properties:
|
|
695
|
+
seeded:
|
|
696
|
+
type: boolean
|
|
697
|
+
workflow:
|
|
698
|
+
description: >-
|
|
699
|
+
the workflow the lanes read - `own: true` when the task's own `workflow:`
|
|
700
|
+
field names it, else inherited from the nearest ancestor task; null when none
|
|
701
|
+
type: [object, 'null']
|
|
702
|
+
properties:
|
|
703
|
+
path: { type: string }
|
|
704
|
+
name: { type: string }
|
|
705
|
+
color: { type: [string, 'null'] }
|
|
706
|
+
own: { type: boolean }
|
|
707
|
+
'404':
|
|
708
|
+
$ref: '#/components/responses/notFound'
|
|
709
|
+
post:
|
|
710
|
+
tags: [contract]
|
|
711
|
+
summary: move a card, save the layout, or reconcile the board
|
|
712
|
+
requestBody:
|
|
713
|
+
required: true
|
|
714
|
+
content:
|
|
715
|
+
application/json:
|
|
716
|
+
schema:
|
|
717
|
+
type: object
|
|
718
|
+
properties:
|
|
719
|
+
path:
|
|
720
|
+
type: string
|
|
721
|
+
op:
|
|
722
|
+
type: string
|
|
723
|
+
enum: [structure, move, reconcile]
|
|
724
|
+
structure:
|
|
725
|
+
type: array
|
|
726
|
+
task:
|
|
727
|
+
type: string
|
|
728
|
+
from:
|
|
729
|
+
type: object
|
|
730
|
+
to:
|
|
731
|
+
type: object
|
|
732
|
+
responses:
|
|
733
|
+
'201':
|
|
734
|
+
description: the resolved board
|
|
735
|
+
content:
|
|
736
|
+
application/json:
|
|
737
|
+
schema:
|
|
738
|
+
type: object
|
|
739
|
+
'400':
|
|
740
|
+
$ref: '#/components/responses/refused'
|
|
741
|
+
/api/dangling:
|
|
742
|
+
get:
|
|
743
|
+
tags: [contract]
|
|
744
|
+
summary: the pointers that did not resolve at index time
|
|
745
|
+
responses:
|
|
746
|
+
'200':
|
|
747
|
+
description: the list
|
|
748
|
+
content:
|
|
749
|
+
application/json:
|
|
750
|
+
schema:
|
|
751
|
+
type: array
|
|
752
|
+
items:
|
|
753
|
+
type: object
|
|
754
|
+
properties:
|
|
755
|
+
from:
|
|
756
|
+
type: string
|
|
757
|
+
raw:
|
|
758
|
+
type: string
|
|
759
|
+
reason:
|
|
760
|
+
type: string
|
|
761
|
+
/api/video:
|
|
762
|
+
get:
|
|
763
|
+
tags: [convenience]
|
|
764
|
+
summary: prepare an MP4 for frame playback, or stream its playable bytes
|
|
765
|
+
description: >-
|
|
766
|
+
Requires ffmpeg and ffprobe. Non-H.264 videos receive a cached H.264 preview under .yo/videos.
|
|
767
|
+
Completed metadata and previews survive restart; changed or deleted sources invalidate them.
|
|
768
|
+
Read-only servers reuse existing products without writing caches.
|
|
769
|
+
Concurrent work is shared; original files are unchanged. Frame timestamps describe
|
|
770
|
+
the playable stream, in seconds. Byte streaming accepts the same Range and If-Range
|
|
771
|
+
headers as /api/blob. HEAD with stream=1 returns stream headers only.
|
|
772
|
+
parameters:
|
|
773
|
+
- $ref: '#/components/parameters/path'
|
|
774
|
+
- name: stream
|
|
775
|
+
in: query
|
|
776
|
+
schema: {type: string, enum: ['1']}
|
|
777
|
+
- name: Range
|
|
778
|
+
in: header
|
|
779
|
+
schema: {type: string}
|
|
780
|
+
- name: If-Range
|
|
781
|
+
in: header
|
|
782
|
+
schema: {type: string}
|
|
783
|
+
responses:
|
|
784
|
+
'200':
|
|
785
|
+
description: metadata, or the playable MP4 when stream=1
|
|
786
|
+
content:
|
|
787
|
+
application/json:
|
|
788
|
+
schema:
|
|
789
|
+
type: object
|
|
790
|
+
required: [duration, frames, width, height, codec, preview, revision]
|
|
791
|
+
properties:
|
|
792
|
+
duration: {type: number}
|
|
793
|
+
frames:
|
|
794
|
+
type: array
|
|
795
|
+
items: {type: number}
|
|
796
|
+
width: {type: integer}
|
|
797
|
+
height: {type: integer}
|
|
798
|
+
codec: {type: string}
|
|
799
|
+
preview: {type: boolean}
|
|
800
|
+
revision: {type: string}
|
|
801
|
+
video/mp4:
|
|
802
|
+
schema: {type: string, format: binary}
|
|
803
|
+
'206':
|
|
804
|
+
description: playable stream byte range
|
|
805
|
+
'416':
|
|
806
|
+
description: unsatisfiable stream byte range
|
|
807
|
+
'415':
|
|
808
|
+
description: not an MP4
|
|
809
|
+
'503':
|
|
810
|
+
description: preparation failed, including missing FFmpeg
|
|
811
|
+
'404':
|
|
812
|
+
$ref: '#/components/responses/notFound'
|
|
813
|
+
/api/thumb:
|
|
814
|
+
get:
|
|
815
|
+
tags: [convenience]
|
|
816
|
+
summary: a thumbnail of a file-backed blob, generated once and cached beside it
|
|
817
|
+
parameters:
|
|
818
|
+
- $ref: '#/components/parameters/path'
|
|
819
|
+
- name: w
|
|
820
|
+
in: query
|
|
821
|
+
schema:
|
|
822
|
+
type: integer
|
|
823
|
+
- name: h
|
|
824
|
+
in: query
|
|
825
|
+
schema:
|
|
826
|
+
type: integer
|
|
827
|
+
responses:
|
|
828
|
+
'200':
|
|
829
|
+
description: the image
|
|
830
|
+
content:
|
|
831
|
+
image/jpeg: {}
|
|
832
|
+
image/png: {}
|
|
833
|
+
'415':
|
|
834
|
+
description: no decoder for the format
|
|
835
|
+
'404':
|
|
836
|
+
$ref: '#/components/responses/notFound'
|
|
837
|
+
/api/cards:
|
|
838
|
+
get:
|
|
839
|
+
tags: [convenience]
|
|
840
|
+
summary: board card stubs for a list of paths
|
|
841
|
+
description: >-
|
|
842
|
+
Each path is resolved by the engine exactly as /api/content walks it: a pointer's slot
|
|
843
|
+
(`:task-sessions:1` for `- *: '20260829'`) answers the card of the task behind it, with
|
|
844
|
+
`path` as asked and `canonical` naming where the task lives when the two differ. A path
|
|
845
|
+
naming no node answers an inert stub, never an error.
|
|
846
|
+
parameters:
|
|
847
|
+
- name: paths
|
|
848
|
+
in: query
|
|
849
|
+
required: true
|
|
850
|
+
description: comma-separated colon paths
|
|
851
|
+
schema:
|
|
852
|
+
type: string
|
|
853
|
+
responses:
|
|
854
|
+
'200':
|
|
855
|
+
description: one stub per path
|
|
856
|
+
content:
|
|
857
|
+
application/json:
|
|
858
|
+
schema:
|
|
859
|
+
type: array
|
|
860
|
+
/api/preview:
|
|
861
|
+
post:
|
|
862
|
+
tags: [convenience]
|
|
863
|
+
summary: the content envelope of a standalone text (stateless)
|
|
864
|
+
requestBody:
|
|
865
|
+
required: true
|
|
866
|
+
content:
|
|
867
|
+
application/json:
|
|
868
|
+
schema:
|
|
869
|
+
type: object
|
|
870
|
+
properties:
|
|
871
|
+
source:
|
|
872
|
+
type: string
|
|
873
|
+
responses:
|
|
874
|
+
'200':
|
|
875
|
+
description: the envelope
|
|
876
|
+
content:
|
|
877
|
+
text/yamlover:
|
|
878
|
+
schema:
|
|
879
|
+
$ref: '#/components/schemas/envelope'
|
|
880
|
+
'400':
|
|
881
|
+
$ref: '#/components/responses/refused'
|
|
882
|
+
/api/edit-text:
|
|
883
|
+
post:
|
|
884
|
+
tags: [convenience]
|
|
885
|
+
summary: an edit batch applied to a standalone text (stateless)
|
|
886
|
+
requestBody:
|
|
887
|
+
required: true
|
|
888
|
+
content:
|
|
889
|
+
application/json:
|
|
890
|
+
schema:
|
|
891
|
+
type: object
|
|
892
|
+
properties:
|
|
893
|
+
source:
|
|
894
|
+
type: string
|
|
895
|
+
edits:
|
|
896
|
+
type: array
|
|
897
|
+
items:
|
|
898
|
+
$ref: '#/components/schemas/edit'
|
|
899
|
+
responses:
|
|
900
|
+
'200':
|
|
901
|
+
description: the text after the batch
|
|
902
|
+
content:
|
|
903
|
+
application/json:
|
|
904
|
+
schema:
|
|
905
|
+
type: object
|
|
906
|
+
properties:
|
|
907
|
+
source:
|
|
908
|
+
type: string
|
|
909
|
+
'400':
|
|
910
|
+
$ref: '#/components/responses/refused'
|
|
911
|
+
/api/dead-links:
|
|
912
|
+
get:
|
|
913
|
+
tags: [convenience]
|
|
914
|
+
summary: the in-tree links the doctor found dead
|
|
915
|
+
responses:
|
|
916
|
+
'200':
|
|
917
|
+
description: the targets
|
|
918
|
+
content:
|
|
919
|
+
application/json:
|
|
920
|
+
schema:
|
|
921
|
+
type: object
|
|
922
|
+
properties:
|
|
923
|
+
targets:
|
|
924
|
+
type: array
|
|
925
|
+
/api/openapi:
|
|
926
|
+
get:
|
|
927
|
+
tags: [convenience]
|
|
928
|
+
summary: this document
|
|
929
|
+
responses:
|
|
930
|
+
'200':
|
|
931
|
+
description: the OpenAPI document, `info.version` the wire version
|
|
932
|
+
content:
|
|
933
|
+
application/json:
|
|
934
|
+
schema:
|
|
935
|
+
type: object
|