dreamteamer 0.30.0 → 0.32.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.
Files changed (43) hide show
  1. package/README.md +47 -153
  2. package/collections/collections.collection.yaml +26 -9
  3. package/package.json +14 -2
  4. package/skills/using-dreamteamer/SKILL.md +16 -10
  5. package/skills/using-dreamteamer/references/before-you-build.md +4 -3
  6. package/skills/using-dreamteamer/references/collections.md +71 -1
  7. package/skills/using-dreamteamer/references/commands.md +3 -3
  8. package/skills/using-dreamteamer/references/data-modeling.md +9 -1
  9. package/skills/using-dreamteamer/references/extensions.md +60 -0
  10. package/skills/using-dreamteamer/references/records.md +17 -0
  11. package/skills/using-dreamteamer/references/sessions.md +4 -5
  12. package/skills/using-dreamteamer/references/skills.md +3 -5
  13. package/src/api.d.ts +109 -0
  14. package/src/api.js +70 -0
  15. package/src/check.js +57 -2
  16. package/src/checkout.js +105 -330
  17. package/src/cli.js +90 -274
  18. package/src/collections-cli.js +16 -165
  19. package/src/commit.js +7 -0
  20. package/src/compile.js +211 -155
  21. package/src/events.js +7 -2
  22. package/src/extensions.js +135 -0
  23. package/src/filter.js +1 -1
  24. package/src/harnesses.js +82 -135
  25. package/src/init.js +9 -3
  26. package/src/placement.js +209 -0
  27. package/src/records-api.d.ts +103 -0
  28. package/src/records-api.js +40 -0
  29. package/src/runtime.js +2 -2
  30. package/src/schema-ops.js +26 -9
  31. package/src/store.js +396 -35
  32. package/collections/containers.collection.yaml +0 -81
  33. package/collections/images.collection.yaml +0 -46
  34. package/collections/proofs.collection.yaml +0 -96
  35. package/skills/using-dreamteamer/references/exporting.md +0 -53
  36. package/skills/using-dreamteamer/references/proofs.md +0 -435
  37. package/skills/using-dreamteamer/references/worktrees.md +0 -235
  38. package/src/container-archive.js +0 -356
  39. package/src/containers.js +0 -635
  40. package/src/export-notebooklm.js +0 -502
  41. package/src/land.js +0 -743
  42. package/src/prove.js +0 -1922
  43. package/src/server.js +0 -481
@@ -17,7 +17,6 @@ import {
17
17
  createSkill, refuseHandAuthored, removeEntity, renameEntity, setEntityFrontmatter,
18
18
  } from './schema-ops.js';
19
19
  import { KINDS } from './compile.js';
20
- import { proofPathFor, artifactRefs, pickFixture, readLedger, resolveRequires, envKeys, flagValue } from './prove.js';
21
20
  import { history, historyDiff } from './history.js';
22
21
  import { commandsFor, recordResolver } from './record-commands.js';
23
22
  import { distinctValues } from './field-values.js';
