@nodii/dev 0.6.7 → 0.6.9
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 +55 -3
- package/dist/cli.js +57 -12
- package/dist/core.js +1 -1
- package/dist/devops-openapi.json +1 -1
- package/dist/doctor.js +23 -2
- package/dist/figma.js +106 -0
- package/dist/hooks.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ nodii-dev login [--no-browser] [--scope KEYS]
|
|
|
59
59
|
nodii-dev logout
|
|
60
60
|
nodii-dev whoami # OAuth identity plus the registered agent
|
|
61
61
|
nodii-dev config show
|
|
62
|
-
nodii-dev doctor [--json]
|
|
62
|
+
nodii-dev doctor [--figma-file KEY] [--json] # preflight: everything a lane needs, read-only
|
|
63
63
|
|
|
64
64
|
nodii-dev api list [--tag TAG] [--json]
|
|
65
65
|
nodii-dev api OPERATION_ID [--param name=value ...] [--body @file|-|JSON]
|
|
@@ -137,6 +137,7 @@ only the lists that differ from Dev's current guideline, and `--dry-run`
|
|
|
137
137
|
prints them without creating anything.
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
|
+
nodii-dev figma file add FILE_KEY --name TEXT --kind design-system|surfaces|prototype [--module M]
|
|
140
141
|
nodii-dev figma lock FILE_KEY --title TEXT
|
|
141
142
|
nodii-dev figma check FILE_KEY
|
|
142
143
|
nodii-dev figma log-write CHANGE_SET --tool TOOL --nodes NODE[,NODE]
|
|
@@ -145,10 +146,23 @@ nodii-dev figma apply CHANGE_SET --figma-version VERSION
|
|
|
145
146
|
nodii-dev figma published CHANGE_SET --figma-version VERSION
|
|
146
147
|
nodii-dev figma abandon CHANGE_SET
|
|
147
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
|
|
148
151
|
nodii-dev figma release FILE_KEY
|
|
149
152
|
|
|
150
153
|
```
|
|
151
154
|
|
|
155
|
+
`figma file add` registers a Figma file in Dev so it can be locked; a lane
|
|
156
|
+
can't lock a file Dev doesn't know (`DESIGN_FILE_NOT_FOUND`). Dev first
|
|
157
|
+
reads the file from Figma with its own token. The name must be the file's
|
|
158
|
+
name in Figma: when it isn't, Dev refuses with `DESIGN_FILE_NAME_MISMATCH`
|
|
159
|
+
and the CLI prints the real name to run it again with. Dev also refuses a
|
|
160
|
+
key Figma doesn't know, or a file its Figma account can't see
|
|
161
|
+
(`FIGMA_FILE_NOT_FOUND`, `FIGMA_FILE_NOT_READABLE`: share the file with
|
|
162
|
+
that account). Registering a key Dev already has returns the stored row
|
|
163
|
+
unchanged. A figma.com file link works in place of the key. `figma lock` on
|
|
164
|
+
an unregistered file prints the `figma file add` command to run.
|
|
165
|
+
|
|
152
166
|
`figma withdraw` moves a change set you hold from `in_review` back to
|
|
153
167
|
`editing`, as long as no item has been decided (Dev's
|
|
154
168
|
`withdrawDesignChangeSet`). Dev refuses when the change set doesn't exist
|
|
@@ -156,7 +170,42 @@ nodii-dev figma release FILE_KEY
|
|
|
156
170
|
aren't its holder or an operator (`WITHDRAW_NOT_ALLOWED`), or an item is
|
|
157
171
|
already decided (`CHANGE_SET_HAS_DECISIONS`: ask the reviewer to request
|
|
158
172
|
changes instead). The CLI prints each refusal in plain words and keeps the
|
|
159
|
-
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`).
|
|
160
209
|
|
|
161
210
|
```bash
|
|
162
211
|
nodii-dev hook claude-figma-pre # reads Claude Code hook JSON on stdin
|
|
@@ -333,6 +382,7 @@ exits 0 only when every check is `OK`. `--json` returns the same checks as
|
|
|
333
382
|
| `machine` | The machine this agent is assigned to and its coordinator. No machine means `lane start` would fail with `MACHINE_REQUIRED`. |
|
|
334
383
|
| `repo` | Whether the repository in this directory is the agent's home repository or granted to it. Repositories are compared by short name (`nodii-clis`, not `owner/nodii-clis`), as Dev compares them. Dev does not let an OAuth agent read its own grants yet (requested in Dev), so a repository other than the home one is `CANNOT CHECK`. |
|
|
335
384
|
| `lane_limit` | The agent's active lanes against its lane limit. A full limit is `OK` when a lane on this branch holds the slot. |
|
|
385
|
+
| `figma_file` | Only with `--figma-file KEY` (a key or figma.com link), or `NODII_DEV_FIGMA_FILE`: whether Dev has the brief's Figma file registered. `MISSING` names the `figma file add` command, since `figma lock` would fail with `DESIGN_FILE_NOT_FOUND`. |
|
|
336
386
|
|
|
337
387
|
Doctor may refresh the access token, as any command does. The permission table
|
|
338
388
|
is kept by hand from Dev's route policy until Dev's OpenAPI names each
|
|
@@ -426,7 +476,9 @@ surfaces, service edges, lanes, swaps, ideas, terminology, and the AD era: `rule
|
|
|
426
476
|
`archive` (`archive resolve --ref pre:D1366`), and `harness methodology`. `api list` is the authoritative discovery view;
|
|
427
477
|
`api OPERATION_ID` makes every operation callable even without an alias.
|
|
428
478
|
|
|
429
|
-
`figma check` exits `0` when allowed and `3` when denied.
|
|
479
|
+
`figma check` exits `0` when allowed and `3` when denied. A held lock is
|
|
480
|
+
denied only while its change set is `in_review` (`change-set-not-editable`),
|
|
481
|
+
and `figma log-write` follows the same rule (`CHANGE_SET_NOT_EDITABLE`). The pre-hook permits
|
|
430
482
|
non-Figma tools and allowlisted Figma reads, but defaults to denying every
|
|
431
483
|
Figma write if the file key is absent, Dev cannot be reached, or the lock
|
|
432
484
|
is denied. It exits `2`, which makes Claude Code block the call. The post-hook
|
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,7 @@ 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 { figmaChangeSetShow, figmaChangeSetText, figmaFileKey, figmaResubmit, notRegisteredHint } from "./figma.js";
|
|
29
30
|
import { docsCommand, rulebookCommand } from "./upload.js";
|
|
30
31
|
import { changeSetCommand, guidelineCommand } from "./guidelines.js";
|
|
31
32
|
import {
|
|
@@ -55,7 +56,8 @@ const HELP = `nodii-dev ${VERSION}
|
|
|
55
56
|
Usage: nodii-dev <command> [options] [--json]
|
|
56
57
|
|
|
57
58
|
login | logout | whoami | config show
|
|
58
|
-
doctor [--json]
|
|
59
|
+
doctor [--figma-file KEY] [--json] # preflight: sign-in, agent, permissions, machine, repo, lane slots
|
|
60
|
+
# and, given a key (or NODII_DEV_FIGMA_FILE), that Figma file's registration
|
|
59
61
|
agent register --name NAME | agent heartbeat
|
|
60
62
|
issues list|show|create|update|claim|release
|
|
61
63
|
issues transition ISSUE --to STATUS [--reason TEXT] [--dev-check REF]
|
|
@@ -68,7 +70,12 @@ Usage: nodii-dev <command> [options] [--json]
|
|
|
68
70
|
design guideline propose ENTRY --file FILE.md [--summary TEXT] [--dry-run]
|
|
69
71
|
design changeset list [--entry KEY] [--state STATE] | show ID
|
|
70
72
|
figma lock|check|log-write|submit|apply|published|abandon|release
|
|
71
|
-
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)
|
|
77
|
+
figma file add FILE_KEY --name TEXT --kind design-system|surfaces|prototype [--module M]
|
|
78
|
+
# register a Figma file in Dev so it can be locked
|
|
72
79
|
hook claude-figma-pre|claude-figma-post|print-settings
|
|
73
80
|
setup [--yes|--check] # dry-run by default
|
|
74
81
|
harness install|update [--include-drafts[=false]] [--adopt PATH,...] [--dry-run]
|
|
@@ -288,6 +295,38 @@ export async function figmaWithdraw(id, { request = devRequest } = {}) {
|
|
|
288
295
|
}
|
|
289
296
|
}
|
|
290
297
|
|
|
298
|
+
// Dev's refusals of registerDesignFile, said in terms of what to do next.
|
|
299
|
+
const REGISTER_REFUSALS = {
|
|
300
|
+
DESIGN_FILE_NAME_MISMATCH: (key, details, message) =>
|
|
301
|
+
details?.figmaName ? `Figma names ${key} "${details.figmaName}"; run it again with --name "${details.figmaName}".` : message,
|
|
302
|
+
FIGMA_FILE_NOT_FOUND: (key) => `Figma has no file ${key} that Dev's Figma account can see; check the key, or share the file with that account.`,
|
|
303
|
+
FIGMA_FILE_NOT_READABLE: (key) => `Dev's Figma account can't read ${key}; share the file with that account.`,
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
export async function figmaFileAdd(value, flags, { request = devRequest } = {}) {
|
|
307
|
+
if (!value) throw new CliError("USAGE", "figma file add FILE_KEY --name TEXT --kind KIND [--module M]", 2);
|
|
308
|
+
const key = figmaFileKey(value);
|
|
309
|
+
if (flags.module === true) throw new CliError("USAGE", "--module needs a value", 2);
|
|
310
|
+
const body = { key, name: requireFlag(flags, "name"), kind: requireFlag(flags, "kind"), ...(flags.module ? { module: flags.module } : {}) };
|
|
311
|
+
try {
|
|
312
|
+
return await request("POST", "/api/v1/design/files", body);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
const say = REGISTER_REFUSALS[error?.code];
|
|
315
|
+
if (!say) throw error;
|
|
316
|
+
throw new CliError(error.code, say(key, error.details, error.message), error.exitCode ?? 1, error.details);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export async function figmaLock(value, title, { request = devRequest } = {}) {
|
|
321
|
+
const key = figmaFileKey(value);
|
|
322
|
+
try {
|
|
323
|
+
return await request("POST", `/api/v1/design/files/${encode(key)}/lock`, { changeSetTitle: title });
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (error?.code !== "DESIGN_FILE_NOT_FOUND") throw error;
|
|
326
|
+
throw new CliError(error.code, notRegisteredHint(key), error.exitCode ?? 1, error.details);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
291
330
|
export async function main(argv = process.argv.slice(2)) {
|
|
292
331
|
if (argv.length === 1 && ["--version", "-v"].includes(argv[0]))
|
|
293
332
|
return console.log(VERSION);
|
|
@@ -338,7 +377,8 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
338
377
|
if (command === "setup") return emitCommand(await setupCommand(f));
|
|
339
378
|
if (command === "doctor") {
|
|
340
379
|
if (action) throw new CliError("USAGE", `doctor takes no arguments, got: ${[action, ...rest].join(" ")}`, 2);
|
|
341
|
-
|
|
380
|
+
if (f["figma-file"] === true) throw new CliError("USAGE", "--figma-file needs a file key or figma.com link", 2);
|
|
381
|
+
const result = await doctorCommand(f["figma-file"] ? { figmaFile: f["figma-file"] } : {});
|
|
342
382
|
emit(result.payload, json, result.human);
|
|
343
383
|
if (result.exitCode) process.exitCode = result.exitCode;
|
|
344
384
|
return;
|
|
@@ -544,14 +584,12 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
544
584
|
}
|
|
545
585
|
if (command === "figma") {
|
|
546
586
|
if (action === "lock")
|
|
547
|
-
return emit(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
json,
|
|
554
|
-
);
|
|
587
|
+
return emit(await figmaLock(rest[0], requireFlag(f, "title")), json);
|
|
588
|
+
if (action === "file") {
|
|
589
|
+
if (rest[0] !== "add") throw new CliError("USAGE", "figma file add FILE_KEY --name TEXT --kind KIND [--module M]", 2);
|
|
590
|
+
return emit(await figmaFileAdd(rest[1], f), json, (p) =>
|
|
591
|
+
`${p.data.fileKey} is registered in Dev: ${p.data.name} (${p.data.kind}${p.data.module ? `, ${p.data.module}` : ""}).`);
|
|
592
|
+
}
|
|
555
593
|
if (action === "check") {
|
|
556
594
|
const c = await readConfig();
|
|
557
595
|
const result = await devRequest(
|
|
@@ -595,7 +633,14 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
595
633
|
);
|
|
596
634
|
}
|
|
597
635
|
if (action === "withdraw")
|
|
598
|
-
return emit(await figmaWithdraw(rest[0]), json, `Withdrew ${rest[0]}; it is back in editing.`);
|
|
636
|
+
return emit(await figmaWithdraw(rest[0]), json, (p) => `Withdrew ${rest[0]}; it is back in ${p.data?.state ?? "editing"}.`);
|
|
637
|
+
if (action === "resubmit")
|
|
638
|
+
return emit(await figmaResubmit(rest[0], rest[1]), json, (p) =>
|
|
639
|
+
[`Re-submitted ${rest[0]}; it is ${p.data.state}.`, figmaChangeSetText(p.data)].join("\n"));
|
|
640
|
+
if (action === "changeset") {
|
|
641
|
+
if (rest[0] !== "show" || !rest[1] || rest.length > 2) throw new CliError("USAGE", "figma changeset show CHANGE_SET", 2);
|
|
642
|
+
return emit(await figmaChangeSetShow(rest[1]), json, (p) => figmaChangeSetText(p.data));
|
|
643
|
+
}
|
|
599
644
|
if (action === "release")
|
|
600
645
|
return emit(
|
|
601
646
|
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.
|
|
7
|
+
export const VERSION = "0.6.9";
|
|
8
8
|
export const configPath = () =>
|
|
9
9
|
process.env.NODII_DEV_CONFIG_PATH ??
|
|
10
10
|
join(homedir(), ".config/nodii-dev/config.json");
|