noggin-cli 0.1.2 → 0.4.2
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 +97 -17
- package/SKILL.md +10 -2
- package/noggin-api.d.mts +262 -159
- package/noggin-api.mjs +654 -534
- package/noggin-mcp.mjs +163 -85
- package/noggin.mjs +311 -176
- package/package.json +4 -1
package/noggin-api.d.mts
CHANGED
|
@@ -1,19 +1,34 @@
|
|
|
1
1
|
// Type declarations for noggin-api.mjs.
|
|
2
2
|
//
|
|
3
3
|
// Hand-written to match the JS implementation; no build step. The .mjs uses
|
|
4
|
-
// /// <reference path="./noggin-api.d.
|
|
4
|
+
// /// <reference path="./noggin-api.d.mts" /> so editors and tsc --noEmit can
|
|
5
5
|
// check usages against this contract.
|
|
6
|
+
//
|
|
7
|
+
// API stability tiers (TSDoc release tags):
|
|
8
|
+
// @public — Stable contract. Breaking changes require a major bump.
|
|
9
|
+
// @experimental — Public but the shape may still change.
|
|
10
|
+
// @internal — Implementation detail; do not depend on this.
|
|
11
|
+
|
|
12
|
+
// ── Core identifiers ─────────────────────────────────────────────────────────
|
|
6
13
|
|
|
7
|
-
|
|
14
|
+
/** @public Opaque, stable item identifier. Treat as a string token. */
|
|
8
15
|
export type ItemKey = string;
|
|
16
|
+
|
|
17
|
+
/** @public Tree path string (e.g. `/1/2/3` or `./X`). Display coordinate only. */
|
|
9
18
|
export type ItemPath = string;
|
|
19
|
+
|
|
20
|
+
/** @public ISO-8601 / RFC 3339 date-time string. */
|
|
10
21
|
export type IsoTimestamp = string;
|
|
11
22
|
|
|
23
|
+
// ── Data model ───────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
/** @public A single entry in an item's append-only note log. */
|
|
12
26
|
export interface Note {
|
|
13
27
|
timestamp: IsoTimestamp;
|
|
14
28
|
text: string;
|
|
15
29
|
}
|
|
16
30
|
|
|
31
|
+
/** @public A single work item in the noggin tree. */
|
|
17
32
|
export interface Item {
|
|
18
33
|
key: ItemKey;
|
|
19
34
|
parentKey: ItemKey | null;
|
|
@@ -23,102 +38,76 @@ export interface Item {
|
|
|
23
38
|
notes: Note[];
|
|
24
39
|
}
|
|
25
40
|
|
|
26
|
-
|
|
41
|
+
/**
|
|
42
|
+
* @public
|
|
43
|
+
* The serialized form of a noggin: pure data. The JSON Schema validates
|
|
44
|
+
* this shape; serializers convert it to/from YAML or JSON; backends
|
|
45
|
+
* load and save it.
|
|
46
|
+
*/
|
|
47
|
+
export interface NogginDocument {
|
|
27
48
|
schemaVersion: number;
|
|
28
49
|
active: ItemKey | null;
|
|
29
50
|
items: Item[];
|
|
30
51
|
}
|
|
31
52
|
|
|
32
|
-
/** An Item enriched with computed path and 1-based sibling position. */
|
|
53
|
+
/** @public An Item enriched with computed path and 1-based sibling position. */
|
|
33
54
|
export interface ItemView extends Item {
|
|
34
55
|
path: ItemPath | null;
|
|
35
56
|
position: number | null;
|
|
36
57
|
}
|
|
37
58
|
|
|
38
|
-
/**
|
|
39
|
-
* A node in a CurrentTreeView's recursive tree. Carries the usual
|
|
40
|
-
* ItemView fields plus an *optional* `children` slot:
|
|
41
|
-
*
|
|
42
|
-
* children present this view renders this node's child level (the
|
|
43
|
-
* array may be empty — e.g. target with no kids)
|
|
44
|
-
* children absent leaf of this view; the store may have a subtree
|
|
45
|
-
* here, but this view doesn't render it
|
|
46
|
-
*
|
|
47
|
-
* The recursion walks the direct ancestor chain from root to target.
|
|
48
|
-
* Each ancestor has a single-element `children`. The target's parent
|
|
49
|
-
* has the full peer row. The target has `children` populated with its
|
|
50
|
-
* first-level kids (or no `children` field at all with `--nokids`).
|
|
51
|
-
* Peers and grandkids are leaves and have no `children` field.
|
|
52
|
-
*/
|
|
59
|
+
/** @public A node in a CurrentTreeView's recursive tree. */
|
|
53
60
|
export interface ViewNode extends ItemView {
|
|
54
61
|
children?: ViewNode[];
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
/** Shape returned by every mutating verb and by `show
|
|
64
|
+
/** @public Shape returned by every mutating verb and by `verbs.show`. */
|
|
58
65
|
export interface CurrentTreeView {
|
|
59
|
-
/** Path of the active item, or null. May differ from the target —
|
|
60
|
-
* active is the user's persistent cursor (📍) and is not necessarily
|
|
61
|
-
* on the spine of this view. */
|
|
62
66
|
activePath: ItemPath | null;
|
|
63
|
-
/** Stable key of the active item, or null. */
|
|
64
67
|
activeKey: ItemKey | null;
|
|
65
|
-
/** Stable key of the item the verb acted on. To grab the full row,
|
|
66
|
-
* walk `items` and find the node whose `key === targetKey`. */
|
|
67
68
|
targetKey: ItemKey;
|
|
68
|
-
/**
|
|
69
|
-
* Top of the rendered tree. Contains either:
|
|
70
|
-
* - a single root ancestor (when the target is below depth 0); or
|
|
71
|
-
* - the target's full peer row (when the target itself is a root).
|
|
72
|
-
* Either way, every node along the path from `items` down to the
|
|
73
|
-
* target has a non-null `children`; leaves of the view have `null`.
|
|
74
|
-
*/
|
|
75
69
|
items: ViewNode[];
|
|
76
70
|
}
|
|
77
71
|
|
|
78
|
-
/** Identifying tombstone for a deleted item
|
|
72
|
+
/** @public Identifying tombstone for a deleted item. */
|
|
79
73
|
export interface DeletedItem {
|
|
80
74
|
key: ItemKey;
|
|
81
75
|
path: ItemPath | null;
|
|
82
76
|
title: string;
|
|
83
77
|
}
|
|
84
78
|
|
|
79
|
+
/** @public */
|
|
85
80
|
export type PlacementKind = 'before' | 'after' | 'into';
|
|
86
81
|
|
|
82
|
+
/** @public Placement spec for `add` / `move`. */
|
|
87
83
|
export interface Placement {
|
|
88
84
|
kind: PlacementKind;
|
|
89
|
-
/** Path to the anchor item.
|
|
85
|
+
/** Path to the anchor item. */
|
|
90
86
|
anchor: ItemPath;
|
|
91
87
|
}
|
|
92
88
|
|
|
93
|
-
/** Optional reposition-after-write. Mirrors the CLI `--goto` flag. */
|
|
89
|
+
/** @public Optional reposition-after-write. Mirrors the CLI `--goto` flag. */
|
|
94
90
|
export interface GotoOption {
|
|
95
|
-
/**
|
|
96
|
-
* Path resolved relative to the operation's target.
|
|
97
|
-
* `true` (or omitted with bare `--goto`) means `.` (the target itself).
|
|
98
|
-
*/
|
|
91
|
+
/** Path resolved relative to the operation's target. `true` means `.`. */
|
|
99
92
|
goto?: ItemPath | true;
|
|
100
93
|
}
|
|
101
94
|
|
|
102
|
-
|
|
103
|
-
file: NogginFilePath;
|
|
104
|
-
source: 'flag' | 'env' | 'default';
|
|
105
|
-
exists: boolean;
|
|
106
|
-
defaultFile: NogginFilePath;
|
|
107
|
-
/** Value of $NOGGIN_FILE at the time of resolution, or null. */
|
|
108
|
-
env: string | null;
|
|
109
|
-
}
|
|
110
|
-
|
|
95
|
+
/** @public Result of `verbs.delete`. */
|
|
111
96
|
export interface DeleteResult {
|
|
112
97
|
deleted: DeletedItem;
|
|
113
98
|
descendantCount: number;
|
|
114
|
-
/** Null only when the resulting tree has no active item (e.g. a root was deleted). */
|
|
115
99
|
view: CurrentTreeView | null;
|
|
116
100
|
}
|
|
117
101
|
|
|
102
|
+
// ── Errors ───────────────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
/** @public Closed-ish union of error codes. New codes are non-breaking. */
|
|
118
105
|
export type NogginErrorCode =
|
|
119
106
|
| 'noggin-error'
|
|
120
107
|
| 'no-active-item'
|
|
121
108
|
| 'no-file'
|
|
109
|
+
| 'no-location'
|
|
110
|
+
| 'no-factory'
|
|
122
111
|
| 'path-not-found'
|
|
123
112
|
| 'path-required'
|
|
124
113
|
| 'cycle'
|
|
@@ -136,10 +125,13 @@ export type NogginErrorCode =
|
|
|
136
125
|
| 'open-descendants'
|
|
137
126
|
| 'pop-no-path'
|
|
138
127
|
| 'invalid-note'
|
|
139
|
-
| 'invalid-
|
|
128
|
+
| 'invalid-op'
|
|
129
|
+
| 'invalid-document'
|
|
140
130
|
| 'unsupported-schema'
|
|
131
|
+
| 'lock-timeout'
|
|
141
132
|
| 'io';
|
|
142
133
|
|
|
134
|
+
/** @public Thrown by every engine function on usage/state errors. */
|
|
143
135
|
export class NogginError extends Error {
|
|
144
136
|
readonly code: NogginErrorCode | string;
|
|
145
137
|
/** Mirrors the CLI exit code (1 = runtime/state, 2 = usage/parse/invalid). */
|
|
@@ -149,169 +141,280 @@ export class NogginError extends Error {
|
|
|
149
141
|
|
|
150
142
|
// ── Constants ────────────────────────────────────────────────────────────────
|
|
151
143
|
|
|
144
|
+
/** @public Current `schemaVersion` written into a `NogginDocument`. */
|
|
152
145
|
export const SCHEMA_VERSION: number;
|
|
153
|
-
export const JSON_SCHEMA_VERSION: number;
|
|
154
|
-
export const DEFAULT_FILE: NogginFilePath;
|
|
155
146
|
|
|
156
|
-
|
|
147
|
+
/** @public Current `envelopeVersion` stamped onto every response envelope. */
|
|
148
|
+
export const RESPONSE_ENVELOPE_VERSION: number;
|
|
157
149
|
|
|
158
|
-
|
|
150
|
+
/** @public @deprecated Renamed to `RESPONSE_ENVELOPE_VERSION`. */
|
|
151
|
+
export const JSON_SCHEMA_VERSION: number;
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
export
|
|
153
|
+
/** @public The system-generated note text appended on close. */
|
|
154
|
+
export const CLOSE_NOTE_TEXT: string;
|
|
162
155
|
|
|
163
|
-
|
|
164
|
-
export function tryResolvePath(store: Store, path: ItemPath): Item | null;
|
|
156
|
+
// ── Eventing primitives ─────────────────────────────────────────────────────
|
|
165
157
|
|
|
166
|
-
|
|
167
|
-
export
|
|
158
|
+
/** @public Disposable returned by event subscriptions. */
|
|
159
|
+
export interface Disposable { dispose(): void }
|
|
168
160
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
target: Item,
|
|
172
|
-
opts?: { includeChildren?: boolean; withSiblings?: boolean; withDescendants?: boolean }
|
|
173
|
-
): CurrentTreeView;
|
|
161
|
+
/** @public vscode-style event subscribe function. */
|
|
162
|
+
export type Event<T> = (handler: (e: T) => void) => Disposable;
|
|
174
163
|
|
|
175
|
-
// ──
|
|
164
|
+
// ── Noggin (interface) ──────────────────────────────────────────────────────
|
|
176
165
|
|
|
177
166
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
167
|
+
* @public
|
|
168
|
+
* A live noggin. Backends implement this interface; consumers consume
|
|
169
|
+
* it. Read accessors are synchronous and reflect the current state.
|
|
170
|
+
* `apply(ops)` is the only mutator — every backend implements it; the
|
|
171
|
+
* `verbs` namespace composes ops and calls it.
|
|
172
|
+
*
|
|
173
|
+
* Storage-tracking contract:
|
|
174
|
+
* - Accessors always reflect the latest known state.
|
|
175
|
+
* - `onDidChange` fires after every mutation (in-process or externally
|
|
176
|
+
* observed). After it fires, accessors are up to date.
|
|
181
177
|
*/
|
|
182
|
-
export interface
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
data: T;
|
|
188
|
-
}
|
|
178
|
+
export interface Noggin {
|
|
179
|
+
// accessors (sync)
|
|
180
|
+
readonly items: readonly Item[];
|
|
181
|
+
readonly active: Item | null;
|
|
182
|
+
readonly roots: readonly Item[];
|
|
189
183
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
184
|
+
findByKey(k: ItemKey | null | undefined): Item | null;
|
|
185
|
+
childrenOf(k: ItemKey | null | undefined): readonly Item[];
|
|
186
|
+
pathOf(item: Item | null | undefined): ItemPath | null;
|
|
187
|
+
resolvePath(p: ItemPath): Item;
|
|
188
|
+
tryResolvePath(p: ItemPath): Item | null;
|
|
189
|
+
|
|
190
|
+
/** Atomically apply a list of `AtomicOp`s. The only write primitive. */
|
|
191
|
+
apply(ops: readonly AtomicOp[]): Promise<void>;
|
|
192
|
+
|
|
193
|
+
/** Release backend resources. After dispose the noggin is unusable. */
|
|
194
|
+
dispose(): Promise<void>;
|
|
195
|
+
|
|
196
|
+
/** Human-readable description of where this noggin lives. Not machine-parseable. */
|
|
197
|
+
describe(): string;
|
|
198
|
+
|
|
199
|
+
readonly onDidChange: Event<void>;
|
|
200
|
+
readonly onDidError: Event<NogginError>;
|
|
200
201
|
}
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
// ── Atomic ops ──────────────────────────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @public
|
|
207
|
+
* Atomic state mutations. Every change to a noggin's state goes through
|
|
208
|
+
* one of these. Verbs compose op lists; backends execute them
|
|
209
|
+
* atomically via `Noggin.apply(ops)`.
|
|
210
|
+
*
|
|
211
|
+
* `position` is the 0-based index among siblings of `parentKey`, or
|
|
212
|
+
* the literal string `'end'` to append.
|
|
213
|
+
*/
|
|
214
|
+
export type AtomicOp =
|
|
215
|
+
| { type: 'add'; item: Item; parentKey: ItemKey | null; position: number | 'end' }
|
|
216
|
+
| { type: 'remove'; keys: readonly ItemKey[] }
|
|
217
|
+
| { type: 'set'; key: ItemKey; patch: { title?: string; done?: boolean } }
|
|
218
|
+
| { type: 'note'; key: ItemKey; note: Note }
|
|
219
|
+
| { type: 'move'; key: ItemKey; parentKey: ItemKey | null; position: number | 'end' }
|
|
220
|
+
| { type: 'setActive'; key: ItemKey | null };
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @public
|
|
224
|
+
* Apply a list of `AtomicOp`s to a `NogginDocument` in-place, then
|
|
225
|
+
* validate. Used by backends inside their `apply()`; also useful for
|
|
226
|
+
* offline document manipulation. Throws `NogginError` if any op
|
|
227
|
+
* references missing data or the resulting document is malformed.
|
|
228
|
+
*/
|
|
229
|
+
export function applyOps(doc: NogginDocument, ops: readonly AtomicOp[]): NogginDocument;
|
|
203
230
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
231
|
+
/**
|
|
232
|
+
* @public
|
|
233
|
+
* Validate a document's structural invariants. Throws `NogginError`
|
|
234
|
+
* with code `'invalid-document'` on failure.
|
|
235
|
+
*/
|
|
236
|
+
export function validateDocument(doc: NogginDocument): void;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @public
|
|
240
|
+
* Normalize a parsed document in-place: stamp schemaVersion, normalize
|
|
241
|
+
* notes, strip legacy fields.
|
|
242
|
+
*/
|
|
243
|
+
export function normalizeDocument(doc: NogginDocument): NogginDocument;
|
|
244
|
+
|
|
245
|
+
/** @internal Used by serializers and `applyOps`. */
|
|
246
|
+
export function normalizeNote(note: { timestamp?: string | null; text: string }): Note;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @public
|
|
250
|
+
* Structural equality between two documents. Used by backends to
|
|
251
|
+
* decide whether an external change actually changed anything.
|
|
252
|
+
*/
|
|
253
|
+
export function documentsEqual(a: NogginDocument, b: NogginDocument): boolean;
|
|
209
254
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
255
|
+
/**
|
|
256
|
+
* @public
|
|
257
|
+
* Deep-freeze a document so accessors can return references without
|
|
258
|
+
* worrying about consumer mutation.
|
|
259
|
+
*/
|
|
260
|
+
export function freezeDocument(doc: NogginDocument): NogginDocument;
|
|
215
261
|
|
|
216
|
-
// ──
|
|
262
|
+
// ── Verbs ───────────────────────────────────────────────────────────────────
|
|
217
263
|
|
|
264
|
+
/** @public Optional context for verbs that stamp timestamps. */
|
|
265
|
+
export interface VerbContext {
|
|
266
|
+
/** Fixed clock for deterministic timestamps in tests. */
|
|
267
|
+
now?: Date;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** @public */
|
|
218
271
|
export interface PushOptions { title: string }
|
|
272
|
+
/** @public */
|
|
219
273
|
export interface AddOptions extends GotoOption { title: string; placement?: Placement }
|
|
274
|
+
/** @public */
|
|
220
275
|
export interface MoveOptions extends GotoOption { path?: ItemPath; placement: Placement }
|
|
221
|
-
|
|
276
|
+
/** @public */
|
|
277
|
+
export interface GotoOptions { path: ItemPath }
|
|
222
278
|
|
|
223
|
-
/** Shared shape for closing verbs (`done`, `pop`, `
|
|
279
|
+
/** @public Shared shape for closing verbs (`done`, `pop`, `edit --done`). */
|
|
224
280
|
export interface CloseOptions {
|
|
225
|
-
/** Skip the open-descendant safety check; close the target even with open kids. */
|
|
226
281
|
force?: boolean;
|
|
227
|
-
/** Close every open descendant first (each gets its own system close note). */
|
|
228
282
|
closeAll?: boolean;
|
|
229
283
|
}
|
|
230
284
|
|
|
285
|
+
/** @public */
|
|
231
286
|
export interface DoneOptions extends CloseOptions { path?: ItemPath }
|
|
287
|
+
/** @public */
|
|
232
288
|
export interface PopOptions extends CloseOptions {}
|
|
233
289
|
|
|
234
|
-
/**
|
|
235
|
-
* `edit` combines the old `set-state` and `retitle` verbs into one
|
|
236
|
-
* idempotent mutation verb. Specify at least one of `done`/`title`;
|
|
237
|
-
* each operation is a no-op when the value already matches.
|
|
238
|
-
*/
|
|
290
|
+
/** @public */
|
|
239
291
|
export interface EditOptions extends GotoOption, CloseOptions {
|
|
240
292
|
path?: ItemPath;
|
|
241
|
-
/** true → close, false → reopen, undefined → don't touch state. */
|
|
242
293
|
done?: boolean;
|
|
243
|
-
/** New title (trimmed). Empty/whitespace is ignored, not an error. */
|
|
244
294
|
title?: string;
|
|
245
295
|
}
|
|
246
296
|
|
|
297
|
+
/** @public */
|
|
247
298
|
export interface ShowOptions extends GotoOption {
|
|
248
299
|
path?: ItemPath;
|
|
249
|
-
/** Whether to expand the target's `children` field. Default true; set false for --no-children. */
|
|
250
300
|
includeChildren?: boolean;
|
|
251
|
-
/** Show note bodies in human output (no effect on JSON — notes are always present). */
|
|
252
301
|
withNotes?: boolean;
|
|
253
|
-
/** Include the full sibling row at every ancestor depth. */
|
|
254
302
|
withSiblings?: boolean;
|
|
255
|
-
/** Expand the target's subtree recursively. */
|
|
256
303
|
withDescendants?: boolean;
|
|
257
304
|
}
|
|
305
|
+
/** @public */
|
|
258
306
|
export interface NoteOptions extends GotoOption { path?: ItemPath; text: string }
|
|
307
|
+
/** @public */
|
|
259
308
|
export interface DeleteOptions { path: ItemPath; recursive?: boolean }
|
|
260
309
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
310
|
+
/**
|
|
311
|
+
* @public
|
|
312
|
+
* The single verb implementation, shared by every backend. Each verb
|
|
313
|
+
* reads state via the `Noggin`'s accessors, composes an `AtomicOp[]`,
|
|
314
|
+
* calls `noggin.apply(ops)` once, and returns the resulting view (or
|
|
315
|
+
* a `DeleteResult` for delete).
|
|
316
|
+
*
|
|
317
|
+
* Verb behavior contracts (push moves active, add doesn't, done
|
|
318
|
+
* appends a close note and surfaces to parent, etc.) live here.
|
|
319
|
+
* Backends do not implement verbs.
|
|
320
|
+
*/
|
|
321
|
+
export const verbs: {
|
|
322
|
+
push(noggin: Noggin, opts: PushOptions, ctx?: VerbContext): Promise<CurrentTreeView>;
|
|
323
|
+
add(noggin: Noggin, opts: AddOptions, ctx?: VerbContext): Promise<CurrentTreeView>;
|
|
324
|
+
move(noggin: Noggin, opts: MoveOptions): Promise<CurrentTreeView>;
|
|
325
|
+
goto(noggin: Noggin, opts: GotoOptions): Promise<CurrentTreeView>;
|
|
326
|
+
done(noggin: Noggin, opts?: DoneOptions, ctx?: VerbContext): Promise<CurrentTreeView>;
|
|
327
|
+
pop(noggin: Noggin, opts?: PopOptions, ctx?: VerbContext): Promise<CurrentTreeView>;
|
|
328
|
+
edit(noggin: Noggin, opts: EditOptions, ctx?: VerbContext): Promise<CurrentTreeView>;
|
|
329
|
+
show(noggin: Noggin, opts?: ShowOptions): Promise<CurrentTreeView | null>;
|
|
330
|
+
note(noggin: Noggin, opts: NoteOptions, ctx?: VerbContext): Promise<CurrentTreeView>;
|
|
331
|
+
delete(noggin: Noggin, opts: DeleteOptions): Promise<DeleteResult>;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
// ── Factory registry ───────────────────────────────────────────────────────
|
|
335
|
+
|
|
336
|
+
/** @public A backend factory: claims a scheme prefix, opens a Noggin. */
|
|
337
|
+
export interface NogginFactory {
|
|
338
|
+
readonly scheme: string;
|
|
339
|
+
open(location: string, opts?: object): Promise<Noggin>;
|
|
340
|
+
}
|
|
272
341
|
|
|
273
|
-
|
|
342
|
+
/** @public Registry interface. The exported `factories` is the singleton. */
|
|
343
|
+
export interface NogginFactoryRegistry {
|
|
344
|
+
register(factory: NogginFactory, opts?: { default?: boolean }): void;
|
|
345
|
+
unregister(scheme: string): boolean;
|
|
346
|
+
get(scheme: string): NogginFactory | null;
|
|
347
|
+
getDefault(): NogginFactory | null;
|
|
348
|
+
list(): readonly { scheme: string; default: boolean }[];
|
|
349
|
+
}
|
|
274
350
|
|
|
275
|
-
|
|
276
|
-
export
|
|
351
|
+
/** @public The process-wide noggin factory registry. */
|
|
352
|
+
export const factories: NogginFactoryRegistry;
|
|
277
353
|
|
|
278
|
-
|
|
279
|
-
|
|
354
|
+
/**
|
|
355
|
+
* @public
|
|
356
|
+
* Open a noggin by location. The scheme prefix (e.g. `file://`,
|
|
357
|
+
* `localstorage://`) selects the factory; a bare location goes to
|
|
358
|
+
* whichever factory was registered with `{default: true}`.
|
|
359
|
+
*/
|
|
360
|
+
export function openNoggin(location: string, opts?: object): Promise<Noggin>;
|
|
280
361
|
|
|
281
|
-
|
|
362
|
+
// ── Public utilities ────────────────────────────────────────────────────────
|
|
282
363
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
364
|
+
/**
|
|
365
|
+
* @public
|
|
366
|
+
* Resolve a path string against a doc-shaped `{items, active}` snapshot.
|
|
367
|
+
* Throws `NogginError('path-not-found')` if the path doesn't resolve.
|
|
368
|
+
*/
|
|
369
|
+
export function resolvePath(snapshot: { items: Item[]; active: ItemKey | null }, p: ItemPath): Item;
|
|
286
370
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
pathOf(item: Item | null | undefined): ItemPath | null;
|
|
290
|
-
resolvePath(path: ItemPath): Item;
|
|
291
|
-
tryResolvePath(path: ItemPath): Item | null;
|
|
371
|
+
/** @public Like `resolvePath` but returns `null` instead of throwing. */
|
|
372
|
+
export function tryResolvePath(snapshot: { items: Item[]; active: ItemKey | null }, p: ItemPath): Item | null;
|
|
292
373
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
opts?: { includeChildren?: boolean }
|
|
296
|
-
): CurrentTreeView | null;
|
|
374
|
+
/** @public Compute the absolute path string for an item. */
|
|
375
|
+
export function pathOf(snapshot: { items: Item[] }, item: Item | null | undefined): ItemPath | null;
|
|
297
376
|
|
|
298
|
-
|
|
299
|
-
|
|
377
|
+
/** @public Direct children of `parentKey` (null = roots), in tree order. */
|
|
378
|
+
export function childrenOf(snapshot: { items: Item[] }, parentKey: ItemKey | null | undefined): Item[];
|
|
300
379
|
|
|
301
|
-
|
|
302
|
-
|
|
380
|
+
/**
|
|
381
|
+
* @public
|
|
382
|
+
* Build a CurrentTreeView for `target`. Pure; does not mutate.
|
|
383
|
+
* Accepts a noggin or a `{items, active}` doc-shape.
|
|
384
|
+
*/
|
|
385
|
+
export function buildView(
|
|
386
|
+
snapshot: { items: readonly Item[]; active: ItemKey | null },
|
|
387
|
+
target: Item,
|
|
388
|
+
opts?: { includeChildren?: boolean; withSiblings?: boolean; withDescendants?: boolean }
|
|
389
|
+
): CurrentTreeView;
|
|
303
390
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
note(opts: NoteOptions): CurrentTreeView;
|
|
313
|
-
delete(opts: DeleteOptions): DeleteResult;
|
|
314
|
-
where(): FileResolution;
|
|
391
|
+
// ── Response envelope ───────────────────────────────────────────────────────
|
|
392
|
+
|
|
393
|
+
/** @public */
|
|
394
|
+
export interface SuccessEnvelope<T = unknown> {
|
|
395
|
+
status: 'ok';
|
|
396
|
+
envelopeVersion: number;
|
|
397
|
+
verb: string | null;
|
|
398
|
+
data: T;
|
|
315
399
|
}
|
|
316
400
|
|
|
317
|
-
|
|
401
|
+
/** @public */
|
|
402
|
+
export interface ErrorEnvelope {
|
|
403
|
+
status: 'error';
|
|
404
|
+
envelopeVersion: number;
|
|
405
|
+
verb: string | null;
|
|
406
|
+
error: {
|
|
407
|
+
code: NogginErrorCode | string;
|
|
408
|
+
message: string;
|
|
409
|
+
exitCode: number;
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** @public */
|
|
414
|
+
export type JsonEnvelope<T = unknown> = SuccessEnvelope<T> | ErrorEnvelope;
|
|
415
|
+
|
|
416
|
+
/** @public */
|
|
417
|
+
export function formatSuccess<T>(opts: { verb?: string; data?: T }): SuccessEnvelope<T>;
|
|
418
|
+
|
|
419
|
+
/** @public */
|
|
420
|
+
export function formatError(opts: { verb?: string; error: unknown }): ErrorEnvelope;
|