@paneui/cli 0.0.14 → 0.0.16
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/dist/commands/create.js +94 -2
- package/dist/commands/template.js +85 -2
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/commands/create.js
CHANGED
|
@@ -14,6 +14,7 @@ const KNOWN_FLAGS = [
|
|
|
14
14
|
"version",
|
|
15
15
|
"event-schema",
|
|
16
16
|
"input-schema",
|
|
17
|
+
"record-schema",
|
|
17
18
|
"title",
|
|
18
19
|
"preamble",
|
|
19
20
|
"input-data",
|
|
@@ -22,6 +23,7 @@ const KNOWN_FLAGS = [
|
|
|
22
23
|
"metadata",
|
|
23
24
|
"callback",
|
|
24
25
|
"context-key",
|
|
26
|
+
"tags",
|
|
25
27
|
"icon-emoji",
|
|
26
28
|
"icon-attachment-id",
|
|
27
29
|
];
|
|
@@ -59,6 +61,7 @@ const SCHEMA_PATH_TO_FLAG = {
|
|
|
59
61
|
"template.source": "--template",
|
|
60
62
|
"template.event_schema": "--event-schema",
|
|
61
63
|
"template.input_schema": "--input-schema",
|
|
64
|
+
"template.record_schema": "--record-schema",
|
|
62
65
|
};
|
|
63
66
|
function schemaPathToFlag(path) {
|
|
64
67
|
const dotted = path.map(String).join(".");
|
|
@@ -82,7 +85,8 @@ A pane is one use of an template. Supply the template in ONE of two ways:
|
|
|
82
85
|
pane create --template-id <id|slug> [--version <n>] [--input-data <v>]
|
|
83
86
|
|
|
84
87
|
Inline form — a one-off template, defined on this call:
|
|
85
|
-
pane create --template <path|inline> [--event-schema <path|json>]
|
|
88
|
+
pane create --template <path|inline> [--event-schema <path|json>]
|
|
89
|
+
[--record-schema <path|json>] [options]
|
|
86
90
|
|
|
87
91
|
Exactly one of --template-id / --template must be given.
|
|
88
92
|
|
|
@@ -106,7 +110,19 @@ Template (choose one):
|
|
|
106
110
|
--event-schema <v> Inline-form event schema. A .json file, or inline JSON.
|
|
107
111
|
Optional with --template. Omit for a view-only template
|
|
108
112
|
(a report/dashboard the human only views — no page/agent
|
|
109
|
-
events).
|
|
113
|
+
events). Rejected with --template-id (the schema comes
|
|
114
|
+
from the pinned template version there).
|
|
115
|
+
|
|
116
|
+
Pane has TWO data primitives — pick the right one before
|
|
117
|
+
designing the schema. Events (this flag) are an
|
|
118
|
+
append-only journal: forms, approvals, surveys, pickers,
|
|
119
|
+
doc reviews. RECORDS (--record-schema, below) are a
|
|
120
|
+
mutable collection: todo lists, shopping lists,
|
|
121
|
+
checklists, kanban boards, comment threads, inventories.
|
|
122
|
+
If the page shows more than one mutable item and the
|
|
123
|
+
current state matters more than the history of edits,
|
|
124
|
+
you want records. See the "Records" section of
|
|
125
|
+
\`pane skill show\` for the decision table.
|
|
110
126
|
|
|
111
127
|
Shape — an object with an "events" map, keyed by event
|
|
112
128
|
type. Each entry declares who may emit it and the JSON
|
|
@@ -135,6 +151,42 @@ Template (choose one):
|
|
|
135
151
|
page via window.pane.downloadBlob. Without it, attachment
|
|
136
152
|
refs in --input-data are silently unreachable. See
|
|
137
153
|
docs/SPEC.md and #208.
|
|
154
|
+
--record-schema <v> Inline-form record schema — declares the per-pane
|
|
155
|
+
mutable collections this template exposes (todos,
|
|
156
|
+
comments, line items, etc.). A .json file, or inline
|
|
157
|
+
JSON. Optional with --template; omit for an event-only
|
|
158
|
+
one-off. Rejected with --template-id (the schema comes
|
|
159
|
+
from the pinned template version there).
|
|
160
|
+
|
|
161
|
+
Shape — a JSON Schema 2020-12 document with an
|
|
162
|
+
"x-pane-collections" extension mapping collection names
|
|
163
|
+
to { schema, write, delete }. \`write\` is a non-empty
|
|
164
|
+
subset of {agent, page}; \`delete\` is a non-empty
|
|
165
|
+
subset of {agent, page, author}.
|
|
166
|
+
{
|
|
167
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
168
|
+
"$defs": {
|
|
169
|
+
"Todo": {
|
|
170
|
+
"type": "object",
|
|
171
|
+
"properties": {
|
|
172
|
+
"text": { "type": "string" },
|
|
173
|
+
"done": { "type": "boolean" }
|
|
174
|
+
},
|
|
175
|
+
"required": ["text"]
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"x-pane-collections": {
|
|
179
|
+
"todos": {
|
|
180
|
+
"schema": { "$ref": "#/$defs/Todo" },
|
|
181
|
+
"write": ["page", "agent"],
|
|
182
|
+
"delete": ["author"]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
See 'pane skill show' (the "Records" section) for the
|
|
187
|
+
full grammar. Use \`pane records …\` to mutate rows in
|
|
188
|
+
a live pane, and \`pane template-records …\` for
|
|
189
|
+
template-level (cross-pane) curated rows.
|
|
138
190
|
|
|
139
191
|
Options:
|
|
140
192
|
--title <text> Tab title shown to the human (max 80 chars, single
|
|
@@ -172,6 +224,13 @@ Options:
|
|
|
172
224
|
meaningful when the calling agent is claimed by a
|
|
173
225
|
human; omit otherwise. Allowed chars: A-Za-z0-9_:.-,
|
|
174
226
|
max 256.
|
|
227
|
+
--tags <t1,t2,...> Per-pane filter tags (comma-separated). Merged with the
|
|
228
|
+
template's tags (deduped) and snapshotted onto the pane;
|
|
229
|
+
they drive the human's Panes-tab tag filter. Use for an
|
|
230
|
+
instance-specific axis on top of the template's tags —
|
|
231
|
+
e.g. a PR-review template tagged \`pr-review\`, with the
|
|
232
|
+
repo per pane: \`--tags cp-backend\`. (\`favorite\`/
|
|
233
|
+
\`favorites\` are reserved; ≤20 tags, ≤50 chars each.)
|
|
175
234
|
--icon-emoji <e> Per-pane icon override — a single emoji grapheme. NULL/
|
|
176
235
|
omitted = inherit the template's icon.
|
|
177
236
|
--icon-attachment-id <id>
|
|
@@ -213,6 +272,9 @@ export async function runCreate(args) {
|
|
|
213
272
|
if (args.flags.get("input-schema") !== undefined) {
|
|
214
273
|
fail("--input-schema is incompatible with --template-id — the input schema comes from the pinned template version. Author the schema on the template (`pane template create --input-schema …`) instead.", "invalid_args");
|
|
215
274
|
}
|
|
275
|
+
if (args.flags.get("record-schema") !== undefined) {
|
|
276
|
+
fail("--record-schema is incompatible with --template-id — the record collections come from the pinned template version. Author the schema on the template (`pane template create --record-schema …`) instead.", "invalid_args");
|
|
277
|
+
}
|
|
216
278
|
// --name / --slug name the inline form's auto-created template. The
|
|
217
279
|
// reference form inherits the existing Template.name/slug, so they have
|
|
218
280
|
// no meaning here — reject rather than silently ignore.
|
|
@@ -246,6 +308,7 @@ export async function runCreate(args) {
|
|
|
246
308
|
// See #208.
|
|
247
309
|
const schemaVal = args.flags.get("event-schema");
|
|
248
310
|
const inputSchemaVal = args.flags.get("input-schema");
|
|
311
|
+
const recordSchemaVal = args.flags.get("record-schema");
|
|
249
312
|
const templateType = (args.flags.get("template-type") ?? "html-inline");
|
|
250
313
|
if (templateType !== "html-inline" && templateType !== "html-ref") {
|
|
251
314
|
fail("--template-type must be 'html-inline' or 'html-ref'", "invalid_args");
|
|
@@ -301,6 +364,22 @@ export async function runCreate(args) {
|
|
|
301
364
|
fail(e instanceof Error ? e.message : String(e), "invalid_args");
|
|
302
365
|
}
|
|
303
366
|
}
|
|
367
|
+
// --record-schema: declares the inline template's per-pane record
|
|
368
|
+
// collections. Absent → no collections (event-only one-off). The relay
|
|
369
|
+
// does the full validation; we only check it parses as an object so a
|
|
370
|
+
// typo surfaces locally rather than as a generic "expected object".
|
|
371
|
+
if (recordSchemaVal !== undefined) {
|
|
372
|
+
try {
|
|
373
|
+
const v = resolveJson(recordSchemaVal, "--record-schema");
|
|
374
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) {
|
|
375
|
+
fail("--record-schema must be a JSON object", "invalid_args");
|
|
376
|
+
}
|
|
377
|
+
inlineArtifact["record_schema"] = v;
|
|
378
|
+
}
|
|
379
|
+
catch (e) {
|
|
380
|
+
fail(e instanceof Error ? e.message : String(e), "invalid_args");
|
|
381
|
+
}
|
|
382
|
+
}
|
|
304
383
|
candidate["template"] = inlineArtifact;
|
|
305
384
|
}
|
|
306
385
|
// --title — passthrough, no client-side requiredness. The relay is the
|
|
@@ -370,6 +449,19 @@ export async function runCreate(args) {
|
|
|
370
449
|
if (contextKey !== undefined) {
|
|
371
450
|
candidate["context_key"] = contextKey;
|
|
372
451
|
}
|
|
452
|
+
// --tags — per-pane filter tags, comma-separated. Merged (deduped) with the
|
|
453
|
+
// template's tags by the relay and snapshotted onto the pane. Useful for an
|
|
454
|
+
// instance-specific axis (e.g. the repo a PR-review pane is for) on top of
|
|
455
|
+
// the template's tags. The relay enforces the limits + reserved names.
|
|
456
|
+
const tagsRaw = args.flags.get("tags");
|
|
457
|
+
if (tagsRaw !== undefined) {
|
|
458
|
+
const tags = tagsRaw
|
|
459
|
+
.split(",")
|
|
460
|
+
.map((t) => t.trim())
|
|
461
|
+
.filter((t) => t !== "");
|
|
462
|
+
if (tags.length > 0)
|
|
463
|
+
candidate["tags"] = tags;
|
|
464
|
+
}
|
|
373
465
|
// Per-pane icon override. Passthrough — the relay validates the emoji
|
|
374
466
|
// (single grapheme) and the attachment (ready raster image, accessible to
|
|
375
467
|
// the agent), so a bad value panes as a schema/route rejection rather than
|
|
@@ -23,6 +23,7 @@ const CREATE_FLAGS = [
|
|
|
23
23
|
"template-type",
|
|
24
24
|
"event-schema",
|
|
25
25
|
"input-schema",
|
|
26
|
+
"record-schema",
|
|
26
27
|
"icon-emoji",
|
|
27
28
|
];
|
|
28
29
|
const SET_ICON_FLAGS = ["template-id", "emoji", "image"];
|
|
@@ -32,6 +33,7 @@ const VERSION_FLAGS = [
|
|
|
32
33
|
"template-type",
|
|
33
34
|
"event-schema",
|
|
34
35
|
"input-schema",
|
|
36
|
+
"record-schema",
|
|
35
37
|
];
|
|
36
38
|
const UPDATE_FLAGS = ["name", "slug", "description", "tags"];
|
|
37
39
|
const NO_FLAGS = [];
|
|
@@ -73,7 +75,8 @@ Subcommands:
|
|
|
73
75
|
pane template create --name <n> --template <path|inline>
|
|
74
76
|
[--event-schema <path|json>] [--slug <s>]
|
|
75
77
|
[--description <d>] [--tags <t1,t2>]
|
|
76
|
-
[--input-schema <path|json>]
|
|
78
|
+
[--input-schema <path|json>]
|
|
79
|
+
[--record-schema <path|json>] [--template-type <t>]
|
|
77
80
|
[--icon-emoji <emoji>]
|
|
78
81
|
Creates a named template. Prints { template_id, slug, version }.
|
|
79
82
|
--icon-emoji sets a single-emoji icon at create time; use 'set-icon'
|
|
@@ -81,7 +84,8 @@ Subcommands:
|
|
|
81
84
|
|
|
82
85
|
pane template version <id|slug> --template <path|inline>
|
|
83
86
|
[--event-schema <path|json>]
|
|
84
|
-
[--input-schema <path|json>]
|
|
87
|
+
[--input-schema <path|json>]
|
|
88
|
+
[--record-schema <path|json>] [--template-type <t>]
|
|
85
89
|
Appends a new immutable version. Prints { template_id, version }.
|
|
86
90
|
|
|
87
91
|
pane template update <id|slug> [--name <n>] [--slug <s>]
|
|
@@ -149,6 +153,17 @@ Options:
|
|
|
149
153
|
report/dashboard the human only views — no page/agent
|
|
150
154
|
events).
|
|
151
155
|
|
|
156
|
+
Pane has TWO data primitives — pick the right one before
|
|
157
|
+
designing the schema. Events (this flag) are an
|
|
158
|
+
append-only journal: forms, approvals, surveys, pickers,
|
|
159
|
+
doc reviews. RECORDS (--record-schema, below) are a
|
|
160
|
+
mutable collection: todo lists, shopping lists,
|
|
161
|
+
checklists, kanban boards, comment threads, inventories.
|
|
162
|
+
If the page shows more than one mutable item and the
|
|
163
|
+
current state matters more than the history of edits,
|
|
164
|
+
you want records. See the "Records" section of
|
|
165
|
+
\`pane skill show\` for the decision table.
|
|
166
|
+
|
|
152
167
|
Shape — an object with an "events" map, keyed by event
|
|
153
168
|
type. Each entry declares who may emit it and the JSON
|
|
154
169
|
Schema for its payload:
|
|
@@ -169,6 +184,39 @@ Options:
|
|
|
169
184
|
emit against it. See docs/SPEC.md for the full grammar.
|
|
170
185
|
--input-schema <v> JSON Schema for this template's per-pane input_data —
|
|
171
186
|
a file path, or inline JSON. Optional.
|
|
187
|
+
--record-schema <v> JSON Schema 2020-12 document declaring this template's
|
|
188
|
+
per-pane record collections — a file path, or inline
|
|
189
|
+
JSON. Optional; omit for an event-only template (no
|
|
190
|
+
mutable collections).
|
|
191
|
+
|
|
192
|
+
Shape — a JSON Schema doc with an "x-pane-collections"
|
|
193
|
+
extension mapping collection names to { schema, write,
|
|
194
|
+
delete } entries. \`write\` is a non-empty subset of
|
|
195
|
+
{agent, page}; \`delete\` is a non-empty subset of
|
|
196
|
+
{agent, page, author}.
|
|
197
|
+
{
|
|
198
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
199
|
+
"$defs": {
|
|
200
|
+
"Todo": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"properties": {
|
|
203
|
+
"text": { "type": "string" },
|
|
204
|
+
"done": { "type": "boolean" }
|
|
205
|
+
},
|
|
206
|
+
"required": ["text"]
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
"x-pane-collections": {
|
|
210
|
+
"todos": {
|
|
211
|
+
"schema": { "$ref": "#/$defs/Todo" },
|
|
212
|
+
"write": ["page", "agent"],
|
|
213
|
+
"delete": ["author"]
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
The relay validates the document and rejects anything
|
|
218
|
+
malformed at create time. See 'pane skill show' (the
|
|
219
|
+
"Records" section) for the full grammar.
|
|
172
220
|
--icon-emoji <e> Single-emoji icon for the template (create only).
|
|
173
221
|
--template-type <t> "html-inline" (default) or "html-ref".
|
|
174
222
|
--url <url> Relay base URL (overrides PANE_URL).
|
|
@@ -229,6 +277,29 @@ function resolveInputSchema(args) {
|
|
|
229
277
|
fail(e instanceof Error ? e.message : String(e), "invalid_args");
|
|
230
278
|
}
|
|
231
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Resolve the optional --record-schema — file path or inline JSON. Must be an
|
|
282
|
+
* object (a JSON Schema 2020-12 document with an `x-pane-collections`
|
|
283
|
+
* extension). Absent → returns `undefined` so the caller omits `record_schema`
|
|
284
|
+
* from the request entirely (template has no record collections). The relay
|
|
285
|
+
* runs the full shape + collection validation; this helper only does the
|
|
286
|
+
* obvious "is it an object" pre-check so a typo surfaces locally.
|
|
287
|
+
*/
|
|
288
|
+
function resolveRecordSchema(args) {
|
|
289
|
+
const raw = args.flags.get("record-schema");
|
|
290
|
+
if (raw === undefined)
|
|
291
|
+
return undefined;
|
|
292
|
+
try {
|
|
293
|
+
const v = resolveJson(raw, "--record-schema");
|
|
294
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) {
|
|
295
|
+
fail("--record-schema must be a JSON object", "invalid_args");
|
|
296
|
+
}
|
|
297
|
+
return v;
|
|
298
|
+
}
|
|
299
|
+
catch (e) {
|
|
300
|
+
fail(e instanceof Error ? e.message : String(e), "invalid_args");
|
|
301
|
+
}
|
|
302
|
+
}
|
|
232
303
|
/** Parse a comma-separated --tags flag into a string array. */
|
|
233
304
|
function resolveTags(args) {
|
|
234
305
|
const raw = args.flags.get("tags");
|
|
@@ -249,6 +320,7 @@ async function runTemplateCreate(args) {
|
|
|
249
320
|
const source = resolveSource(args, type);
|
|
250
321
|
const eventSchema = resolveEventSchema(args);
|
|
251
322
|
const inputSchema = resolveInputSchema(args);
|
|
323
|
+
const recordSchema = resolveRecordSchema(args);
|
|
252
324
|
const tags = resolveTags(args);
|
|
253
325
|
const slug = args.flags.get("slug");
|
|
254
326
|
const description = args.flags.get("description");
|
|
@@ -269,6 +341,11 @@ async function runTemplateCreate(args) {
|
|
|
269
341
|
candidate["tags"] = tags;
|
|
270
342
|
if (inputSchema !== undefined)
|
|
271
343
|
candidate["input_schema"] = inputSchema;
|
|
344
|
+
// record_schema is OMITTED entirely when --record-schema is absent — a
|
|
345
|
+
// template with no record collections (event-only). Setting it to
|
|
346
|
+
// `undefined` would still add the key.
|
|
347
|
+
if (recordSchema !== undefined)
|
|
348
|
+
candidate["record_schema"] = recordSchema;
|
|
272
349
|
const iconEmoji = args.flags.get("icon-emoji");
|
|
273
350
|
if (iconEmoji !== undefined)
|
|
274
351
|
candidate["icon_emoji"] = iconEmoji;
|
|
@@ -302,6 +379,7 @@ async function runTemplateVersion(args) {
|
|
|
302
379
|
const source = resolveSource(args, type);
|
|
303
380
|
const eventSchema = resolveEventSchema(args);
|
|
304
381
|
const inputSchema = resolveInputSchema(args);
|
|
382
|
+
const recordSchema = resolveRecordSchema(args);
|
|
305
383
|
const candidate = {
|
|
306
384
|
source,
|
|
307
385
|
type,
|
|
@@ -312,6 +390,11 @@ async function runTemplateVersion(args) {
|
|
|
312
390
|
candidate["event_schema"] = eventSchema;
|
|
313
391
|
if (inputSchema !== undefined)
|
|
314
392
|
candidate["input_schema"] = inputSchema;
|
|
393
|
+
// record_schema is OMITTED entirely when --record-schema is absent — same
|
|
394
|
+
// rationale as event_schema above. Including the key as undefined would
|
|
395
|
+
// serialise as null and read as "intentionally cleared" on the wire.
|
|
396
|
+
if (recordSchema !== undefined)
|
|
397
|
+
candidate["record_schema"] = recordSchema;
|
|
315
398
|
const parsed = createArtifactVersionSchema.safeParse(candidate);
|
|
316
399
|
if (!parsed.success) {
|
|
317
400
|
const issue = parsed.error.issues[0];
|
package/dist/version.js
CHANGED
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
// Keep this in lockstep with packages/cli/package.json's `version` field;
|
|
9
9
|
// they're consulted in different places (here for the runtime header,
|
|
10
10
|
// package.json for npm publish + dependency resolution).
|
|
11
|
-
export const VERSION = "0.0.
|
|
11
|
+
export const VERSION = "0.0.16";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paneui/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Command-line client for the Pane relay: create panes, inspect state, send and watch events.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"test:unit": "vitest run"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@paneui/core": "^0.0.
|
|
44
|
+
"@paneui/core": "^0.0.16",
|
|
45
45
|
"qrcode-terminal": "^0.12.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|