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/README.md
CHANGED
|
@@ -4,8 +4,8 @@ A small, single-user working-memory tree for in-flight work — your
|
|
|
4
4
|
second brain for the stuff you can't fit in your head.
|
|
5
5
|
|
|
6
6
|
Lives in `~/.noggin.yaml` by default. Override per call with `--file
|
|
7
|
-
<path>`, or set `$
|
|
8
|
-
different file. (The VS Code extension sets `
|
|
7
|
+
<path>`, or set `$NOGGIN` to point every invocation at a
|
|
8
|
+
different file. (The VS Code extension sets `NOGGIN` in its
|
|
9
9
|
terminals so the CLI follows whichever noggin you have open.) Driven
|
|
10
10
|
by [`noggin.mjs`](noggin.mjs) next to this file. The YAML file is the source
|
|
11
11
|
of truth; the CLI is the only sanctioned way to read or write it.
|
|
@@ -110,10 +110,12 @@ Every command takes:
|
|
|
110
110
|
The file is resolved in this order:
|
|
111
111
|
|
|
112
112
|
1. `--file <path>`
|
|
113
|
-
2. `$
|
|
113
|
+
2. `$NOGGIN` environment variable
|
|
114
114
|
3. `~/.noggin.yaml`
|
|
115
115
|
|
|
116
|
-
Use `noggin where` at any time to print
|
|
116
|
+
Use `noggin where` at any time to print the canonical location of
|
|
117
|
+
the noggin currently in use (a round-trippable string like
|
|
118
|
+
`~/.noggin.yaml`, `./.noggin.yaml`, or an absolute path).
|
|
117
119
|
why.
|
|
118
120
|
|
|
119
121
|
Commands that change or inspect a target also take `--goto [path]`.
|
|
@@ -135,7 +137,8 @@ Common flags can appear before or after the verb.
|
|
|
135
137
|
| `show [<path>] [--no-children\|--with-descendants] [--with-siblings] [--with-all] [--with-notes] [--goto [path]]` | Current-position view: ancestor spine, sibling peers, current-item details, and first-level children. Default target is active. `--no-children` omits children. `--with-siblings` also includes the full sibling row at every ancestor depth (sibling subtrees stay collapsed). `--with-descendants` expands the target's subtree recursively. `--with-all` = `--with-siblings --with-descendants`. `--with-notes` appends note bodies. `--no-children` and `--with-descendants` are mutually exclusive. |
|
|
136
138
|
| `note [<path>] <text…> [--goto [path]]` | Append a timestamped note. |
|
|
137
139
|
| `delete <path> [--recursive]` | Remove an item. Refuses if the item has descendants unless `--recursive` is passed, in which case the whole subtree is deleted. If the active item is inside the deleted subtree, active falls back to the deleted item's parent (or becomes empty if it was a root). |
|
|
138
|
-
| `where` | Print
|
|
140
|
+
| `where` | Print the canonical location string of the noggin in use. |
|
|
141
|
+
| `copy <from> <to>` | Append every item from the `<from>` noggin into the `<to>` noggin. Whole-noggin, append-only. Source roots become new roots of dest, after any existing dest content. Keys are regenerated; notes, done state, and `createdAt` are preserved verbatim. Source is not modified. Dest's `active` is unchanged. v1 copies the entire source; subtree slicing is reserved for a later version. |
|
|
139
142
|
| `help` | Print full help. |
|
|
140
143
|
|
|
141
144
|
### Tree output
|
|
@@ -156,30 +159,33 @@ append them after the tree.
|
|
|
156
159
|
|
|
157
160
|
### JSON output
|
|
158
161
|
|
|
159
|
-
`--json` and `--with-json` emit a stable envelope shared with
|
|
160
|
-
extension's language-model tools, so a single consumer can
|
|
161
|
-
surfaces.
|
|
162
|
+
`--json` and `--with-json` emit a stable response envelope shared with
|
|
163
|
+
the VS Code extension's language-model tools, so a single consumer can
|
|
164
|
+
target both surfaces.
|
|
162
165
|
|
|
163
166
|
```jsonc
|
|
164
167
|
// success
|
|
165
168
|
{
|
|
166
169
|
"status": "ok",
|
|
167
|
-
"
|
|
170
|
+
"envelopeVersion": 3, // RESPONSE_ENVELOPE_VERSION — bump on breaking changes
|
|
168
171
|
"verb": "push", // command that produced this payload
|
|
169
|
-
"file": "/…/.noggin.yaml", // resolved noggin file
|
|
170
172
|
"data": { … } // verb-specific (CurrentTreeView, DeleteResult, …)
|
|
171
173
|
}
|
|
172
174
|
|
|
173
175
|
// error (written to stderr; exit code matches error.exitCode)
|
|
174
176
|
{
|
|
175
177
|
"status": "error",
|
|
176
|
-
"
|
|
178
|
+
"envelopeVersion": 3,
|
|
177
179
|
"verb": "push",
|
|
178
|
-
"file": "/…/.noggin.yaml",
|
|
179
180
|
"error": { "code": "title-required", "message": "…", "exitCode": 2 }
|
|
180
181
|
}
|
|
181
182
|
```
|
|
182
183
|
|
|
184
|
+
`envelopeVersion` versions the wrapper shape (and the per-verb
|
|
185
|
+
payloads inside `data`), independently of the on-disk document's
|
|
186
|
+
`schemaVersion` (see [File schema](#file-schema-v1)). The two rev
|
|
187
|
+
on different cadences.
|
|
188
|
+
|
|
183
189
|
Inside `data`, a small whitelist of fields whose value matches their
|
|
184
190
|
declared default is **omitted** to keep payloads focused. A consumer
|
|
185
191
|
that doesn't see one of these fields should treat it as the default:
|
|
@@ -193,11 +199,12 @@ that doesn't see one of these fields should treat it as the default:
|
|
|
193
199
|
| `activeKey` | `null` (no active item) |
|
|
194
200
|
| `descendantCount` | `0` (in `DeleteResult`) |
|
|
195
201
|
| `view` | `null` (delete left the tree empty) |
|
|
196
|
-
| `exists` | `false` (in `where` output) |
|
|
197
|
-
| `env` | `null` (in `where` output, no `$NOGGIN_FILE` set) |
|
|
198
202
|
|
|
199
203
|
Everything else is always present, including the envelope itself
|
|
200
|
-
(`status`, `
|
|
204
|
+
(`status`, `envelopeVersion`, `verb`, `data` / `error`).
|
|
205
|
+
|
|
206
|
+
`where --json` is a special case: `data` is a plain string (the
|
|
207
|
+
canonical location of the noggin), not a structured object.
|
|
201
208
|
|
|
202
209
|
`ViewNode.children` is special: it's already a tri-state encoded by
|
|
203
210
|
presence (see `CurrentTreeView` below). Pruning doesn't touch it.
|
|
@@ -272,8 +279,59 @@ Returned in `data` by `delete`. Always carries the deletion record;
|
|
|
272
279
|
|
|
273
280
|
#### `where`
|
|
274
281
|
|
|
275
|
-
Returns the
|
|
276
|
-
|
|
282
|
+
Returns the canonical location string of the noggin currently in use
|
|
283
|
+
— the same string `openNoggin()` would accept to reopen it. The
|
|
284
|
+
string is round-trippable: `~/.noggin.yaml` stays as `~/.noggin.yaml`,
|
|
285
|
+
`./.noggin.yaml` stays as `./.noggin.yaml`, absolute paths stay
|
|
286
|
+
absolute. Both the human and `--json` output are this single string.
|
|
287
|
+
|
|
288
|
+
## JavaScript API
|
|
289
|
+
|
|
290
|
+
For consumers embedding noggin in a Node process (the VS Code
|
|
291
|
+
extension, custom tooling), there's a small public API beyond the
|
|
292
|
+
CLI:
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
import { fileNoggin } from 'noggin/backends/file';
|
|
296
|
+
|
|
297
|
+
const noggin = await fileNoggin('/path/to/.noggin.yaml', { watch: true });
|
|
298
|
+
const view = await noggin.push({ title: 'spike storage layer' });
|
|
299
|
+
console.log(noggin.active?.title);
|
|
300
|
+
noggin.onDidChange(() => render(noggin.items));
|
|
301
|
+
await noggin.dispose();
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Public surface
|
|
305
|
+
|
|
306
|
+
| What | Where |
|
|
307
|
+
|---|---|
|
|
308
|
+
| `Noggin` class — live noggin with verb methods, accessors, events | `noggin/noggin-api.mjs` |
|
|
309
|
+
| `fileNoggin(path, opts?): Promise<Noggin>` — open a file-backed noggin | `noggin/backends/file.mjs` |
|
|
310
|
+
| `applyX(doc, opts, ctx?)` — pure verb functions over `NogginDocument` | `noggin/noggin-api.mjs` |
|
|
311
|
+
| `fromYaml` / `toYaml` / `fromJson` / `toJson` — serializers | `noggin/serializers/{yaml,json}.mjs` |
|
|
312
|
+
| `NogginError`, `NogginErrorCode` — typed errors | `noggin/noggin-api.mjs` |
|
|
313
|
+
| `formatSuccess` / `formatError` — response envelope helpers | `noggin/noggin-api.mjs` |
|
|
314
|
+
| `SCHEMA_VERSION`, `RESPONSE_ENVELOPE_VERSION` — constants | `noggin/noggin-api.mjs` |
|
|
315
|
+
|
|
316
|
+
All `Noggin` verb methods return `Promise`. Per-instance calls are
|
|
317
|
+
serialized (in-process queue); cross-process callers should treat
|
|
318
|
+
the file as advisory-locked at the application layer.
|
|
319
|
+
|
|
320
|
+
### `NogginDocument` shape
|
|
321
|
+
|
|
322
|
+
The serialized form (what the JSON Schema validates, what
|
|
323
|
+
serializers convert to/from) is just:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
interface NogginDocument {
|
|
327
|
+
schemaVersion: 1;
|
|
328
|
+
active: ItemKey | null;
|
|
329
|
+
items: Item[];
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
A live `Noggin` does not expose `schemaVersion` — that's a wire
|
|
334
|
+
concern, owned by the serializers.
|
|
277
335
|
|
|
278
336
|
## File schema (v1)
|
|
279
337
|
|
|
@@ -281,6 +339,28 @@ The CLI reads and writes a single YAML file. Writes are atomic: the
|
|
|
281
339
|
CLI writes to `<file>.tmp-<pid>-<ts>` and renames over the real path,
|
|
282
340
|
so a partial write never corrupts the user's file.
|
|
283
341
|
|
|
342
|
+
A machine-readable JSON Schema for the noggin data model is published
|
|
343
|
+
at the repo root as [`noggin.schema.json`](../noggin.schema.json).
|
|
344
|
+
The schema describes the shape itself, independent of any particular
|
|
345
|
+
producer or consumer — YAML 1.2 is a JSON superset, so the same schema
|
|
346
|
+
validates both YAML and JSON renderings. To get autocomplete and inline
|
|
347
|
+
validation in VS Code, install the Red Hat YAML extension and add to
|
|
348
|
+
your settings:
|
|
349
|
+
|
|
350
|
+
```jsonc
|
|
351
|
+
"yaml.schemas": {
|
|
352
|
+
"https://dornstein.github.io/noggin/noggin.schema.json": [
|
|
353
|
+
".noggin.yaml",
|
|
354
|
+
"**/.noggin/*.yaml"
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
The CLI enforces stronger invariants than JSON Schema can express
|
|
360
|
+
(unique keys, `parentKey`/`active` referential integrity, the "done
|
|
361
|
+
items have no open descendants" rule unless force-closed) — see
|
|
362
|
+
[Invariants](#invariants) below.
|
|
363
|
+
|
|
284
364
|
### Top-level shape
|
|
285
365
|
|
|
286
366
|
```yaml
|
package/SKILL.md
CHANGED
|
@@ -79,6 +79,7 @@ stable IDs. Don't store them.
|
|
|
79
79
|
| "Add a note about X" | `note <text>` (active) or `note <path> <text>` |
|
|
80
80
|
| "Rename this" | `edit [<path>] --title <new title>` |
|
|
81
81
|
| "Drop this" / "never mind, delete it" | `delete <path>` (add `--recursive` if it has children) |
|
|
82
|
+
| "Migrate my noggin into this repo" / "copy the home noggin into this folder" | `copy <from> <to>` (whole-noggin, append-only; preserves notes and timestamps) |
|
|
82
83
|
|
|
83
84
|
Default to `push` for active side-quests, `add` for everything that
|
|
84
85
|
can wait. The cost of `add` is near zero — capture stray "we should
|
|
@@ -115,15 +116,22 @@ also…" remarks rather than letting them evaporate.
|
|
|
115
116
|
`#nogginPop`, `#nogginNote`, `#nogginEdit`,
|
|
116
117
|
`#nogginMove`, `#nogginDelete`) over shelling out to `noggin.mjs`. The tools always
|
|
117
118
|
target the noggin the user has open in the editor. If you do shell
|
|
118
|
-
out, the CLI honors the `
|
|
119
|
+
out, the CLI honors the `NOGGIN` env var, which the extension
|
|
119
120
|
sets in every terminal — so `node noggin.mjs ...` in a VS Code
|
|
120
121
|
terminal still hits the right file. Use `noggin where` if you need
|
|
121
122
|
to confirm which file the CLI would touch.
|
|
122
|
-
11. **Outside VS Code (Copilot CLI, Claude Code, Codex), prefer the MCP
|
|
123
|
+
11. **Outside VS Code (GitHub Copilot CLI, Claude Code, Codex), prefer the MCP
|
|
123
124
|
tools** (`noggin_show`, `noggin_push`, etc.) when the host has the
|
|
124
125
|
noggin MCP server wired up — they return the same JSON envelope as
|
|
125
126
|
the CLI with no spawn cost. Fall back to `noggin.mjs` only when no
|
|
126
127
|
tool surface is available.
|
|
128
|
+
12. **The MCP server is multi-noggin: every tool call requires a `noggin`
|
|
129
|
+
parameter** — a canonical location string like `~/.noggin.yaml`,
|
|
130
|
+
`./.noggin.yaml`, or `file:///abs/path.yaml`. There is no
|
|
131
|
+
server-wide default. Pass the location the user is working with;
|
|
132
|
+
if you don't know it, ask. Use `noggin_where` to confirm a noggin
|
|
133
|
+
is reachable, or `noggin_factories` to discover what location forms
|
|
134
|
+
the server accepts.
|
|
127
135
|
|
|
128
136
|
## Resumption note template
|
|
129
137
|
|