@@ -91,7 +90,6 @@ export function collectionCommand(ws, collection, verb, args) {
91
90
  if (collection === 'collections' && verb === 'get' && flags.module !== undefined) return metaCollectionsGet(ws, store, flags, pos);
92
91
  if (collection === 'collections' && verb === 'move') return metaCollectionsMove(ws, store, flags, pos);
93
92
  if (collection === 'commands' && verb === 'for') return metaCommandsFor(ws, store, flags, pos);
94
- if (collection === 'proofs' && verb === 'list') return metaProofsList(ws, store, flags);
95
93
  if (collection === 'ui-views' && ['add', 'set', 'rm'].includes(verb)) return metaUiView(ws, store, verb, flags, pos);
96
94
  if (collection === 'modules' && verb === 'add') return metaModulesAdd(ws, store, flags);
97
95
  if (collection === 'modules' && verb === 'rm') return metaModulesRm(ws, store, flags, pos);
@@ -107,7 +105,7 @@ export function collectionCommand(ws, collection, verb, args) {
107
105
  // PATH for the five hand-authored kinds; `set` edits frontmatter; `rm` and `rename` work on all
108
106
  // six. Keyed on the collection NAME rather than on `storage.base` because these six are the
109
107
  // ones with a source-file shape — `modules` is projected and `collections` has its own verbs.
110
- if (ENTITY_KINDS.has(collection) && ['add', 'set', 'rm', 'rename'].includes(verb)) {
108
+ if (isEntityKind(store, collection) && ['add', 'set', 'rm', 'rename'].includes(verb)) {
111
109
  return metaEntityVerb(ws, store, collection, verb, flags, pos);
112
110
  }
113
111
  // `revert` on ANY system entity: its history is git's, and `store.revert` writes a RECORD.
@@ -138,34 +136,8 @@ export function collectionCommand(ws, collection, verb, args) {
138
136
  case 'get': {
139
137
  const id = need(pos, 0, 'id');
140
138
  const { fields } = store.read(collection, id);
141
- // ⚠ COMPUTED HERE, NEVER STORED (R1). Compile writes a staged kind's bytes to the runtime
142
- // verbatim and the Claude adapter copies a command's bytes into `.claude/commands/`, so a
143
- // derived `proofs:` frontmatter key would land in every harness's copy of the file — the
144
- // exact noise a sidecar collection exists to avoid. One `readAll('proofs')` instead.
145
- const isArtifact = ARTIFACT_KINDS.has(collection);
146
- const about = isArtifact ? proofsAbout(store, `${collection}/${id}`) : [];
147
- if (flags.json) {
148
- // ⚠ R38 — `proofs` IS NEVER A SOMETIMES-KEY on an artifact. Omitting it when the list was
149
- // empty made "nothing is about this" indistinguishable from "this engine does not compute
150
- // the join", so every consumer needed a `?? []` it had no reason to expect. A collection
151
- // that is not an artifact kind still grows no key at all — there is no join to report.
152
- //
153
- // ⚠ M3 — AND THE PROOF'S OWN TWO COMPUTED COLUMNS TRAVEL WITH IT. `--json` is the shape a
154
- // script reads, and it was the ONE surface that dropped them: `dt list proofs --json`
155
- // carried `availability` and `last`, this carried neither, so a script asking about one
156
- // proof had to list every proof to learn what the text output had already told a human.
157
- const facts = collection === 'proofs' ? proofFacts(ws, store, id, fields) : null;
158
- emit(JSON.stringify({ ...fields, id, ...(isArtifact ? { proofs: about } : {}), ...(facts ?? {}) }, null, 2));
159
- return 0;
160
- }
139
+ if (flags.json) { emit(JSON.stringify({ ...fields, id }, null, 2)); return 0; }
161
140
  console.log(dump(fields).trimEnd());
162
- if (about.length) console.log(`proofs: ${about.join(', ')}`);
163
- // the same two questions the listing answers, for the one proof asked about
164
- if (collection === 'proofs') {
165
- const facts = proofFacts(ws, store, id, fields);
166
- console.log(`availability: ${facts.availability}`);
167
- console.log(`last: ${lastCell(facts.last)}`);
168
- }
169
141
  return 0;
170
142
  }
171
143
  case 'add': {
@@ -739,7 +711,12 @@ function metaRemoveField(ws, store, collection, flags) {
739
711
  return 0;
740
712
  }
741
713
 
742
- const ENTITY_KINDS = new Set(['skills', 'agents', 'commands', 'command-bindings', 'collection-templates', 'proofs']);
714
+ /** An IDENTITY entity kind — a compiled source file per id (skills, agents, commands, bindings,
715
+ * collection-templates, and any kind an extension contributes). Derived from the runtime rather than
716
+ * listed, so a contributed kind gets `set · rm · rename` without core knowing its name; `collections`,
717
+ * `ui-views` and `modules` have verbs of their own. */
718
+ const OWN_VERBS = new Set(['collections', 'ui-views', 'modules']);
719
+ const isEntityKind = (store, collection) => store?.descriptors.get(collection)?.storage?.base === 'runtime' && !OWN_VERBS.has(collection);
743
720
  const SCAFFOLDABLE = new Set(['skills']);
744
721
 
745
722
  function metaEntityVerb(ws, store, kind, verb, flags, pos) {
@@ -756,11 +733,6 @@ function metaEntityVerb(ws, store, kind, verb, flags, pos) {
756
733
  console.log(`✔ ${rel(ws.root, out.file)}`);
757
734
  console.log('✔ compiled — the skill is live (write its body next; the frontmatter is the trigger)');
758
735
  reportCommits(out.commits);
759
- // ⚠ LAST, after the commit report, and it is a nudge rather than a gate: a skill that nobody
760
- // can prove loads is the artifact `dt prove` exists for, and the cheapest moment to say so is
761
- // the moment the file is created. Named path, never a rule to derive — the module root is
762
- // whichever one actually received the skill (`--module`, or the workspace module).
763
- console.log(`no proof yet — ${proofPathFor(`skills/${out.id}`, out.moduleRoot)} (see using-dreamteamer › proofs)`);
764
736
  return 0;
765
737
  }
766
738
  if (verb === 'rm') {
@@ -1194,9 +1166,9 @@ const fmtCell = (v) => (v === undefined ? '-' : Array.isArray(v) ? v.join(',') :
1194
1166
  /**
1195
1167
  * The rows one `list` invocation actually wants — narrowed, ordered, bodies dropped.
1196
1168
  *
1197
- * ⚠ ONE implementation, two callers: the generic `list` case and the `proofs` interceptor, which
1198
- * appends two COMPUTED columns to the same rows. A second copy is how `--sort` ends up working on
1199
- * one collection and not on another, and how a `--filter` fix lands in half the listings.
1169
+ * ⚠ ONE implementation: the generic `list` case is its only caller today, and an interceptor that
1170
+ * adds columns calls it rather than copying it — a second copy is how `--sort` ends up working on
1171
+ * one collection and not on another.
1200
1172
  */
1201
1173
  function narrowRows(store, d, collection, flags) {
1202
1174
  // EVERY condition, ANDed — a repeated flag composes rather than replacing. `--filter a=1
@@ -1249,117 +1221,6 @@ function narrowRows(store, d, collection, flags) {
1249
1221
  /** `id` first, then the descriptor's own columns — the shape every text listing prints. */
1250
1222
  const listColumns = (d) => ['id', ...(d.list_fields ?? []).filter((c) => c !== 'id')];
1251
1223
 
1252
- // ── the proof read surfaces ─────────────────────────────────────────────────────────────────────
1253
- //
1254
- // ⚠ NOTHING BELOW WRITES A BYTE. A proof's SOURCE says what it asserts; everything an operator asks
1255
- // about one — can it run HERE, what did it last answer, what has no proof at all — is a fact about
1256
- // this machine and this store, so it is computed at read time (R1).
1257
-
1258
- /**
1259
- * The three artifact kinds a proof's `about` can name AND `dt get <collection>/<id>` can be asked
1260
- * for. A module script has no record of its own, so `<module>/bin/<file>` appears only in
1261
- * `--missing`.
1262
- *
1263
- * ⚠ THIS IS THE `dt get` HALF OF `artifactRefs`'s FOUR BUCKETS (`src/prove.js`), and the fourth is
1264
- * missing on purpose rather than by omission: `skills` · `commands` · `bindings` each have a record
1265
- * to hang a `proofs:` line off, and `scripts` does not. If a fifth artifact kind is ever added there,
1266
- * it belongs here too — the two enumerations answer the same question from opposite sides, and a
1267
- * kind present in one and absent from the other is a join that silently reports nothing.
1268
- */
1269
- const ARTIFACT_KINDS = new Set(['skills', 'commands', 'command-bindings']);
1270
-
1271
- /** Every proof whose `about` names this artifact, by id. */
1272
- function proofsAbout(store, ref) {
1273
- if (!store.descriptors.has('proofs')) return [];
1274
- const ids = [];
1275
- for (const { id, fields } of store.readAll('proofs')) if ((fields.about ?? []).includes(ref)) ids.push(id);
1276
- return ids.sort();
1277
- }
1278
-
1279
- /**
1280
- * `{ availability, last }` for ONE proof — the two columns no record carries.
1281
- *
1282
- * `availability` answers "could this run here, right now": `requires` against this machine first
1283
- * (its FIX is what the column names, never the env value — `.env` holds credentials), then, for a
1284
- * live proof picking from the live store, whether `given` actually matches anything. A `fixture`
1285
- * proof brings its own record and a gate needs none, so both are `available` once requires pass.
1286
- *
1287
- * `last` is the TAIL of this machine's ledger — a proof that failed on Monday and passed on Tuesday
1288
- * is passing — or null, which prints as `never`.
1289
- *
1290
- * `names` is the machine's `.env` KEY set, read once by a caller that loops (R38) — never its values.
1291
- */
1292
- function proofFacts(ws, store, id, proof, names) {
1293
- const need = resolveRequires(ws, proof.requires, names ?? envKeys(ws.root));
1294
- let availability = need.ok ? 'available' : `unavailable (${need.missing[0].fix})`;
1295
- // ⚠ R38 — THE PROBE TURNS ON "IS THERE A RECORD TO PICK", NOT ON `where`. It used to require a
1296
- // `where`, so a `given` that names its record another way printed `available` and then exited 4
1297
- // on the very next command. A `fixture` proof brings its own record and a gate needs none; every
1298
- // other live proof is a question about THIS store, and the only way to answer it is to ask.
1299
- if (need.ok && proof.given !== undefined && proof.given?.fixture !== true) {
1300
- // a probe, not a run: the only way to answer "is there a record for this" is to ask
1301
- let picked = null;
1302
- try { picked = pickFixture(store, proof.given, null); } catch { picked = null; }
1303
- if (!picked) availability = 'no-fixture';
1304
- }
1305
- const rows = readLedger(ws.root, id);
1306
- const t = rows[rows.length - 1];
1307
- return { availability, last: t ? { verdict: t.verdict, when: String(t.when).slice(0, 10), record: t.record ?? null } : null };
1308
- }
1309
-
1310
- /** The `last` column: `<verdict> <YYYY-MM-DD> [<record>]`, or `never`. */
1311
- const lastCell = (last) => (last ? `${last.verdict} ${last.when}${last.record ? ` [${last.record}]` : ''}` : 'never');
1312
-
1313
- /**
1314
- * `dt list proofs` — the generic listing plus `availability` and `last`, or, under `--missing`, the
1315
- * artifacts NO proof names.
1316
- *
1317
- * ⚠ `--missing` LISTS ARTIFACTS, NOT PROOFS, so it takes no narrowing: accepting `--filter kind=gate`
1318
- * and ignoring it would answer a question nobody asked, at exit 0.
1319
- */
1320
- function metaProofsList(ws, store, flags) {
1321
- const d = store.descriptor('proofs');
1322
- // ⚠ M2/R46 — `--missing=false` TURNED THE FLAG ON. `!== undefined` is true for every value a
1323
- // person can type, so the one spelling that says "no" selected the inverted listing — the same
1324
- // class as `--strict=false` arming a gate, and the same shared reader is the fix.
1325
- if (flagValue(flags.missing)) {
1326
- const narrowing = Object.keys(flags).filter((f) => f !== 'missing' && f !== 'json');
1327
- // ⚠ R38 — IT NAMES THE FLAG THAT CAUSED IT. "it takes no filter" sent a reader who had typed
1328
- // `--sort` looking for a `--filter` they never wrote, which is one round trip more than the
1329
- // refusal needs to cost.
1330
- if (narrowing.length) throw new Error(`--missing lists artifacts, not proofs — drop ${narrowing.map((f) => `--${f}`).join(' ')}`);
1331
- const named = new Set();
1332
- for (const { fields } of store.readAll('proofs')) for (const a of fields.about ?? []) named.add(String(a));
1333
- // the same enumeration compile's coverage line counts, in its order — that line says
1334
- // `commands 1/2`, this says WHICH one
1335
- const refs = artifactRefs(store);
1336
- const missing = [...refs.commands, ...refs.skills, ...refs.scripts, ...refs.bindings].filter((r) => !named.has(r));
1337
- if (flags.json) { emit(JSON.stringify(missing, null, 2)); return 0; }
1338
- for (const m of missing) console.log(m);
1339
- if (!missing.length) console.log('(every artifact has a proof)');
1340
- return 0;
1341
- }
1342
- // ⚠ `missing` IS CONSUMED HERE AND MUST NOT TRAVEL ON. `narrowRows` reads every non-meta flag as
1343
- // a bare-field filter, so `--missing=false` — now correctly read as OFF (M2) — reached it as a
1344
- // filter on a field `proofs` does not have and refused the whole listing. It is this function's
1345
- // own flag, answered above, and there is nothing left of it to narrow by.
1346
- const { missing: _consumed, ...narrowing } = flags;
1347
- const { rows, narrowed } = narrowRows(store, d, 'proofs', narrowing);
1348
- // ONE `.env` parse for the whole listing (R38): the key set is a fact about the machine, and
1349
- // re-reading the file per row is work whose answer cannot change between rows.
1350
- const names = envKeys(ws.root);
1351
- const facts = rows.map((r) => proofFacts(ws, store, r.id, r, names));
1352
- if (flags.json) {
1353
- emit(JSON.stringify(rows.map((r, i) => ({ ...r, ...facts[i] })), null, 2));
1354
- return 0;
1355
- }
1356
- const cols = listColumns(d);
1357
- rows.forEach((r, i) => console.log([...cols.map((c) => fmtCell(r[c])), facts[i].availability, lastCell(facts[i].last)].join(' ')));
1358
- if (!rows.length) console.log(`(no proofs${narrowed ? ' matching' : ''})`);
1359
- return 0;
1360
- }
1361
-
1362
-
1363
1224
  function rel(root, p) {
1364
1225
  return p.startsWith(root) ? p.slice(root.length + 1) : p;
1365
1226
  }
@@ -1411,14 +1272,6 @@ export const VERB_FLAGS = {
1411
1272
  // whatever a harness reads), so there is no closed set to check it against.
1412
1273
  'skills:add': ['json', 'module', 'name', 'description'],
1413
1274
  'ui-views:add': ['json', 'module', 'id', 'force'], 'ui-views:set': ['json', 'module', 'id', 'force'], 'ui-views:rm': FORCE_RM,
1414
- // `worktrees` is OBSERVED from git and has no descriptor, so nothing downstream of the CLI would
1415
- // ever catch a typo here — and the typo that matters is `--tmep`, which silently turns a request
1416
- // for a throwaway sandbox into a permanent branch worktree.
1417
- // `--missing` inverts the listing: the artifacts NO proof names, which is the other half of
1418
- // compile's coverage line. It is DECLARED here or `refuseUnknownFlags` rejects it as a typo.
1419
- 'proofs:list': ['json', 'filter', 'where', 'sort', 'missing'],
1420
- 'worktrees:list': JSON_ONLY, 'worktrees:get': JSON_ONLY,
1421
- 'worktrees:add': ['json', 'name', 'path', 'base', 'temp', 'hook'], 'worktrees:rm': ['json', 'force'],
1422
1275
  };
1423
1276
 
1424
1277
  /** Edit distance, capped — enough to turn `--fliter` into "did you mean --filter?", and to refuse to
@@ -1438,21 +1291,19 @@ function nearest(word, candidates) {
1438
1291
  }
1439
1292
 
1440
1293
  export function refuseUnknownFlags(store, collection, verb, flags) {
1441
- // `store` is null for an entity the store does not know: `worktrees` is observed from git, and
1442
- // the surface still owes its flags the same refusal every other verb gets.
1294
+ // `store` may be null for an entity the store does not know — the refusal is still owed.
1443
1295
  const d = store?.descriptors.get(collection);
1444
1296
  const known = VERB_FLAGS[`${collection}:${verb}`]
1445
- ?? (ENTITY_KINDS.has(collection) && verb === 'add' ? VERB_FLAGS['skills:add'] : VERB_FLAGS[verb]);
1297
+ ?? (isEntityKind(store, collection) && verb === 'add' ? VERB_FLAGS['skills:add'] : VERB_FLAGS[verb]);
1446
1298
  if (!known) return; // no declared vocabulary — left exactly as it was rather than guessed at
1447
1299
  // The OPEN half: a data collection's own fields (shorthand filters and field writes), and the
1448
1300
  // declared keys of an entity `set` writes (`--layout` on a view, and dotted `options.sort`).
1449
1301
  const system = d?.storage?.base === 'runtime';
1450
- // ⚠ NO DESCRIPTOR MEANS NO OPEN HALF. `worktrees` has no fields to shorthand-filter or write, so
1451
- // its vocabulary is CLOSED — offering "plus any field of worktrees" would name a half that does
1452
- // not exist and read as though the refused flag were merely misspelled.
1302
+ // ⚠ NO DESCRIPTOR MEANS NO OPEN HALF — offering "plus any field of X" for a thing with no fields
1303
+ // would read as though the refused flag were merely misspelled.
1453
1304
  const openOf = !d ? null
1454
1305
  : !system ? (['list', 'add', 'set'].includes(verb) ? `field of ${collection}` : null)
1455
- : (collection === 'ui-views' && verb !== 'rm') || (ENTITY_KINDS.has(collection) && verb === 'set') ? `declared key of ${collection}` : null;
1306
+ : (collection === 'ui-views' && verb !== 'rm') || (isEntityKind(store, collection) && verb === 'set') ? `declared key of ${collection}` : null;
1456
1307
  const open = openOf ? Object.keys(d?.schema?.properties ?? {}) : [];
1457
1308
  const allowed = new Set([...known, ...open]);
1458
1309
  for (const f of Object.keys(flags)) {
package/src/commit.js CHANGED
@@ -329,6 +329,13 @@ function scopeByRepo(descriptors, only) {
329
329
  const repo = d.storage.repo ?? '.';
330
330
  if (!byRepo.has(repo)) byRepo.set(repo, []);
331
331
  byRepo.get(repo).push(p);
332
+ // A collection stored UNDER another keeps most of its files inside the parent's folder, so
333
+ // scoping `git status` to its own path alone would sample only the fallback root and report
334
+ // the rest as "nothing pending" — the one report that looks like success. The parent's path
335
+ // joins the pathspec; pathToRecord then attributes each file to the collection it belongs to,
336
+ // and the row filter in commitPlan keeps the parent's own records out of a scoped commit.
337
+ const parent = d.storage.under && descriptors.get(d.storage.under.collection);
338
+ if (parent?.storage?.path && !byRepo.get(repo).includes(parent.storage.path)) byRepo.get(repo).push(parent.storage.path);
332
339
  }
333
340
  return byRepo;
334
341
  }