@nodii/dev 0.6.8 → 0.6.10

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 CHANGED
@@ -146,6 +146,8 @@ nodii-dev figma apply CHANGE_SET --figma-version VERSION
146
146
  nodii-dev figma published CHANGE_SET --figma-version VERSION
147
147
  nodii-dev figma abandon CHANGE_SET
148
148
  nodii-dev figma withdraw CHANGE_SET # take back a submit before anything is decided
149
+ nodii-dev figma resubmit CHANGE_SET PAYLOAD.json # round 2: re-submit every rejected item
150
+ nodii-dev figma changeset show CHANGE_SET # items, variants, round, decision, comment
149
151
  nodii-dev figma release FILE_KEY
150
152
 
151
153
  ```
@@ -168,7 +170,42 @@ an unregistered file prints the `figma file add` command to run.
168
170
  aren't its holder or an operator (`WITHDRAW_NOT_ALLOWED`), or an item is
169
171
  already decided (`CHANGE_SET_HAS_DECISIONS`: ask the reviewer to request
170
172
  changes instead). The CLI prints each refusal in plain words and keeps the
171
- code.
173
+ code. Withdrawing an undecided re-submit returns the set to `applying`.
174
+
175
+ `figma changeset show` lists a Figma change set's current items (the latest
176
+ round of each): each one's decision, its comment (a rejection always has one), its
177
+ round, the previous round's decision and comment when it was re-submitted,
178
+ and its variants. It reads Dev's `getDesignChangeSet`; `--json` also gives the
179
+ replaced rows (`previousRounds`) and the write log. Guideline change sets are
180
+ `design changeset show`.
181
+
182
+ `figma resubmit` is round 2 inside the same change set (Dev's
183
+ `resubmitDesignChangeSet`). When every item is decided and some were
184
+ rejected, the set is `applying`: rework the rejected items in Figma (the lock
185
+ check allows writes in `applying`, and refuses them only while a submit is
186
+ `in_review`), then re-submit them. The payload names every rejected item, by
187
+ `itemId` or `figmaNodeId`, with its new variants, exported at 2x as for
188
+ `figma submit`:
189
+
190
+ ```json
191
+ {
192
+ "figmaVersion": "VERSION",
193
+ "items": [
194
+ { "figmaNodeId": "36:531", "variants": [{ "nodeId": "36:532", "afterPngBase64": "..." }] }
195
+ ]
196
+ }
197
+ ```
198
+
199
+ A variant without a PNG is rendered from Figma, and a variant keeps the
200
+ "before" image from its earlier round. Each item goes back to review with its
201
+ round + 1; approved items keep their decisions; the set goes `in_review`.
202
+ `figma apply` runs once, when every item is approved. Dev refuses when you
203
+ aren't the holder (`CHANGE_SET_HOLDER_REQUIRED`), the set isn't `applying`
204
+ (`INVALID_CHANGE_SET_STATE`), nothing is rejected
205
+ (`CHANGE_SET_HAS_NO_REJECTIONS`), a rejected item is missing (`REJECTED_ITEMS_MISSING`:
206
+ the CLI lists each one with its comment), or the payload names an item that
207
+ isn't rejected (`CHANGE_ITEM_NOT_REJECTED`); images go through the same
208
+ style check as a submit (`CHANGE_SET_IMAGE_STYLE`).
172
209
 
173
210
  ```bash
174
211
  nodii-dev hook claude-figma-pre # reads Claude Code hook JSON on stdin
@@ -191,7 +228,7 @@ nodii-dev lane prioritize|deprioritize KEY --reason TEXT
191
228
  nodii-dev lane stop KEY --reason TEXT
192
229
  nodii-dev lane non-issue KEY --reason TEXT --evidence TEXT --reroute KEY[,KEY]|none
193
230
  --branch carried:ISSUE|dropped[:REASON] [--commits SHA[,SHA]]
194
- nodii-dev next KEY
231
+ nodii-dev next KEY [--paths A,B] [--components K,L] [--role ROLE]
195
232
 
