@nodii/dev 0.6.6 → 0.6.8
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 +27 -1
- package/dist/cli.js +67 -10
- package/dist/core.js +1 -1
- package/dist/devops-openapi.json +1 -1
- package/dist/doctor.js +23 -2
- package/dist/figma.js +15 -0
- 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]
|
|
@@ -144,8 +145,32 @@ nodii-dev figma submit CHANGE_SET --file SUBMISSION.json
|
|
|
144
145
|
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
|
|
148
|
+
nodii-dev figma withdraw CHANGE_SET # take back a submit before anything is decided
|
|
147
149
|
nodii-dev figma release FILE_KEY
|
|
148
150
|
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`figma file add` registers a Figma file in Dev so it can be locked; a lane
|
|
154
|
+
can't lock a file Dev doesn't know (`DESIGN_FILE_NOT_FOUND`). Dev first
|
|
155
|
+
reads the file from Figma with its own token. The name must be the file's
|
|
156
|
+
name in Figma: when it isn't, Dev refuses with `DESIGN_FILE_NAME_MISMATCH`
|
|
157
|
+
and the CLI prints the real name to run it again with. Dev also refuses a
|
|
158
|
+
key Figma doesn't know, or a file its Figma account can't see
|
|
159
|
+
(`FIGMA_FILE_NOT_FOUND`, `FIGMA_FILE_NOT_READABLE`: share the file with
|
|
160
|
+
that account). Registering a key Dev already has returns the stored row
|
|
161
|
+
unchanged. A figma.com file link works in place of the key. `figma lock` on
|
|
162
|
+
an unregistered file prints the `figma file add` command to run.
|
|
163
|
+
|
|
164
|
+
`figma withdraw` moves a change set you hold from `in_review` back to
|
|
165
|
+
`editing`, as long as no item has been decided (Dev's
|
|
166
|
+
`withdrawDesignChangeSet`). Dev refuses when the change set doesn't exist
|
|
167
|
+
(`CHANGE_SET_NOT_FOUND`), isn't in review (`CHANGE_SET_NOT_IN_REVIEW`), you
|
|
168
|
+
aren't its holder or an operator (`WITHDRAW_NOT_ALLOWED`), or an item is
|
|
169
|
+
already decided (`CHANGE_SET_HAS_DECISIONS`: ask the reviewer to request
|
|
170
|
+
changes instead). The CLI prints each refusal in plain words and keeps the
|
|
171
|
+
code.
|
|
172
|
+
|
|
173
|
+
```bash
|
|
149
174
|
nodii-dev hook claude-figma-pre # reads Claude Code hook JSON on stdin
|
|
150
175
|
nodii-dev hook claude-figma-post # reads Claude Code hook JSON on stdin
|
|
151
176
|
nodii-dev hook print-settings # prints managed-settings JSON; writes nothing
|
|
@@ -320,6 +345,7 @@ exits 0 only when every check is `OK`. `--json` returns the same checks as
|
|
|
320
345
|
| `machine` | The machine this agent is assigned to and its coordinator. No machine means `lane start` would fail with `MACHINE_REQUIRED`. |
|
|
321
346
|
| `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`. |
|
|
322
347
|
| `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. |
|
|
348
|
+
| `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`. |
|
|
323
349
|
|
|
324
350
|
Doctor may refresh the access token, as any command does. The permission table
|
|
325
351
|
is kept by hand from Dev's route policy until Dev's OpenAPI names each
|
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 { figmaFileKey, 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,6 +70,9 @@ 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
|
|
73
|
+
figma withdraw CHANGE_SET # holder takes back a submit: in_review -> editing
|
|
74
|
+
figma file add FILE_KEY --name TEXT --kind design-system|surfaces|prototype [--module M]
|
|
75
|
+
# register a Figma file in Dev so it can be locked
|
|
71
76
|
hook claude-figma-pre|claude-figma-post|print-settings
|
|
72
77
|
setup [--yes|--check] # dry-run by default
|
|
73
78
|
harness install|update [--include-drafts[=false]] [--adopt PATH,...] [--dry-run]
|
|
@@ -268,6 +273,57 @@ export function transitionBody(f) {
|
|
|
268
273
|
return { to, ...(note ? { note } : {}) };
|
|
269
274
|
}
|
|
270
275
|
|
|
276
|
+
// Dev's refusals of withdrawDesignChangeSet, said in terms of what to do next.
|
|
277
|
+
const WITHDRAW_REFUSALS = {
|
|
278
|
+
CHANGE_SET_NOT_FOUND: (id) => `No change set ${id} in Dev.`,
|
|
279
|
+
CHANGE_SET_NOT_IN_REVIEW: (id) => `${id} is not in review; only a submitted (in_review) change set can be withdrawn.`,
|
|
280
|
+
WITHDRAW_NOT_ALLOWED: (id) => `You don't hold ${id}; only its holder (or an operator) can withdraw it.`,
|
|
281
|
+
CHANGE_SET_HAS_DECISIONS: (id) => `${id} already has a decided item, so it can't be withdrawn; ask the reviewer to request changes instead.`,
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
export async function figmaWithdraw(id, { request = devRequest } = {}) {
|
|
285
|
+
if (!id) throw new CliError("USAGE", "figma withdraw CHANGE_SET", 2);
|
|
286
|
+
try {
|
|
287
|
+
return await request("POST", `/api/v1/design/change-sets/${encode(id)}/withdraw`, {});
|
|
288
|
+
} catch (error) {
|
|
289
|
+
const say = WITHDRAW_REFUSALS[error?.code];
|
|
290
|
+
if (!say) throw error;
|
|
291
|
+
throw new CliError(error.code, say(id), error.exitCode ?? 1, error.details);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Dev's refusals of registerDesignFile, said in terms of what to do next.
|
|
296
|
+
const REGISTER_REFUSALS = {
|
|
297
|
+
DESIGN_FILE_NAME_MISMATCH: (key, details, message) =>
|
|
298
|
+
details?.figmaName ? `Figma names ${key} "${details.figmaName}"; run it again with --name "${details.figmaName}".` : message,
|
|
299
|
+
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.`,
|
|
300
|
+
FIGMA_FILE_NOT_READABLE: (key) => `Dev's Figma account can't read ${key}; share the file with that account.`,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
export async function figmaFileAdd(value, flags, { request = devRequest } = {}) {
|
|
304
|
+
if (!value) throw new CliError("USAGE", "figma file add FILE_KEY --name TEXT --kind KIND [--module M]", 2);
|
|
305
|
+
const key = figmaFileKey(value);
|
|
306
|
+
if (flags.module === true) throw new CliError("USAGE", "--module needs a value", 2);
|
|
307
|
+
const body = { key, name: requireFlag(flags, "name"), kind: requireFlag(flags, "kind"), ...(flags.module ? { module: flags.module } : {}) };
|
|
308
|
+
try {
|
|
309
|
+
return await request("POST", "/api/v1/design/files", body);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
const say = REGISTER_REFUSALS[error?.code];
|
|
312
|
+
if (!say) throw error;
|
|
313
|
+
throw new CliError(error.code, say(key, error.details, error.message), error.exitCode ?? 1, error.details);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export async function figmaLock(value, title, { request = devRequest } = {}) {
|
|
318
|
+
const key = figmaFileKey(value);
|
|
319
|
+
try {
|
|
320
|
+
return await request("POST", `/api/v1/design/files/${encode(key)}/lock`, { changeSetTitle: title });
|
|
321
|
+
} catch (error) {
|
|
322
|
+
if (error?.code !== "DESIGN_FILE_NOT_FOUND") throw error;
|
|
323
|
+
throw new CliError(error.code, notRegisteredHint(key), error.exitCode ?? 1, error.details);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
271
327
|
export async function main(argv = process.argv.slice(2)) {
|
|
272
328
|
if (argv.length === 1 && ["--version", "-v"].includes(argv[0]))
|
|
273
329
|
return console.log(VERSION);
|
|
@@ -318,7 +374,8 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
318
374
|
if (command === "setup") return emitCommand(await setupCommand(f));
|
|
319
375
|
if (command === "doctor") {
|
|
320
376
|
if (action) throw new CliError("USAGE", `doctor takes no arguments, got: ${[action, ...rest].join(" ")}`, 2);
|
|
321
|
-
|
|
377
|
+
if (f["figma-file"] === true) throw new CliError("USAGE", "--figma-file needs a file key or figma.com link", 2);
|
|
378
|
+
const result = await doctorCommand(f["figma-file"] ? { figmaFile: f["figma-file"] } : {});
|
|
322
379
|
emit(result.payload, json, result.human);
|
|
323
380
|
if (result.exitCode) process.exitCode = result.exitCode;
|
|
324
381
|
return;
|
|
@@ -524,14 +581,12 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
524
581
|
}
|
|
525
582
|
if (command === "figma") {
|
|
526
583
|
if (action === "lock")
|
|
527
|
-
return emit(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
json,
|
|
534
|
-
);
|
|
584
|
+
return emit(await figmaLock(rest[0], requireFlag(f, "title")), json);
|
|
585
|
+
if (action === "file") {
|
|
586
|
+
if (rest[0] !== "add") throw new CliError("USAGE", "figma file add FILE_KEY --name TEXT --kind KIND [--module M]", 2);
|
|
587
|
+
return emit(await figmaFileAdd(rest[1], f), json, (p) =>
|
|
588
|
+
`${p.data.fileKey} is registered in Dev: ${p.data.name} (${p.data.kind}${p.data.module ? `, ${p.data.module}` : ""}).`);
|
|
589
|
+
}
|
|
535
590
|
if (action === "check") {
|
|
536
591
|
const c = await readConfig();
|
|
537
592
|
const result = await devRequest(
|
|
@@ -574,6 +629,8 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
574
629
|
json,
|
|
575
630
|
);
|
|
576
631
|
}
|
|
632
|
+
if (action === "withdraw")
|
|
633
|
+
return emit(await figmaWithdraw(rest[0]), json, `Withdrew ${rest[0]}; it is back in editing.`);
|
|
577
634
|
if (action === "release")
|
|
578
635
|
return emit(
|
|
579
636
|
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.8";
|
|
8
8
|
export const configPath = () =>
|
|
9
9
|
process.env.NODII_DEV_CONFIG_PATH ??
|
|
10
10
|
join(homedir(), ".config/nodii-dev/config.json");
|