@miadi/inquiry-weave 0.6.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/attention-node.d.ts +70 -0
- package/dist/attention-node.d.ts.map +1 -0
- package/dist/attention-node.js +194 -0
- package/dist/attention-node.js.map +1 -0
- package/dist/chronicle-dsl.d.ts +191 -0
- package/dist/chronicle-dsl.d.ts.map +1 -0
- package/dist/chronicle-dsl.js +327 -0
- package/dist/chronicle-dsl.js.map +1 -0
- package/dist/chronicle-terminal.d.ts +305 -0
- package/dist/chronicle-terminal.d.ts.map +1 -0
- package/dist/chronicle-terminal.js +449 -0
- package/dist/chronicle-terminal.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +222 -8
- package/dist/cli.js.map +1 -1
- package/dist/episode.d.ts.map +1 -1
- package/dist/episode.js +11 -3
- package/dist/episode.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/terminal-install.d.ts +84 -0
- package/dist/terminal-install.d.ts.map +1 -0
- package/dist/terminal-install.js +306 -0
- package/dist/terminal-install.js.map +1 -0
- package/package.json +9 -10
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Miadi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -235,3 +235,116 @@ calls (`INQUIRY_WEAVE_ISSUE_LIB` injects a fake issue lib).
|
|
|
235
235
|
---
|
|
236
236
|
🌸: A loom, not a pen — the weave holds artefact, issue, and episode in relation so none
|
|
237
237
|
drifts from the others, while the question itself stays yours to ask.
|
|
238
|
+
|
|
239
|
+
## `resolve` — one chronicle reference, answered
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
inquiry-weave resolve "miadi-chronicle:311/services-inventory"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
écoute factorisation logiciels — the relational software factory
|
|
247
|
+
[room·local] [room·tailnet] [room·public] [wheel·captures]
|
|
248
|
+
[wheel·graph] [wheel·node] [wheel·relations] [file·inventory]
|
|
249
|
+
<miadi-chronicle:311/services-inventory>
|
|
250
|
+
episode 311 · 2026-08-05-episode-311-coute-… · matched by number
|
|
251
|
+
path: /srv/miadi/episodes/…/services-inventory.json
|
|
252
|
+
modality: relational
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Turns a `miadi-chronicle:` reference into every door it opens. Contract:
|
|
256
|
+
`rispecs/miadi-chronicle-dsl/SPEC.md` (v1.1) and `SPEC-TERMINAL.md` (v1.2);
|
|
257
|
+
grounding in `foundations/resource-addressing-and-terminal-hypermedia/`.
|
|
258
|
+
|
|
259
|
+
Each bracket is its own OSC 8 hyperlink, and the canonical reference stays
|
|
260
|
+
visible beside them — the OSC 8 specification says a hyperlink "should not be
|
|
261
|
+
the only means of figuring out the target", and there is no way to detect
|
|
262
|
+
whether a terminal supports them. `--raw` drops the escape for clean capture.
|
|
263
|
+
|
|
264
|
+
**The reference is host-free.** `miadi-chronicle:311` is the name; a base is
|
|
265
|
+
chosen at render time. That is ARK's Name Mapping Authority rule — the
|
|
266
|
+
resolver's hostport is identity-inert — and it is why the same reference reads
|
|
267
|
+
correctly from this host, the tailnet, or the public front.
|
|
268
|
+
|
|
269
|
+
| flag | does |
|
|
270
|
+
| --- | --- |
|
|
271
|
+
| `--json` | the full result: `canonical`, `resolution`, `artifact`, `destinations[]`, `open`, `shareable`, `path`, `modality` |
|
|
272
|
+
| `--base local\|internal\|public` | lead with one door. Reorders; never removes one |
|
|
273
|
+
| `--local` | lead with the file on this disk |
|
|
274
|
+
| `--verify` | ask the wheel whether the episode is really on it |
|
|
275
|
+
| `--raw` | no escape sequences |
|
|
276
|
+
|
|
277
|
+
**`--verify` exists because a 200 proves nothing.** The wheel's `/graph`,
|
|
278
|
+
`/nodes` and `/relations` pages are client-routed, and so is forgewright's
|
|
279
|
+
chronicle view: both return 200 for an episode name that does not exist
|
|
280
|
+
(measured `?episode=9999-99-99-episode-000-nope` → 200). Only
|
|
281
|
+
`GET /api/nodes/<id>` discriminates, and that is what `--verify` asks.
|
|
282
|
+
|
|
283
|
+
**Two answers, never collapsed.** `open` is where a human click should land —
|
|
284
|
+
the episode room. `path` is the bytes on this host. An earlier draft returned
|
|
285
|
+
only the file, and clicking it opened a text editor on raw JSON: local-first is
|
|
286
|
+
about data ownership and availability, not about presentation.
|
|
287
|
+
|
|
288
|
+
### Forms
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
miadi-chronicle:092/126?view=wheel#scene=river # canonical, rootless
|
|
292
|
+
miadi-chronicle://092/126 # accepted forever, normalized away
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
`//` is RFC 3986 §3.2's authority marker, so a conformant parser reads the
|
|
296
|
+
first path segment as a host — `new URL("miadi-chronicle://126")` yields host
|
|
297
|
+
`"126"` and an **empty path**. Producers emit rootless; parsers accept both.
|
|
298
|
+
|
|
299
|
+
### Artifact segments
|
|
300
|
+
|
|
301
|
+
`services-inventory` · `state-machine` · `captures` · `recordings` · `inquiry`
|
|
302
|
+
· `plans`. The last four are served by the medicine wheel and are keyed by
|
|
303
|
+
`episode_path` — the **full folder name**. The episode number is not a key
|
|
304
|
+
there: `?episode_number=320` returns 0 records for an episode whose
|
|
305
|
+
`?episode_path=<folder>` returns 1.
|
|
306
|
+
|
|
307
|
+
### Fragments
|
|
308
|
+
|
|
309
|
+
`#state=` and `#event=` are spellable; `#transition=`, `#parameter=`,
|
|
310
|
+
`#action=` and `#source=` are not. State names are unique tree-wide (SMDF's
|
|
311
|
+
V002) so they survive structural motion; transitions are addressed positionally
|
|
312
|
+
and a sibling insert silently retargets the reference. Name-keyed fragments are
|
|
313
|
+
durable against structural motion and **fragile against rename** — see
|
|
314
|
+
`SPEC-TERMINAL.md` §4.3a.
|
|
315
|
+
|
|
316
|
+
## `terminal install` — clickable references in Terminator
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
inquiry-weave terminal install --enable
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Writes three files and one config line, each printed:
|
|
323
|
+
|
|
324
|
+
| path | is |
|
|
325
|
+
| --- | --- |
|
|
326
|
+
| `~/.config/terminator/plugins/miadi_chronicle_url_handler.py` | the URL handler |
|
|
327
|
+
| `~/.config/environment.d/50-miadi-chronicle.conf` | systemd user environment |
|
|
328
|
+
| `~/bin/miadi-chronicle-open` | the resolver wrapper a click runs |
|
|
329
|
+
| `enabled_plugins` in the Terminator config | only with `--enable`, after a backup |
|
|
330
|
+
|
|
331
|
+
Then restart Terminator and **Ctrl+click** a `miadi-chronicle:` reference
|
|
332
|
+
anywhere in its output. Plain click needs `link_single_click = True`.
|
|
333
|
+
|
|
334
|
+
`--force` overwrites, `--dry-run` previews, `terminal uninstall` reverses it,
|
|
335
|
+
`terminal show` prints the paths. Running install twice is safe.
|
|
336
|
+
|
|
337
|
+
**Why a plugin when OSC 8 exists.** Terminator has two click paths: an OSC 8
|
|
338
|
+
hyperlink calls `open_url(prepare=False)` and goes straight to `xdg-open`,
|
|
339
|
+
while a regex match calls `prepare=True` — the only path that consults
|
|
340
|
+
`url_handler` plugins. So the plugin covers what OSC 8 structurally cannot: a
|
|
341
|
+
bare `miadi-chronicle:311` in output that knows nothing about miadi — a git
|
|
342
|
+
log, a grep hit, an agent's raw text.
|
|
343
|
+
|
|
344
|
+
**Why the environment drop-in.** A GUI process inherits nothing from your
|
|
345
|
+
shell, so `MIADI_URL_BASE`, `MW_API_URL` and `MIADI_CHRONICLE_ROOT` are absent
|
|
346
|
+
at click time and every click falls back to localhost. `environment.d` is the
|
|
347
|
+
OS's own answer — read by systemd's user-environment generator at session
|
|
348
|
+
start, so every GUI process in the session inherits it. Takes effect at the
|
|
349
|
+
next login; the wrapper carries the same values as a fallback until then.
|
|
350
|
+
Test with `env -i`, which is the real click condition. See `jgwill/Miadi#620`.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attention-node projection — make "what needs a human" visible on the wheel.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors episode-node.ts: the vessel's `attention.json` stays authoritative;
|
|
5
|
+
* each item projects as ONE dedicated node (`attention:<episode>/<item-id>`),
|
|
6
|
+
* riding `knowledge` facing SOUTH — a decision ask is consent work. Per-item
|
|
7
|
+
* nodes are deliberate: medicine-wheel PATCH replaces the whole metadata
|
|
8
|
+
* object (storage-provider jsonl.ts `metadata: patch.metadata`, no merge), so
|
|
9
|
+
* items sharing a node would race every concurrent writer; one item, one
|
|
10
|
+
* writer, one node. forgewright's chronicle view is wheel-fed only, so this
|
|
11
|
+
* projection IS how attention reaches ilex.
|
|
12
|
+
*
|
|
13
|
+
* POST upserts by id on medicine-wheel ≥0.5.0, so registration preflights GET
|
|
14
|
+
* and UPDATES an existing node via PATCH instead of silently overwriting.
|
|
15
|
+
* Fail-open boundary exactly like registerEpisodeNode: network failure
|
|
16
|
+
* resolves to `pending`, never a throw — the file write upstream must never
|
|
17
|
+
* be lost to a wheel outage.
|
|
18
|
+
*/
|
|
19
|
+
import type { AttentionItem } from "@miadi/episodic-memory-schema";
|
|
20
|
+
import { ATTENTION_SCHEMA_VERSION } from "@miadi/episodic-memory-schema";
|
|
21
|
+
export interface AttentionNodeRecord {
|
|
22
|
+
id: string;
|
|
23
|
+
type: "knowledge";
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
direction: "south";
|
|
27
|
+
metadata: {
|
|
28
|
+
contract: "miadi.artifact-ref.v1";
|
|
29
|
+
kind: "attention";
|
|
30
|
+
schema_version: typeof ATTENTION_SCHEMA_VERSION;
|
|
31
|
+
root: "MIADI_CHRONICLE_ROOT";
|
|
32
|
+
relative_path: string;
|
|
33
|
+
parent_id: string;
|
|
34
|
+
item_id: string;
|
|
35
|
+
state: "open" | "answered";
|
|
36
|
+
asked?: string;
|
|
37
|
+
unlocks?: string;
|
|
38
|
+
answer?: string;
|
|
39
|
+
answered_at?: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export type AttentionNodeState = "registered" | "updated" | "pending";
|
|
43
|
+
export interface AttentionNodeOutcome {
|
|
44
|
+
state: AttentionNodeState;
|
|
45
|
+
node_id: string;
|
|
46
|
+
/** True only when a read-back confirmed the stored state matches the item. */
|
|
47
|
+
verified: boolean;
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function attentionNodeId(episodeName: string, itemId: string): string;
|
|
51
|
+
export declare function projectAttentionNode(episodeName: string, item: AttentionItem): AttentionNodeRecord;
|
|
52
|
+
export interface RegisterAttentionNodeOptions {
|
|
53
|
+
fetchImpl?: typeof fetch;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create or update the wheel node for one item, then read it back.
|
|
57
|
+
* `verified: true` means the wheel now SERVES the item's state — reached,
|
|
58
|
+
* not merely configured.
|
|
59
|
+
*/
|
|
60
|
+
export declare function registerAttentionNode(mwUrl: string, episodeName: string, item: AttentionItem, options?: RegisterAttentionNodeOptions): Promise<AttentionNodeOutcome>;
|
|
61
|
+
export interface SyncAttentionOutcome {
|
|
62
|
+
outcomes: AttentionNodeOutcome[];
|
|
63
|
+
registered: number;
|
|
64
|
+
updated: number;
|
|
65
|
+
pending: number;
|
|
66
|
+
verified: number;
|
|
67
|
+
}
|
|
68
|
+
/** Project every item of one episode; never throws past its boundary. */
|
|
69
|
+
export declare function syncEpisodeAttention(mwUrl: string, episodeName: string, items: readonly AttentionItem[], options?: RegisterAttentionNodeOptions): Promise<SyncAttentionOutcome>;
|
|
70
|
+
//# sourceMappingURL=attention-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention-node.d.ts","sourceRoot":"","sources":["../src/attention-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AAExE,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE;QACR,QAAQ,EAAE,uBAAuB,CAAA;QACjC,IAAI,EAAE,WAAW,CAAA;QACjB,cAAc,EAAE,OAAO,wBAAwB,CAAA;QAC/C,IAAI,EAAE,sBAAsB,CAAA;QAC5B,aAAa,EAAE,MAAM,CAAA;QACrB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,MAAM,GAAG,UAAU,CAAA;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;CACF;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAA;AAErE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,kBAAkB,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,aAAa,GAClB,mBAAmB,CAuBrB;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAgBD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,4BAAiC,GACzC,OAAO,CAAC,oBAAoB,CAAC,CAwG/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,oBAAoB,EAAE,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,yEAAyE;AACzE,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,OAAO,GAAE,4BAAiC,GACzC,OAAO,CAAC,oBAAoB,CAAC,CAY/B"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attention-node projection — make "what needs a human" visible on the wheel.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors episode-node.ts: the vessel's `attention.json` stays authoritative;
|
|
5
|
+
* each item projects as ONE dedicated node (`attention:<episode>/<item-id>`),
|
|
6
|
+
* riding `knowledge` facing SOUTH — a decision ask is consent work. Per-item
|
|
7
|
+
* nodes are deliberate: medicine-wheel PATCH replaces the whole metadata
|
|
8
|
+
* object (storage-provider jsonl.ts `metadata: patch.metadata`, no merge), so
|
|
9
|
+
* items sharing a node would race every concurrent writer; one item, one
|
|
10
|
+
* writer, one node. forgewright's chronicle view is wheel-fed only, so this
|
|
11
|
+
* projection IS how attention reaches ilex.
|
|
12
|
+
*
|
|
13
|
+
* POST upserts by id on medicine-wheel ≥0.5.0, so registration preflights GET
|
|
14
|
+
* and UPDATES an existing node via PATCH instead of silently overwriting.
|
|
15
|
+
* Fail-open boundary exactly like registerEpisodeNode: network failure
|
|
16
|
+
* resolves to `pending`, never a throw — the file write upstream must never
|
|
17
|
+
* be lost to a wheel outage.
|
|
18
|
+
*/
|
|
19
|
+
import { ATTENTION_SCHEMA_VERSION } from "@miadi/episodic-memory-schema";
|
|
20
|
+
export function attentionNodeId(episodeName, itemId) {
|
|
21
|
+
return `attention:${episodeName}/${itemId}`;
|
|
22
|
+
}
|
|
23
|
+
export function projectAttentionNode(episodeName, item) {
|
|
24
|
+
const metadata = {
|
|
25
|
+
contract: "miadi.artifact-ref.v1",
|
|
26
|
+
kind: "attention",
|
|
27
|
+
schema_version: ATTENTION_SCHEMA_VERSION,
|
|
28
|
+
root: "MIADI_CHRONICLE_ROOT",
|
|
29
|
+
relative_path: `${episodeName}/attention.json`,
|
|
30
|
+
parent_id: `chronicle:${episodeName}`,
|
|
31
|
+
item_id: item.id,
|
|
32
|
+
state: item.state,
|
|
33
|
+
};
|
|
34
|
+
if (item.asked)
|
|
35
|
+
metadata.asked = item.asked;
|
|
36
|
+
if (item.unlocks)
|
|
37
|
+
metadata.unlocks = item.unlocks;
|
|
38
|
+
if (item.answer)
|
|
39
|
+
metadata.answer = item.answer;
|
|
40
|
+
if (item.answered_at)
|
|
41
|
+
metadata.answered_at = item.answered_at;
|
|
42
|
+
return {
|
|
43
|
+
id: attentionNodeId(episodeName, item.id),
|
|
44
|
+
type: "knowledge",
|
|
45
|
+
name: item.question,
|
|
46
|
+
description: item.unlocks ? `unlocks: ${item.unlocks}` : "",
|
|
47
|
+
direction: "south",
|
|
48
|
+
metadata,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function describeFailure(error) {
|
|
52
|
+
return error instanceof Error ? error.message : String(error);
|
|
53
|
+
}
|
|
54
|
+
async function readErrorBody(response) {
|
|
55
|
+
try {
|
|
56
|
+
const body = (await response.json());
|
|
57
|
+
if (body && typeof body.error === "string")
|
|
58
|
+
return body.error;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Non-JSON body — the status line is all we can report.
|
|
62
|
+
}
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create or update the wheel node for one item, then read it back.
|
|
67
|
+
* `verified: true` means the wheel now SERVES the item's state — reached,
|
|
68
|
+
* not merely configured.
|
|
69
|
+
*/
|
|
70
|
+
export async function registerAttentionNode(mwUrl, episodeName, item, options = {}) {
|
|
71
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
72
|
+
const base = mwUrl.replace(/\/+$/, "");
|
|
73
|
+
const record = projectAttentionNode(episodeName, item);
|
|
74
|
+
const node_id = record.id;
|
|
75
|
+
const nodeUrl = `${base}/api/nodes/${encodeURIComponent(node_id)}`;
|
|
76
|
+
let existing;
|
|
77
|
+
try {
|
|
78
|
+
existing = await fetchImpl(nodeUrl);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return {
|
|
82
|
+
state: "pending",
|
|
83
|
+
node_id,
|
|
84
|
+
verified: false,
|
|
85
|
+
error: `medicine-wheel unreachable at ${base}: ${describeFailure(error)}`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
let state;
|
|
89
|
+
if (existing.ok) {
|
|
90
|
+
// Full-metadata PATCH by design: the store replaces, so we always send the
|
|
91
|
+
// complete projection — never a partial that would erase sibling fields.
|
|
92
|
+
let patched;
|
|
93
|
+
try {
|
|
94
|
+
patched = await fetchImpl(nodeUrl, {
|
|
95
|
+
method: "PATCH",
|
|
96
|
+
headers: { "content-type": "application/json" },
|
|
97
|
+
body: JSON.stringify({
|
|
98
|
+
name: record.name,
|
|
99
|
+
description: record.description,
|
|
100
|
+
metadata: record.metadata,
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
state: "pending",
|
|
107
|
+
node_id,
|
|
108
|
+
verified: false,
|
|
109
|
+
error: `PATCH ${nodeUrl}: ${describeFailure(error)}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (!patched.ok) {
|
|
113
|
+
const detail = await readErrorBody(patched);
|
|
114
|
+
return {
|
|
115
|
+
state: "pending",
|
|
116
|
+
node_id,
|
|
117
|
+
verified: false,
|
|
118
|
+
error: `PATCH ${nodeUrl}: HTTP ${patched.status}${detail ? ` — ${detail}` : ""}`,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
state = "updated";
|
|
122
|
+
}
|
|
123
|
+
else if (existing.status === 404) {
|
|
124
|
+
let created;
|
|
125
|
+
try {
|
|
126
|
+
created = await fetchImpl(`${base}/api/nodes`, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: { "content-type": "application/json" },
|
|
129
|
+
body: JSON.stringify(record),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
return {
|
|
134
|
+
state: "pending",
|
|
135
|
+
node_id,
|
|
136
|
+
verified: false,
|
|
137
|
+
error: `medicine-wheel unreachable at ${base}: ${describeFailure(error)}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (!created.ok) {
|
|
141
|
+
const detail = await readErrorBody(created);
|
|
142
|
+
return {
|
|
143
|
+
state: "pending",
|
|
144
|
+
node_id,
|
|
145
|
+
verified: false,
|
|
146
|
+
error: `POST ${base}/api/nodes: HTTP ${created.status}${detail ? ` — ${detail}` : ""}`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
state = "registered";
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const detail = await readErrorBody(existing);
|
|
153
|
+
return {
|
|
154
|
+
state: "pending",
|
|
155
|
+
node_id,
|
|
156
|
+
verified: false,
|
|
157
|
+
error: `GET ${nodeUrl}: HTTP ${existing.status}${detail ? ` — ${detail}` : ""}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// The verify leg — the boot-law applied to the write path.
|
|
161
|
+
try {
|
|
162
|
+
const back = await fetchImpl(nodeUrl);
|
|
163
|
+
if (!back.ok)
|
|
164
|
+
return { state, node_id, verified: false, error: `verify GET: HTTP ${back.status}` };
|
|
165
|
+
const body = (await back.json());
|
|
166
|
+
const served = body.node?.metadata?.state ?? body.metadata?.state;
|
|
167
|
+
if (served === item.state)
|
|
168
|
+
return { state, node_id, verified: true };
|
|
169
|
+
return {
|
|
170
|
+
state,
|
|
171
|
+
node_id,
|
|
172
|
+
verified: false,
|
|
173
|
+
error: `verify: wheel serves state=${String(served)}, item is ${item.state}`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
return { state, node_id, verified: false, error: `verify GET: ${describeFailure(error)}` };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** Project every item of one episode; never throws past its boundary. */
|
|
181
|
+
export async function syncEpisodeAttention(mwUrl, episodeName, items, options = {}) {
|
|
182
|
+
const outcomes = [];
|
|
183
|
+
for (const item of items) {
|
|
184
|
+
outcomes.push(await registerAttentionNode(mwUrl, episodeName, item, options));
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
outcomes,
|
|
188
|
+
registered: outcomes.filter((o) => o.state === "registered").length,
|
|
189
|
+
updated: outcomes.filter((o) => o.state === "updated").length,
|
|
190
|
+
pending: outcomes.filter((o) => o.state === "pending").length,
|
|
191
|
+
verified: outcomes.filter((o) => o.verified).length,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=attention-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention-node.js","sourceRoot":"","sources":["../src/attention-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AAkCxE,MAAM,UAAU,eAAe,CAAC,WAAmB,EAAE,MAAc;IACjE,OAAO,aAAa,WAAW,IAAI,MAAM,EAAE,CAAA;AAC7C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAmB,EACnB,IAAmB;IAEnB,MAAM,QAAQ,GAAoC;QAChD,QAAQ,EAAE,uBAAuB;QACjC,IAAI,EAAE,WAAW;QACjB,cAAc,EAAE,wBAAwB;QACxC,IAAI,EAAE,sBAAsB;QAC5B,aAAa,EAAE,GAAG,WAAW,iBAAiB;QAC9C,SAAS,EAAE,aAAa,WAAW,EAAE;QACrC,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAA;IACD,IAAI,IAAI,CAAC,KAAK;QAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IAC3C,IAAI,IAAI,CAAC,OAAO;QAAE,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;IACjD,IAAI,IAAI,CAAC,MAAM;QAAE,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC9C,IAAI,IAAI,CAAC,WAAW;QAAE,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;IAC7D,OAAO;QACL,EAAE,EAAE,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC;QACzC,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,IAAI,CAAC,QAAQ;QACnB,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE;QAC3D,SAAS,EAAE,OAAO;QAClB,QAAQ;KACT,CAAA;AACH,CAAC;AAMD,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC/D,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,QAAkB;IAC7C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAA;QAC3D,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,KAAK,CAAA;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAa,EACb,WAAmB,EACnB,IAAmB,EACnB,UAAwC,EAAE;IAE1C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAA;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACtC,MAAM,MAAM,GAAG,oBAAoB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;IACtD,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAA;IACzB,MAAM,OAAO,GAAG,GAAG,IAAI,cAAc,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAA;IAElE,IAAI,QAAkB,CAAA;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAA;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,OAAO;YACP,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,iCAAiC,IAAI,KAAK,eAAe,CAAC,KAAK,CAAC,EAAE;SAC1E,CAAA;IACH,CAAC;IAED,IAAI,KAAyB,CAAA;IAC7B,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QAChB,2EAA2E;QAC3E,yEAAyE;QACzE,IAAI,OAAiB,CAAA;QACrB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE;gBACjC,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ;iBAC1B,CAAC;aACH,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,KAAK,EAAE,SAAS;gBAChB,OAAO;gBACP,QAAQ,EAAE,KAAK;gBACf,KAAK,EAAE,SAAS,OAAO,KAAK,eAAe,CAAC,KAAK,CAAC,EAAE;aACrD,CAAA;QACH,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAA;YAC3C,OAAO;gBACL,KAAK,EAAE,SAAS;gBAChB,OAAO;gBACP,QAAQ,EAAE,KAAK;gBACf,KAAK,EAAE,SAAS,OAAO,UAAU,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;aACjF,CAAA;QACH,CAAC;QACD,KAAK,GAAG,SAAS,CAAA;IACnB,CAAC;SAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACnC,IAAI,OAAiB,CAAA;QACrB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,YAAY,EAAE;gBAC7C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;aAC7B,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,KAAK,EAAE,SAAS;gBAChB,OAAO;gBACP,QAAQ,EAAE,KAAK;gBACf,KAAK,EAAE,iCAAiC,IAAI,KAAK,eAAe,CAAC,KAAK,CAAC,EAAE;aAC1E,CAAA;QACH,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAA;YAC3C,OAAO;gBACL,KAAK,EAAE,SAAS;gBAChB,OAAO;gBACP,QAAQ,EAAE,KAAK;gBACf,KAAK,EAAE,QAAQ,IAAI,oBAAoB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;aACvF,CAAA;QACH,CAAC;QACD,KAAK,GAAG,YAAY,CAAA;IACtB,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC5C,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,OAAO;YACP,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,OAAO,OAAO,UAAU,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;SAChF,CAAA;IACH,CAAC;IAED,2DAA2D;IAC3D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAA;QACrC,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,IAAI,CAAC,MAAM,EAAE,EAAE,CAAA;QAClG,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAkD,CAAA;QACjF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,IAAK,IAA2C,CAAC,QAAQ,EAAE,KAAK,CAAA;QACzG,IAAI,MAAM,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;QACpE,OAAO;YACL,KAAK;YACL,OAAO;YACP,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,8BAA8B,MAAM,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,KAAK,EAAE;SAC7E,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,CAAA;IAC5F,CAAC;AACH,CAAC;AAUD,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAa,EACb,WAAmB,EACnB,KAA+B,EAC/B,UAAwC,EAAE;IAE1C,MAAM,QAAQ,GAA2B,EAAE,CAAA;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC,MAAM,qBAAqB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;IAC/E,CAAC;IACD,OAAO;QACL,QAAQ;QACR,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,MAAM;QACnE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,MAAM;QAC7D,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,MAAM;QAC7D,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM;KACpD,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* miadi-chronicle URI parsing, artifact registry, and episode resolution.
|
|
3
|
+
*
|
|
4
|
+
* Contract: rispecs/miadi-chronicle-dsl/SPEC.md (v1.1) and SPEC-TERMINAL.md
|
|
5
|
+
* (v1.2). Grounded in foundations/resource-addressing-and-terminal-hypermedia/.
|
|
6
|
+
*
|
|
7
|
+
* This is the app's three pure modules (`app/chronicle/lib/{dsl,resolveRef,
|
|
8
|
+
* inventoryRef}.ts`) brought into a package that already ships built ESM, so
|
|
9
|
+
* one resolver can answer the browser, the HTTP route, and a terminal. It
|
|
10
|
+
* stays pure — no fs, no fetch, no React. The catalog arrives as an argument.
|
|
11
|
+
*
|
|
12
|
+
* Two changes v1.1 does not have, both from the foundations packet:
|
|
13
|
+
*
|
|
14
|
+
* 1. ROOTLESS FORM. `//` is RFC 3986 §3.2's authority marker, so every
|
|
15
|
+
* conformant parser reads the first path segment as a host:
|
|
16
|
+
* new URL("miadi-chronicle://126") → host "126", pathname ""
|
|
17
|
+
* The most common reference has an EMPTY PATH, stock parsers disagree
|
|
18
|
+
* with this file, and SPEC §8's reserved `//root@…/` growth slot is
|
|
19
|
+
* unreachable because episode data already occupies it. Every non-HTTP
|
|
20
|
+
* scheme that survived — did:, urn:, ark:, swh:, tag:, info: — is
|
|
21
|
+
* rootless. So: `miadi-chronicle:092/126` is canonical, `//` is accepted
|
|
22
|
+
* forever on input and normalized away on output.
|
|
23
|
+
*
|
|
24
|
+
* 2. ARTIFACT REGISTRY. v1.1's "registry" was one const string compared by
|
|
25
|
+
* `===` in three places. It is a map now, with `state-machine` as the
|
|
26
|
+
* second entry.
|
|
27
|
+
*/
|
|
28
|
+
export declare const MIADI_CHRONICLE_SCHEME = "miadi-chronicle:";
|
|
29
|
+
/** Rendering options folded into the URI query under the reserved prefix. */
|
|
30
|
+
export declare const OPTION_PREFIX = "mc.";
|
|
31
|
+
/**
|
|
32
|
+
* Reserved artifact segments — the registry SPEC §7.1 named itself after.
|
|
33
|
+
* Each key is a name no episode folder can carry (folder names are
|
|
34
|
+
* date-prefixed); each value is the artifact kind the resolver dispatches on.
|
|
35
|
+
*/
|
|
36
|
+
export declare const ARTIFACT_SEGMENTS: {
|
|
37
|
+
readonly "services-inventory": "inventory";
|
|
38
|
+
readonly "state-machine": "state-machine";
|
|
39
|
+
readonly captures: "captures";
|
|
40
|
+
readonly recordings: "captures";
|
|
41
|
+
readonly inquiry: "inquiry";
|
|
42
|
+
readonly plans: "plans";
|
|
43
|
+
};
|
|
44
|
+
export type ArtifactKind = (typeof ARTIFACT_SEGMENTS)[keyof typeof ARTIFACT_SEGMENTS];
|
|
45
|
+
/** Kinds served by the medicine wheel rather than by the vessel on disk. */
|
|
46
|
+
export declare const WHEEL_ARTIFACT_KINDS: readonly ["captures", "inquiry", "plans"];
|
|
47
|
+
/** The wheel node id for an episode. The observed format, not the expected one:
|
|
48
|
+
* `chronicle:2026-08-05-episode-311-coute-…-factory`. */
|
|
49
|
+
export declare function wheelNodeId(episodeFolder: string): string;
|
|
50
|
+
export interface ParsedChronicleUri {
|
|
51
|
+
/** The full original URI, exactly as given. */
|
|
52
|
+
uri: string;
|
|
53
|
+
/** Canonical rootless form with `mc.*` options and fragment preserved. */
|
|
54
|
+
canonical: string;
|
|
55
|
+
/** Raw slash-joined path as written, e.g. "092/126" or "311/state-machine". */
|
|
56
|
+
episodePath: string;
|
|
57
|
+
/** Path split into segments, artifact segment included when present. */
|
|
58
|
+
segments: string[];
|
|
59
|
+
/** Segments that address an EPISODE — the artifact segment stripped. */
|
|
60
|
+
episodeSegments: string[];
|
|
61
|
+
/** Which artifact this reference names, or null for a plain episode ref. */
|
|
62
|
+
artifact: ArtifactKind | null;
|
|
63
|
+
/** Query params minus the mc.* rendering options. */
|
|
64
|
+
query: Record<string, string>;
|
|
65
|
+
/** mc.* rendering options, prefix stripped (show, label, highlight, as, …). */
|
|
66
|
+
options: Record<string, string>;
|
|
67
|
+
/** In-episode navigation hint, e.g. "scene=river" or "state=Gathering". */
|
|
68
|
+
fragment?: string;
|
|
69
|
+
}
|
|
70
|
+
export declare function isMiadiChronicleUri(href: string | undefined): boolean;
|
|
71
|
+
/** Parse one URI. Returns null on anything malformed — never throws. */
|
|
72
|
+
export declare function parseMiadiChronicleUri(uri: string): ParsedChronicleUri | null;
|
|
73
|
+
/**
|
|
74
|
+
* Keys a `state-machine` fragment may use.
|
|
75
|
+
*
|
|
76
|
+
* `state` and `event` are name-keyed: SMDF's validation rule V002 forces
|
|
77
|
+
* tree-wide unique state names, and events are keyed by id, so both survive
|
|
78
|
+
* structural motion. Transitions, parameters, actions and event sources are
|
|
79
|
+
* addressed POSITIONALLY (`{state, index}`) — an index shifts the moment a
|
|
80
|
+
* sibling is inserted, and the reference then resolves to the wrong thing
|
|
81
|
+
* without raising anything. Content drift outruns link rot roughly 3:1
|
|
82
|
+
* (Jones et al. 2016, doi:10.1371/journal.pone.0167475) and the silent
|
|
83
|
+
* variant is the damaging one, so a form that cannot be durable is not
|
|
84
|
+
* spellable here.
|
|
85
|
+
*
|
|
86
|
+
* The narrow claim, precisely: a BARE `{state, index}` pair carries no content
|
|
87
|
+
* by which a shifted reference could be re-matched or a mis-resolution
|
|
88
|
+
* detected. Positional addressing can be hardened (Phelps & Wilensky carry
|
|
89
|
+
* node tags alongside the index and resolve by approximate match) — but
|
|
90
|
+
* hardening it here would amount to describing the transition, at which point
|
|
91
|
+
* the index is doing no work. The sanctioned way to address one is therefore
|
|
92
|
+
* by description, from V002-unique names, which inherits their durability:
|
|
93
|
+
* #transition=(from:<State>,on:<Event>,to:<State>)
|
|
94
|
+
* That form EXTENDS this rule rather than breaching it. It is not implemented.
|
|
95
|
+
*
|
|
96
|
+
* Conditional by design: transitions are positional IN SMDF TODAY. OMG XMI
|
|
97
|
+
* gives every model element an `xmi:id`; if SMDF ever mints author-assigned
|
|
98
|
+
* transition ids under the same uniqueness constraint, `#transition=` becomes
|
|
99
|
+
* durable and this rule's own principle would then REQUIRE permitting it.
|
|
100
|
+
*/
|
|
101
|
+
export declare const DURABLE_FRAGMENT_KEYS: readonly ["state", "event"];
|
|
102
|
+
/** Positional keys, refused with a reason rather than silently ignored. */
|
|
103
|
+
export declare const POSITIONAL_FRAGMENT_KEYS: readonly ["transition", "parameter", "action", "source"];
|
|
104
|
+
export interface FragmentVerdict {
|
|
105
|
+
key: string;
|
|
106
|
+
value: string;
|
|
107
|
+
durable: boolean;
|
|
108
|
+
reason?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Judge a `key=value` fragment against the durability rule. An unknown key is
|
|
112
|
+
* neither endorsed nor refused — it is passed through, per SPEC §1's rule that
|
|
113
|
+
* unknown parameters are preserved and never fatal.
|
|
114
|
+
*/
|
|
115
|
+
export declare function judgeFragment(fragment: string | undefined): FragmentVerdict | null;
|
|
116
|
+
/**
|
|
117
|
+
* Rename is the hole V002 does not cover.
|
|
118
|
+
*
|
|
119
|
+
* V002 gives tree-wide unique state names AT A POINT IN TIME. It says nothing
|
|
120
|
+
* about immutability: under rename, `#state=Foo` fails exactly as a positional
|
|
121
|
+
* reference fails under insertion, and the worse variant — a name reused for a
|
|
122
|
+
* different state — resolves successfully to the wrong element.
|
|
123
|
+
*
|
|
124
|
+
* The policy this package implements is the middle of the three the packet
|
|
125
|
+
* lists: an alias table. A machine MAY carry `former-names`, and a reference
|
|
126
|
+
* to a former name resolves WITH A DEPRECATION SIGNAL rather than failing.
|
|
127
|
+
* That is XPointer's ordered-fallback pattern applied locally, and Memento's
|
|
128
|
+
* idea (reach a prior state) without an archive. Until SMDF carries
|
|
129
|
+
* `former-names`, the honest status is: name-keyed fragments are durable
|
|
130
|
+
* against structural motion and fragile against rename, and this is stated
|
|
131
|
+
* rather than implied.
|
|
132
|
+
*/
|
|
133
|
+
export declare const RENAME_POLICY: "alias-table-pending";
|
|
134
|
+
export type MatchedBy = "folder-name" | "number" | "slug" | "date";
|
|
135
|
+
/** The seven fields resolution actually reads. Structurally satisfied by
|
|
136
|
+
* `EpisodeManifestEntry` from the catalog, and by the app's richer view. */
|
|
137
|
+
export interface ResolvableEpisode {
|
|
138
|
+
name: string;
|
|
139
|
+
number?: number;
|
|
140
|
+
slug?: string;
|
|
141
|
+
date?: string;
|
|
142
|
+
title?: string;
|
|
143
|
+
direction?: string;
|
|
144
|
+
theme?: string;
|
|
145
|
+
}
|
|
146
|
+
export interface ResolvedEpisodeRef {
|
|
147
|
+
segment: string;
|
|
148
|
+
resolved: boolean;
|
|
149
|
+
matchedBy?: MatchedBy;
|
|
150
|
+
name?: string;
|
|
151
|
+
number?: number;
|
|
152
|
+
title?: string;
|
|
153
|
+
date?: string;
|
|
154
|
+
direction?: string;
|
|
155
|
+
theme?: string;
|
|
156
|
+
/** App route to the episode room, fragment already attached for targets. */
|
|
157
|
+
route?: string;
|
|
158
|
+
/**
|
|
159
|
+
* Folder names of OTHER episodes the segment also matched. The catalog
|
|
160
|
+
* really does hold duplicate numbers; resolution stays deterministic and
|
|
161
|
+
* the ambiguity is surfaced instead of hidden.
|
|
162
|
+
*
|
|
163
|
+
* Note what this does NOT yet solve: the tie-break is lexicographically
|
|
164
|
+
* first, so backfilling a newly-discovered OLDER episode with a duplicate
|
|
165
|
+
* number silently retargets every existing reference. Non-reassignment is a
|
|
166
|
+
* primary dimension of identifier validity (Kunze et al. 2017); ARK and DOI
|
|
167
|
+
* forbid reassignment outright. Deterministic-at-an-instant is not
|
|
168
|
+
* stable-over-time, and `alternates` reports the ambiguity without fixing it.
|
|
169
|
+
*/
|
|
170
|
+
alternates?: string[];
|
|
171
|
+
}
|
|
172
|
+
export interface ChronicleResolution {
|
|
173
|
+
resolved: boolean;
|
|
174
|
+
matchedBy?: MatchedBy;
|
|
175
|
+
target: ResolvedEpisodeRef;
|
|
176
|
+
waypoints: ResolvedEpisodeRef[];
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Resolve an already-parsed URI against the catalog.
|
|
180
|
+
*
|
|
181
|
+
* Resolution runs over `episodeSegments`, so an artifact reference resolves
|
|
182
|
+
* its episode exactly as a plain reference does — the reserved segment is
|
|
183
|
+
* stripped before matching, never matched against a folder.
|
|
184
|
+
*/
|
|
185
|
+
export declare function resolveChronicleRef(parsed: ParsedChronicleUri, entries: ResolvableEpisode[]): ChronicleResolution;
|
|
186
|
+
/** One-call convenience: raw URI string → resolution, or null if unparseable. */
|
|
187
|
+
export declare function resolveChronicleUri(uri: string, entries: ResolvableEpisode[]): {
|
|
188
|
+
parsed: ParsedChronicleUri;
|
|
189
|
+
resolution: ChronicleResolution;
|
|
190
|
+
} | null;
|
|
191
|
+
//# sourceMappingURL=chronicle-dsl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chronicle-dsl.d.ts","sourceRoot":"","sources":["../src/chronicle-dsl.ts"],"names":[],"mappings":"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"}
|