196
233
  nodii-dev built list [--cursor CURSOR] [--include-acknowledged true]
197
234
  nodii-dev built ack KEY [KEY ...] [--note TEXT]
@@ -287,8 +324,60 @@ same checks, plus the ones that need its data, in one transaction.
287
324
  - `docs validate` also prints Dev's warnings for each document (they never
288
325
  block) and any problems with the decision's amends.
289
326
 
327
+ - **Clauses are bullets** (Dev issue 80). A clause is defined only as
328
+ `- **ID** text`. The same id written as a bold paragraph (`**APPR-3.** …`),
329
+ a heading, a bold table row or a numbered item, and defined nowhere as a
330
+ bullet, is refused with `CLAUSE_NOT_A_BULLET` (line and id); text inside the
331
+ bold (`- **ID [INTENDED]** …`) is `CLAUSE_MALFORMED` (write
332
+ `- **ID** [INTENDED] …`). `CLAUSE_COUNT_MISMATCH` then states how many
333
+ clauses Dev would store against how many the source defines, naming the
334
+ missing ids. `docs check` runs these locally; `rulebook list` prints
335
+ `N clauses` for each document.
336
+
337
+ ### Rule delivery (DEC-0020)
338
+
339
+ Every MUST clause declares how it reaches an agent, on one tag line indented
340
+ under the clause:
341
+
342
+ ```
343
+ - **MW2-14** The local gates MUST run in this order, …
344
+ ⟶ enforced · check: review-gates
345
+ - **U03-9** A list MUST page with the shared pager …
346
+ ⟶ served · build: dev_fix · step: adopt_test · side: frontend · comp: data-table
347
+ - **MW1-3** An agent MUST edit only its own config …
348
+ ⟶ core
349
+ ```
350
+
351
+ The delivery is `enforced` (with `check:`, which the document's Enforcement
352
+ table must name), `served` (with optional `build`, `step`, `side`, `svc`,
353
+ `path`, `comp` and `role` tags) or `core`; `gap: ISSUE` marks one that does not
354
+ work yet. `->` and `;` are ASCII aliases for `⟶` and `·`. A tag line as the
355
+ first line under a `###` heading is the default for that sub-section. Dev
356
+ checks every key and value, and refuses a ruling that adds or changes a MUST
357
+ clause with no delivery, and a ratification while any MUST clause has none
358
+ (`RULE_DELIVERY_MISSING`). The full syntax is in Dev's AD-era contract §1.8.
359
+
360
+ ```
361
+ nodii-dev next KEY # the next step, plus the clauses Dev serves for it
362
+ nodii-dev rules core # the generated core (every `core` clause); refused over the cap
363
+ nodii-dev rules report [--section rulebook|services|all] [--lane KEY]
364
+ nodii-dev rules cap TOKENS # operator: the core's token cap (default 3000)
365
+ ```
366
+
367
+ `next` sends the lane's changed files (its branch and working tree against
368
+ `origin/main`, read from the lane's worktree) so Dev serves path-tagged
369
+ clauses only where they apply; `--paths`, `--components` and `--role`
370
+ override. Each served clause prints its id, its first sentence and where to
371
+ read the rest; `--json` carries the full text and token counts. If Dev cannot
372
+ serve rules, `next` still prints the step. `rules report` shows, for each
373
+ document and in total, how many clauses use each delivery, how many MUST
374
+ clauses are untagged and how many carry a tool gap, plus the clauses and
375
+ tokens served to each lane at each step. Tokens are estimated as characters
376
+ divided by four.
377
+
290
378
  Like every other command, these reach Dev only through the platform edge
291
- (`/devops/api/v1/documents`, `/domains`, `/harness`, …) with the OAuth login.
379
+ (`/devops/api/v1/documents`, `/domains`, `/harness`, `/rules`, …) with the
380
+ OAuth login.
292
381
 
293
382
  ## Agent harness
294
383
 
