dreamteamer 0.18.0 → 0.19.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/collections/collections.collection.yaml +19 -4
- package/collections/modules.collection.yaml +30 -5
- package/package.json +1 -1
- package/skills/using-dreamteamer/SKILL.md +34 -4
- package/skills/using-dreamteamer/references/before-you-build.md +2 -2
- package/skills/using-dreamteamer/references/collections.md +29 -9
- package/skills/using-dreamteamer/references/data-modeling.md +24 -12
- package/skills/using-dreamteamer/references/getting-started.md +6 -5
- package/skills/using-dreamteamer/references/ui-views.md +2 -2
- package/src/cli.js +103 -63
- package/src/collections-cli.js +380 -14
- package/src/compile.js +168 -23
- package/src/harnesses.js +7 -1
- package/src/init.js +12 -1
- package/src/runtime.js +7 -1
- package/src/schema-ops.js +1512 -84
- package/src/server.js +87 -15
- package/src/store.js +19 -4
package/src/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import fs from 'node:fs';
|
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { execFileSync } from 'node:child_process';
|
|
15
15
|
import { findWorkspace } from './workspace.js';
|
|
16
|
-
import { compile, staleness, warnIfStale, discoverModules, CHANNEL_LABEL, KINDS } from './compile.js';
|
|
16
|
+
import { compile, staleness, warnIfStale, discoverModules, CHANNEL_LABEL, locationOf, KINDS } from './compile.js';
|
|
17
17
|
import { check } from './check.js';
|
|
18
18
|
import { collectionCommand, emit, relationsCommand } from './collections-cli.js';
|
|
19
19
|
import { init, install, installClone, update, listRepos } from './init.js';
|
|
@@ -78,19 +78,49 @@ the longest DECLARED collection prefix, so finance/transactions/2026/03/coffee i
|
|
|
78
78
|
record keeps the template verbatim. An array
|
|
79
79
|
field prints one item per line)
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
81
|
+
system verbs — the SAME verbs, on the entities the compiler materializes (modules, collections,
|
|
82
|
+
skills, agents, commands, command-bindings, ui-views, collection-templates). ⚠ ONE difference in
|
|
83
|
+
POLICY, not in spelling: a SYSTEM write commits itself, because an uncompilable or unpublished
|
|
84
|
+
schema is not a state a workspace should sit in; a RECORD write does not — \`commit\` publishes it.
|
|
85
|
+
The commit lands in the repo that holds the source, so a write into a git module commits there.
|
|
86
|
+
add collections --name <name> [--module <m>] [--namespace <ns>] [--template docs|entity]
|
|
87
|
+
[--description "…"] [--suffix <s>] [--id-shape dated|slug]
|
|
88
|
+
(--namespace health --name doctors === --name
|
|
89
|
+
health/doctors; a module declaring exactly ONE
|
|
90
|
+
namespace infers it, and the resolved name is echoed.
|
|
91
|
+
--namespace '' means no namespace)
|
|
92
|
+
add modules --name <id> [--description "…"]
|
|
93
|
+
(modules/<id>/ + every kind folder + package.json.
|
|
94
|
+
folder = package name = id, so a module never forks.
|
|
95
|
+
the git shape is \`install --clone <url> [name]\`)
|
|
96
|
+
add skills --name <id> --description "…" (skills/<id>/SKILL.md — --description is required,
|
|
97
|
+
because an undescribed skill is undiscoverable)
|
|
98
|
+
add ui-views --path </route> --target list --collection collections/<c> --layout <id>
|
|
99
|
+
[--id <id>] [k.v=…]
|
|
100
|
+
set <system>/<id> <field>=<value> … (collections: description · use_when · title ·
|
|
101
|
+
title_template · icon · group · list_fields ·
|
|
102
|
+
sort_field · order, plus module=<m>, which MOVES it.
|
|
103
|
+
modules: description · namespaces · dependencies ·
|
|
104
|
+
peerDependencies, record-shaped (modules/core).
|
|
105
|
+
ui-views: dotted keys — options.sort=-date. An empty
|
|
106
|
+
value REMOVES the key; quote it to write the empty
|
|
107
|
+
string itself ('options.sort=""').
|
|
108
|
+
skills/agents/commands/…: frontmatter keys)
|
|
109
|
+
rm <system>/<id> [--force] [--dry-run]
|
|
110
|
+
rename <system>/<id> <new-id> (a collection's rename moves its records, re-suffixes
|
|
111
|
+
the files and rewrites every inbound ref, ONE commit)
|
|
112
|
+
move <system>/<id> --after|--before <id> (nav ordering — it writes \`order\`)
|
|
113
|
+
get collections/<c> [--module <m>] (--module prints ONE module's source contribution
|
|
114
|
+
rather than the merged descriptor)
|
|
115
|
+
list modules | collections | skills | … (id · location · path · namespaces · package name)
|
|
116
|
+
revert <system>/<id> (refused: its source is in git —
|
|
117
|
+
\`git checkout <sha> -- <path>\` then \`dt compile\`)
|
|
118
|
+
|
|
119
|
+
field verbs — a field is the one sub-entity, and it has verbs of its own (there is no \`fields\`
|
|
120
|
+
collection: the ENGINE does not read one, and \`rename-field\` was the only capability it would buy):
|
|
121
|
+
add-field <collection> --name <field> --type <type> [--options a,b] [--default-value v]
|
|
122
|
+
[--required true] [--description "…"] [--many] [--inverse [name]]
|
|
123
|
+
[--inverse-description "…"] [--unique] [--body] [--module <m>]
|
|
94
124
|
[--on-delete restrict|set-null] [--mirror-of <collection>.<field>]
|
|
95
125
|
types: string text markdown boolean number integer date datetime
|
|
96
126
|
enum tags <collection> — a date-time may be written as
|
|
@@ -101,9 +131,11 @@ different word in front of it):
|
|
|
101
131
|
--body marks the field a record's PROSE lands in (the text after the
|
|
102
132
|
frontmatter). One per collection, and a relation mirror needs the
|
|
103
133
|
target to have one.
|
|
104
|
-
|
|
134
|
+
--module writes an OVERLAY in that module (it must declare the base's
|
|
135
|
+
module in dreamteamer.dependencies).
|
|
136
|
+
update-field <collection> --name <field> [--type <type>] [--options a,b] [--default-value v]
|
|
105
137
|
[--required true|false] [--description "…"] [--body true|false]
|
|
106
|
-
[--many] [--inverse [name]] [--unique]
|
|
138
|
+
[--many] [--inverse [name]] [--unique] [--module <m>]
|
|
107
139
|
[--on-delete restrict|set-null] [--mirror-of <collection>.<field>]
|
|
108
140
|
(an existing description survives a retype, and so does every relation
|
|
109
141
|
keyword you do not restate. --inverse on an EXISTING reference is the
|
|
@@ -111,14 +143,16 @@ different word in front of it):
|
|
|
111
143
|
restating --type. --inverse= drops the mirror; --unique false clears
|
|
112
144
|
the one-to-one. Records written before the mirror existed are counted
|
|
113
145
|
for you, with the "relations rebuild" that repairs them.)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
146
|
+
remove-field <collection> --name <field> [--module <m>] [--dry-run]
|
|
147
|
+
(clears the field's VALUES in the same write, and reports the count)
|
|
148
|
+
rename-field <collection> --name <field> --to <new-name> [--module <m>] [--dry-run]
|
|
149
|
+
(rewrites the key in every record AND everywhere a descriptor or view
|
|
150
|
+
names the field: list_fields, sort_field, x-inverse, x-inverse-of,
|
|
151
|
+
title_template, id.generate, a ui-view's options.columns and filter,
|
|
152
|
+
and a command-binding's can-enter/can-exit. ONE commit)
|
|
153
|
+
|
|
154
|
+
Every verb that MOVES records or CLEARS values takes --dry-run and prints its plan first:
|
|
155
|
+
records N · refs M · descriptors K · values cleared V
|
|
122
156
|
|
|
123
157
|
workspace verbs:
|
|
124
158
|
init write the workspace skeleton into the current directory (never compiles)
|
|
@@ -152,21 +186,11 @@ const REF_VERBS = new Set(['get', 'set', 'rm', 'rename', 'history', 'diff', 'rev
|
|
|
152
186
|
const COLLECTION_VERBS = new Set(['list', 'add', 'values']);
|
|
153
187
|
const EITHER_VERBS = new Set(['move', 'commands']);
|
|
154
188
|
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
'rm-collection': ['collections', 'rm'],
|
|
161
|
-
'rename-collection': ['collections', 'rename'],
|
|
162
|
-
'add-view': ['ui-views', 'add'],
|
|
163
|
-
'set-view': ['ui-views', 'set'],
|
|
164
|
-
'rm-view': ['ui-views', 'rm'],
|
|
165
|
-
};
|
|
166
|
-
// These three name their collection POSITIONALLY (`schema add-field contacts --name phone`) and keep
|
|
167
|
-
// their existing verb spelling on it — the schema group is a prefix here, not a rename.
|
|
168
|
-
const SCHEMA_FIELD_OPS = new Set(['add-field', 'update-field', 'remove-field']);
|
|
169
|
-
const SCHEMA_OP_LIST = [...Object.keys(SCHEMA_OPS), ...SCHEMA_FIELD_OPS].join(' | ');
|
|
189
|
+
// FIELD VERBS. Their <target> is a collection and everything else is flags, which is the one shape
|
|
190
|
+
// that differs from the record verbs — so they get their own case arm rather than being folded into
|
|
191
|
+
// `dispatchRecordVerb`. There is no `schema <op>` table any more: system entities take the record
|
|
192
|
+
// verbs, and `collectionCommand`'s interceptors are the whole dispatch (§4).
|
|
193
|
+
const FIELD_VERBS = ['add-field', 'update-field', 'remove-field', 'rename-field'];
|
|
170
194
|
|
|
171
195
|
export function run(argv) {
|
|
172
196
|
const [cmd, ...rest] = argv;
|
|
@@ -184,7 +208,7 @@ export function run(argv) {
|
|
|
184
208
|
process.exit(init({ flags }));
|
|
185
209
|
}
|
|
186
210
|
if (!cmd) {
|
|
187
|
-
|
|
211
|
+
emit(USAGE);
|
|
188
212
|
process.exit(0);
|
|
189
213
|
}
|
|
190
214
|
const ws = findWorkspace();
|
|
@@ -304,11 +328,17 @@ export function run(argv) {
|
|
|
304
328
|
const shadowed = new Map(shadows.map((sh) => [sh.name, sh]));
|
|
305
329
|
console.log('modules:');
|
|
306
330
|
for (const m of modules) {
|
|
307
|
-
|
|
331
|
+
// §10: the folder name IS the label. `hr git_modules @ 3f2a1c (dirty)` needs no
|
|
332
|
+
// legend, and `[inline]` needed one every single time.
|
|
333
|
+
let line = ` ${m.name.padEnd(20)} ${locationOf(m, ws.root)}`;
|
|
308
334
|
if (m.channel === 'git') {
|
|
309
335
|
const ref = tryGit(m.root, ['rev-parse', '--short', 'HEAD']);
|
|
310
336
|
const dirty = tryGit(m.root, ['status', '--porcelain']);
|
|
311
|
-
|
|
337
|
+
// ⚠ A SCHEMA WRITE NOW COMMITS HERE (§9), so a clone can be ahead of its remote
|
|
338
|
+
// with work the operator does not know they are holding. `status` is the command
|
|
339
|
+
// they run when something feels wrong, so it is where the count belongs.
|
|
340
|
+
const ahead = tryGit(m.root, ['rev-list', '--count', 'HEAD', '--not', '--remotes']);
|
|
341
|
+
line += ` @ ${ref ?? '?'}${dirty ? ' (dirty)' : ''}${Number(ahead) > 0 ? ` — ahead ${ahead}, push when ready` : ''}`;
|
|
312
342
|
}
|
|
313
343
|
const sh = shadowed.get(m.name);
|
|
314
344
|
if (sh) line += ` — shadows ${CHANNEL_LABEL[sh.loser]} copy`;
|
|
@@ -347,7 +377,7 @@ export function run(argv) {
|
|
|
347
377
|
process.exit(0);
|
|
348
378
|
}
|
|
349
379
|
case 'help':
|
|
350
|
-
|
|
380
|
+
emit(USAGE);
|
|
351
381
|
process.exit(0);
|
|
352
382
|
case 'list': case 'add': case 'values':
|
|
353
383
|
case 'get': case 'set': case 'rm': case 'rename': case 'history': case 'diff': case 'revert':
|
|
@@ -356,6 +386,20 @@ export function run(argv) {
|
|
|
356
386
|
process.exit(dispatchRecordVerb(ws, cmd, rest));
|
|
357
387
|
// The verb `check`'s stale-mirror message names. It reads the compiled relations, and
|
|
358
388
|
// rebuild WRITES records, so both want the same staleness warning every record verb gets.
|
|
389
|
+
// FIELD VERBS — see FIELD_VERBS. Their <target> is a collection and everything else is
|
|
390
|
+
// flags, so they are their own case rather than being folded into `dispatchRecordVerb`.
|
|
391
|
+
//
|
|
392
|
+
// ⚠ `dt schema <op>` is GONE, not aliased. The 0.12.0 policy: a stale invocation must fail
|
|
393
|
+
// loudly, because a half-working grammar teaches the wrong shape without ever saying so.
|
|
394
|
+
// The `default` arm below names `schema` specifically.
|
|
395
|
+
case 'add-field': case 'update-field': case 'remove-field': case 'rename-field': {
|
|
396
|
+
warnIfStale(ws.root);
|
|
397
|
+
const [target, ...flagArgs] = rest;
|
|
398
|
+
if (!target || target.startsWith('--')) {
|
|
399
|
+
throw new Error(`dt ${cmd} needs a collection: dreamteamer ${cmd} <collection> --name <field> …`);
|
|
400
|
+
}
|
|
401
|
+
process.exit(collectionCommand(ws, target, cmd, flagArgs));
|
|
402
|
+
}
|
|
359
403
|
case 'relations':
|
|
360
404
|
warnIfStale(ws.root);
|
|
361
405
|
process.exit(relationsCommand(ws, rest));
|
|
@@ -364,14 +408,26 @@ export function run(argv) {
|
|
|
364
408
|
case 'ensure':
|
|
365
409
|
warnIfStale(ws.root);
|
|
366
410
|
process.exit(collectionCommand(ws, 'repos', 'ensure', rest));
|
|
367
|
-
case 'schema':
|
|
368
|
-
warnIfStale(ws.root);
|
|
369
|
-
process.exit(dispatchSchemaVerb(ws, rest));
|
|
370
411
|
case 'resolve':
|
|
371
412
|
process.exit(resolveVariables(ws, rest));
|
|
372
413
|
default:
|
|
414
|
+
// ⚠ NAMED, not just unknown. Every doc, skill and downstream script spelled these
|
|
415
|
+
// `dt schema <op>` for seven releases, so the failure has to carry the translation —
|
|
416
|
+
// an "unknown verb" alone sends the reader to `help` to guess which of nine verbs
|
|
417
|
+
// replaced the one they typed. No alias layer and no deprecation window: 0.12.0's
|
|
418
|
+
// policy, and the reason it is the right one is that `dt contacts list` failing
|
|
419
|
+
// loudly is what taught the verb-first grammar in one command.
|
|
420
|
+
if (cmd === 'schema') {
|
|
421
|
+
console.error('✖ unknown verb "schema" — schema verbs are gone since 0.19.0. System entities take the RECORD verbs now:');
|
|
422
|
+
console.error(' dt add collections --name <c> [--module <m>] · dt rm collections/<c> · dt rename collections/<old> <new>');
|
|
423
|
+
console.error(' dt set collections/<c> module=<m> | <scalar>=<v> · dt get collections/<c> [--module <m>]');
|
|
424
|
+
console.error(' dt add-field <c> … · dt update-field <c> … · dt remove-field <c> … · dt rename-field <c> --name <f> --to <g>');
|
|
425
|
+
console.error(' dt add|set|rm|rename modules/<id> … · dt add|set|rm|rename ui-views/<id> …');
|
|
426
|
+
console.error(' the full mapping table is in UPDATING.md (0.18.0 → 0.19.0), and `dt help` has the current spellings.');
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
373
429
|
console.error(`✖ unknown verb "${cmd}" — dreamteamer is verb-first since 0.12.0: dt <verb> [<target>]`);
|
|
374
|
-
|
|
430
|
+
emit(USAGE, 2);
|
|
375
431
|
process.exit(1);
|
|
376
432
|
}
|
|
377
433
|
} catch (e) {
|
|
@@ -468,22 +524,6 @@ function resolveVariables(ws, args) {
|
|
|
468
524
|
return 0;
|
|
469
525
|
}
|
|
470
526
|
|
|
471
|
-
/** Translate `dt schema <op> …` onto the same meta verbs `collectionCommand` already routes. */
|
|
472
|
-
function dispatchSchemaVerb(ws, args) {
|
|
473
|
-
const [op, ...rest] = args;
|
|
474
|
-
if (!op) throw new Error(`dt schema needs an operation — use ${SCHEMA_OP_LIST}`);
|
|
475
|
-
if (SCHEMA_FIELD_OPS.has(op)) {
|
|
476
|
-
const [collection, ...flags] = rest;
|
|
477
|
-
if (!collection || collection.startsWith('--')) {
|
|
478
|
-
throw new Error(`dt schema ${op} needs a collection: dreamteamer schema ${op} <collection> --name <field> …`);
|
|
479
|
-
}
|
|
480
|
-
return collectionCommand(ws, collection, op, flags);
|
|
481
|
-
}
|
|
482
|
-
const pair = SCHEMA_OPS[op];
|
|
483
|
-
if (!pair) throw new Error(`unknown schema operation "${op}" — use ${SCHEMA_OP_LIST}`);
|
|
484
|
-
return collectionCommand(ws, pair[0], pair[1], rest);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
527
|
function tryGit(cwd, args) {
|
|
488
528
|
try { return execFileSync('git', args, { cwd, stdio: QUIET }).toString().trim() || null; } catch { return null; }
|
|
489
529
|
}
|