dreamteamer 0.20.0 → 0.21.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dreamteamer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "A workspace compiler for coding agents — schema-validated records as plain files over git, compiled into every harness",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Gilad Khen <giladkhen@gmail.com>",
|
|
@@ -227,6 +227,45 @@ Two gates around it:
|
|
|
227
227
|
- ⚠ **An overlay can add fields but cannot remove an inherited one.** If the shape is wrong for
|
|
228
228
|
the module rather than just for this workspace, fix the base.
|
|
229
229
|
|
|
230
|
+
## `x-choices` — what an enum VALUE looks like
|
|
231
|
+
|
|
232
|
+
An enum value carries a label and nothing else by default: a surface gets `{ text, value }` and
|
|
233
|
+
draws the value. `x-choices` is an OPTIONAL sparse map, keyed by the value, that gives a surface
|
|
234
|
+
more to draw with — a board grouping by the field, a dropdown in a form, anything reading
|
|
235
|
+
`edit_options.choices`.
|
|
236
|
+
|
|
237
|
+
```yaml
|
|
238
|
+
lane:
|
|
239
|
+
type: string
|
|
240
|
+
enum: [alpha, bravo, charlie]
|
|
241
|
+
x-choices:
|
|
242
|
+
alpha:
|
|
243
|
+
label: Alpha team # what a surface shows; the stored VALUE is still `alpha`
|
|
244
|
+
description: the one that ships
|
|
245
|
+
icon: rocket # a codicon name …
|
|
246
|
+
color: charts.blue # a theme colour id — the accent
|
|
247
|
+
background: charts.blue # … and the fill
|
|
248
|
+
bravo:
|
|
249
|
+
icon: assets/icons/lucide/anchor # … OR a reference to a `codec: file` record
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
- **Sparse and additive.** Decorate one value, or none. A value with no entry projects exactly as it
|
|
253
|
+
did before this keyword existed, so adding it changes nothing that already works.
|
|
254
|
+
- **`enum` still owns the value set AND its order.** A map key cannot add, remove or reorder a
|
|
255
|
+
value — which matters, because a grouped view takes its band order from the enum.
|
|
256
|
+
- **Five keys, and only five** — `label` · `description` · `icon` · `color` · `background`, each an
|
|
257
|
+
optional string. Anything else in an entry is dropped: the projection copies by name, so a
|
|
258
|
+
descriptor cannot inject keys into a contract every surface reads.
|
|
259
|
+
- **`label` becomes `text`.** So a workspace can relabel a value without touching the value, and no
|
|
260
|
+
stored record moves.
|
|
261
|
+
- **`icon` is a codicon name or a reference to a record of a `codec: file` collection.** A codicon
|
|
262
|
+
name never contains a slash and a record reference always does, so the surface decides which
|
|
263
|
+
without a second keyword.
|
|
264
|
+
- **Colours are theme colour ids, not hex.** A hex is authored against one theme and wrong in the
|
|
265
|
+
other.
|
|
266
|
+
- **Both mistakes warn rather than fail** — a key that is not one of the enum's values, and the
|
|
267
|
+
keyword on a field with no enum. See the message catalog below.
|
|
268
|
+
|
|
230
269
|
## the reference contract — `x-reference` across the module graph
|
|
231
270
|
|
|
232
271
|
Every `x-reference` target must be one of: a **core** collection (the entity kinds plus `repos`)
|
|
@@ -291,6 +330,8 @@ collection author actually meets. (⚠ = warning: it compiled, and you should st
|
|
|
291
330
|
| `cyclic module dependencies: a → b → a` | concept-level links declared as module deps | the collection belongs in `peerDependencies` |
|
|
292
331
|
| relation refusals (`stamps a mirror onto…`, `declared on both sides…`) | the relation rules | `data-modeling.md` Part VI |
|
|
293
332
|
| ⚠ `x-unique on "f" is inert` | a relation keyword with no relation — nothing enforces it | declare the inverse, or drop it |
|
|
333
|
+
| ⚠ `x-choices on "f" has an entry for "k"` | it decorates enum VALUES and `k` is not one — a typo, or a value since removed | fix the spelling, or drop the entry |
|
|
334
|
+
| ⚠ `x-choices on "f" is inert` | the keyword on a field that declares no enum — nothing reads it | give the field an enum, or drop the keyword |
|
|
294
335
|
| ⚠ `collection … has no description` | it renders as a bare name in the orientation block every session loads | write the sentence (`data-modeling.md` §18) |
|
|
295
336
|
| ⚠ `module "…" contributed no recognised sources` | its folders match no kind and it ships no UI bundle | usually a layout or naming mistake |
|
|
296
337
|
| ⚠ `module X: <channel> copy shadows <channel> copy` | the same module delivered twice — the more local wins (npm-link semantics) | intended for dev; otherwise remove one |
|
package/src/compile.js
CHANGED
|
@@ -1315,6 +1315,25 @@ export function compile({ root, pkg }) {
|
|
|
1315
1315
|
if (h['x-unique'] === true && h['x-inverse'] === undefined && h['x-inverse-of'] === undefined) {
|
|
1316
1316
|
console.warn(`⚠ collection ${name}: x-unique on "${fieldName}" is inert — it is a RELATION keyword, enforced only while the store maintains a mirror, and this field declares no x-inverse. Nothing constrains the value. Declare the relation (dreamteamer update-field ${name} --name ${fieldName} --inverse) or drop x-unique.`);
|
|
1317
1317
|
}
|
|
1318
|
+
// `x-choices` decorates ENUM VALUES (presentation.js#choiceRow, 0.21.0), and both ways of
|
|
1319
|
+
// getting it wrong are SILENT: a key that is not a value decorates nothing, and the keyword
|
|
1320
|
+
// on a non-enum field is read by no one at all. Either way the author sees no error and no
|
|
1321
|
+
// decoration — on a surface they are probably not looking at while editing the descriptor.
|
|
1322
|
+
// ⚠ WARNINGS, not failures, for the same reason as x-unique directly above: neither breaks
|
|
1323
|
+
// anything today, and a descriptor mid-edit must stay compilable.
|
|
1324
|
+
const choices = h['x-choices'];
|
|
1325
|
+
if (choices && typeof choices === 'object' && !Array.isArray(choices)) {
|
|
1326
|
+
const values = Array.isArray(h.enum) ? h.enum.map(String) : null;
|
|
1327
|
+
if (!values) {
|
|
1328
|
+
console.warn(`⚠ collection ${name}: x-choices on "${fieldName}" is inert — it decorates the values of an enum, and this field declares no enum. Nothing reads it.`);
|
|
1329
|
+
} else {
|
|
1330
|
+
// Named per offending key rather than "some keys are wrong", and the legal values are
|
|
1331
|
+
// quoted so the fix needs no second lookup — the same shape as every other warning here.
|
|
1332
|
+
for (const k of Object.keys(choices)) {
|
|
1333
|
+
if (!values.includes(k)) console.warn(`⚠ collection ${name}: x-choices on "${fieldName}" has an entry for "${k}", which is not one of its enum values (${values.join(', ')}) — it decorates nothing. Fix the spelling, or drop the entry.`);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1318
1337
|
}
|
|
1319
1338
|
const rt = path.join('collections', `${name}.collection.yaml`);
|
|
1320
1339
|
entries.set(rt, { sources: descriptorSources, bytes: Buffer.from(dump(merged)) });
|
package/src/presentation.js
CHANGED
|
@@ -152,6 +152,33 @@ function titleTemplateOf(prop, descriptors) {
|
|
|
152
152
|
return typeof first === 'string' && first.length > 0 && inherited.every((v) => v === first) ? first : undefined;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
// The keys a descriptor may attach to an enum VALUE through `x-choices` (0.21.0), beyond the label.
|
|
156
|
+
// Copied BY NAME rather than spread: a descriptor is authored data, and spreading whatever it
|
|
157
|
+
// happens to carry would let a workspace inject arbitrary keys into a contract every surface reads.
|
|
158
|
+
// One line is the whole vocabulary, which is also what makes it readable from the consuming side.
|
|
159
|
+
//
|
|
160
|
+
// `icon` is a codicon name OR a reference to a record of a `codec: file` collection — the surface
|
|
161
|
+
// decides which by whether it resolves as a reference, so no second keyword and no set of known
|
|
162
|
+
// collection names. `color`/`background` are theme colour ids for the same reason a hex is not one:
|
|
163
|
+
// a hex is authored against one theme and wrong in the other.
|
|
164
|
+
const CHOICE_KEYS = ['description', 'icon', 'color', 'background'];
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* One `choices` row: `{ text, value }` as it has always been, plus whatever `x-choices` declared.
|
|
168
|
+
*
|
|
169
|
+
* ⚠ PURELY ADDITIVE. A value with no entry projects byte-identically to what it projected before
|
|
170
|
+
* this existed, which is the only reason not one of the descriptors already in the wild had to
|
|
171
|
+
* change. `label` arrives as `text` — the key every surface already reads — so a workspace can
|
|
172
|
+
* relabel a value without touching the value, and a stored record never moves.
|
|
173
|
+
*/
|
|
174
|
+
function choiceRow(v, entry) {
|
|
175
|
+
const row = { text: String(entry?.label ?? v), value: v };
|
|
176
|
+
if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
|
|
177
|
+
for (const k of CHOICE_KEYS) if (typeof entry[k] === 'string' && entry[k].length > 0) row[k] = entry[k];
|
|
178
|
+
}
|
|
179
|
+
return row;
|
|
180
|
+
}
|
|
181
|
+
|
|
155
182
|
function fieldRow(d, name, prop, isRequired, descriptors) {
|
|
156
183
|
const meta = { collection: d.name, field: name };
|
|
157
184
|
if (isRequired) meta.required = true;
|
|
@@ -233,7 +260,7 @@ function fieldRow(d, name, prop, isRequired, descriptors) {
|
|
|
233
260
|
}
|
|
234
261
|
|
|
235
262
|
if (Array.isArray(prop.enum) && prop.enum.length > 0) {
|
|
236
|
-
meta.edit_options = { choices: prop.enum.map((v) => (
|
|
263
|
+
meta.edit_options = { choices: prop.enum.map((v) => choiceRow(v, prop['x-choices']?.[v])) };
|
|
237
264
|
}
|
|
238
265
|
const tpl = titleTemplateOf(prop, descriptors);
|
|
239
266
|
if (typeof tpl === 'string' && tpl.length > 0) meta.view_options = { ...meta.view_options, template: tpl };
|