@@ -357,7 +446,8 @@ operation's permission (requested in Dev).
357
446
  name, as Dev compares it), branch and worktree from git unless overridden, and resolves `--issue` keys to the UUIDs
358
447
  required by Dev. Lane keys are passed directly to every lane and Built
359
448
  acknowledgement route. `next` reads the lane's generated
360
- API steps and prints the exact next `lane step` command. Server refusals,
449
+ API steps and prints the exact next `lane step` command, then the rules Dev
450
+ serves for that step (see Rule delivery). Server refusals,
361
451
  including operator-only actions, workflow blocks, lane limits and Built items
362
452
  that are not on dev, retain Dev's error code/message and exit non-zero.
363
453
 
@@ -439,7 +529,9 @@ surfaces, service edges, lanes, swaps, ideas, terminology, and the AD era: `rule
439
529
  `archive` (`archive resolve --ref pre:D1366`), and `harness methodology`. `api list` is the authoritative discovery view;
440
530
  `api OPERATION_ID` makes every operation callable even without an alias.
441
531
 
442
- `figma check` exits `0` when allowed and `3` when denied. The pre-hook permits
532
+ `figma check` exits `0` when allowed and `3` when denied. A held lock is
533
+ denied only while its change set is `in_review` (`change-set-not-editable`),
534
+ and `figma log-write` follows the same rule (`CHANGE_SET_NOT_EDITABLE`). The pre-hook permits
443
535
  non-Figma tools and allowlisted Figma reads, but defaults to denying every
444
536
  Figma write if the file key is absent, Dev cannot be reached, or the lock
445
537
  is denied. It exits `2`, which makes Claude Code block the call. The post-hook
package/dist/api.js CHANGED
@@ -103,6 +103,8 @@ export const GROUPS = {
103
103
  swaps: "Swaps", ideas: "Ideas", terminology: "Terminology", credentials: "Credentials",
104
104
  rulebook: "ad-documents", "ad-decisions": "ad-decisions", domains: "ad-domains", standardizations: "standardizations",
105
105
  archive: "archive", harness: "harness",
106
+ // DEC-0020 rule delivery; `rules core|report|cap` are first-class (upload.js).
107
+ rules: "rulebook",
106
108
  };
107
109
 
108
110
  export const ALIASES = {
package/dist/cli.js CHANGED
@@ -26,8 +26,8 @@ import { heartbeatCurrentLane, postHook, preHook, settingsSnippet, workflowSugge
26
26
  import { setupCommand } from "./setup.js";
27
27
  import { harnessCommand } from "./harness.js";
28
28
  import { doctorCommand } from "./doctor.js";
29
- import { figmaFileKey, notRegisteredHint } from "./figma.js";
30
- import { docsCommand, rulebookCommand } from "./upload.js";
29
+ import { figmaChangeSetShow, figmaChangeSetText, figmaFileKey, figmaResubmit, notRegisteredHint } from "./figma.js";
30
+ import { docsCommand, rulebookCommand, rulesCommand } from "./upload.js";
31
31
  import { changeSetCommand, guidelineCommand } from "./guidelines.js";
32
32
  import {
33
33
  ALIASES,
@@ -70,7 +70,10 @@ Usage: nodii-dev <command> [options] [--json]
70
70
  design guideline propose ENTRY --file FILE.md [--summary TEXT] [--dry-run]
71
71
  design changeset list [--entry KEY] [--state STATE] | show ID
72
72
  figma lock|check|log-write|submit|apply|published|abandon|release
73
- figma withdraw CHANGE_SET # holder takes back a submit: in_review -> editing
73
+ figma withdraw CHANGE_SET # holder takes back a submit: in_review -> editing (or a re-submit -> applying)
74
+ figma resubmit CHANGE_SET PAYLOAD.json
75
+ # holder re-submits every rejected item: applying -> in_review, round + 1
76
+ figma changeset show CHANGE_SET # items, variants, round, decision and comment (with the previous round's)
74
77
  figma file add FILE_KEY --name TEXT --kind design-system|surfaces|prototype [--module M]
75
78
  # register a Figma file in Dev so it can be locked
76
79
  hook claude-figma-pre|claude-figma-post|print-settings
@@ -84,6 +87,9 @@ Usage: nodii-dev <command> [options] [--json]
84
87
  docs ratify --domain KEY [--domain KEY ...] --decision FILE [--wait]
85
88
  docs parked [CODE] [--status pending|acknowledged]
86
89
  rulebook list|show CODE [--version V]|diff CODE
90
+ rules core # the generated core (M05-33); refused over the cap
91
+ rules report [--section S] [--lane KEY] # delivery totals per document; rules served per lane
92
+ rules cap TOKENS # operator: set the core token cap (default 3000)
87
93
 
88
94
  lane start <key> --title TEXT --kind KIND --side SIDE [--repo REPO] [--issue ISSUE]
89
95
  lane step <key> --side SIDE --start|--done|--block <step>
@@ -93,7 +99,8 @@ Usage: nodii-dev <command> [options] [--json]
93
99
  --branch carried:KEY|dropped[:REASON] [--commits SHA[,SHA]]
94
100
  # DEC-0011: terminal non_issue; issue -> wont_do; slot frees
95
101
  lane list [--kind KIND] [--status STATUS] [--mine] [--cursor CURSOR]
96
- lane show <key> | next <key>
102
+ lane show <key> | next <key> [--paths A,B] [--components K,L] [--role R]
103
+ # next step, plus the rules Dev serves for it (DEC-0020)
97
104
  built list | built ack <key...>
98
105
  machine list|show|set-coordinator|assign|report
99
106
  agent lane-limit|grant|revoke
@@ -387,6 +394,7 @@ export async function main(argv = process.argv.slice(2)) {
387
394
  }
388
395
  if (command === "docs") return emitCommand(await docsCommand(action, rest, f));
389
396
  if (command === "rulebook" && ["list", "show", "diff"].includes(action)) return emitCommand(await rulebookCommand(action, rest, f));
397
+ if (command === "rules") return emitCommand(await rulesCommand(action, rest, f));
390
398
  // Guideline change sets: approving or rejecting one is a person's action in Dev.
391
399
  if (command === "design" && action === "guideline") return emitCommand(await guidelineCommand(rest[0], rest.slice(1), f));
392
400
  if (command === "design" && action === "changeset") return emitCommand(await changeSetCommand(rest[0], rest.slice(1), f));
@@ -630,7 +638,14 @@ export async function main(argv = process.argv.slice(2)) {
630
638
  );
631
639
  }
632
640
  if (action === "withdraw")
633
- return emit(await figmaWithdraw(rest[0]), json, `Withdrew ${rest[0]}; it is back in editing.`);
641
+ return emit(await figmaWithdraw(rest[0]), json, (p) => `Withdrew ${rest[0]}; it is back in ${p.data?.state ?? "editing"}.`);
642
+ if (action === "resubmit")
643
+ return emit(await figmaResubmit(rest[0], rest[1]), json, (p) =>
644
+ [`Re-submitted ${rest[0]}; it is ${p.data.state}.`, figmaChangeSetText(p.data)].join("\n"));
645
+ if (action === "changeset") {
646
+ if (rest[0] !== "show" || !rest[1] || rest.length > 2) throw new CliError("USAGE", "figma changeset show CHANGE_SET", 2);
647
+ return emit(await figmaChangeSetShow(rest[1]), json, (p) => figmaChangeSetText(p.data));
648
+ }
634
649
  if (action === "release")
635
650
  return emit(
636
651
  await devRequest(
package/dist/core.js CHANGED
@@ -4,7 +4,7 @@ import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
4
  import { homedir, platform } from "node:os";
5
5
  import { dirname, join } from "node:path";
6
6
 
7
- export const VERSION = "0.6.8";
7
+ export const VERSION = "0.6.10";
8
8
  export const configPath = () =>
9
9
  process.env.NODII_DEV_CONFIG_PATH ??
10
10
  join(homedir(), ".config/nodii-dev/config.json");