@nodii/dev 0.4.1 → 0.6.1
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 +117 -29
- package/dist/api.js +20 -11
- package/dist/cli.js +607 -0
- package/dist/core.js +80 -210
- package/dist/devops-openapi.json +1 -0
- package/dist/docs.js +204 -0
- package/dist/harness.js +343 -0
- package/dist/hooks.js +4 -4
- package/dist/lanes.js +7 -7
- package/dist/nodii-dev.js +2 -629
- package/dist/oauth.js +1 -1
- package/dist/setup.js +7 -7
- package/dist/upload.js +291 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -13,35 +13,43 @@ nodii-dev login # opens the approval page in your browser
|
|
|
13
13
|
nodii-dev login --no-browser # prints the link and code instead
|
|
14
14
|
nodii-dev login --scope devops.issues.read,devops.issues.write # narrower grant
|
|
15
15
|
nodii-dev agent register --name my-agent
|
|
16
|
-
|
|
17
|
-
# Temporary compatibility path:
|
|
18
|
-
printf '%s' "$PLANNING_HUB_HMAC_SECRET" | nodii-dev login --person PERSON_ID --secret-stdin
|
|
19
|
-
nodii-dev login --hmac --person PERSON_ID --from-aws
|
|
20
16
|
```
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
(`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
`nodii-dev` talks only to Dev, through the platform edge
|
|
19
|
+
(`https://platform.nucleus-cloud.in/devops/*`), signed in as the platform
|
|
20
|
+
tenant's nodii-dev OAuth app (D1368). There is no other host and no other way
|
|
21
|
+
to sign in. `NODII_DEV_OAUTH_CLIENT_ID` or `--client-id` overrides the built-in
|
|
22
|
+
public client id. With no `--scope`, auth grants the app's full ceiling: every
|
|
23
|
+
live `devops.*` key except `devops.releases.promote`, which is never granted.
|
|
24
|
+
Login uses the RFC 8628 device flow and opens the verification page on an
|
|
25
|
+
interactive terminal unless `--no-browser` is passed. Refresh tokens are
|
|
26
|
+
stored only in macOS Keychain or Linux Secret Service (`secret-tool`); the CLI
|
|
27
|
+
refuses plaintext fallback. Access tokens stay in memory. Every API call goes
|
|
28
|
+
to the edge's `/devops` prefix with the OAuth bearer and the registered
|
|
29
|
+
`x-agent-id`. `logout` revokes the refresh chain before erasing local
|
|
32
30
|
credentials. `--auth-url`, `--edge-url`, and `--tenant-hint` select another real
|
|
33
31
|
deployment.
|
|
34
32
|
|
|
33
|
+
Upgrading from 0.4.x: the shared-secret login (`login --hmac`, `--person`,
|
|
34
|
+
`--secret-stdin`, `--from-aws`, `--hub-url`) was removed in 0.5.0, and `login`
|
|
35
|
+
refuses those flags. The first command you run after upgrading deletes the old
|
|
36
|
+
config and its stored secret (Keychain item or file) without printing it, then
|
|
37
|
+
asks you to run `nodii-dev login`.
|
|
38
|
+
|
|
39
|
+
`nodii-dev` is only the Dev control CLI. The local-stack CLI is `./nodii-stack`,
|
|
40
|
+
run from the `nodii-local-stack` checkout (renamed per operator ruling G3-6,
|
|
41
|
+
with no alias under the old name). Typing one of its verbs here, such as
|
|
42
|
+
`nodii-dev doctor`, fails and names the `./nodii-stack` command instead.
|
|
43
|
+
|
|
35
44
|
Every command accepts `--json`; without it, output is formatted for humans.
|
|
36
|
-
|
|
45
|
+
Dev failures print Dev's error code to stderr and exit non-zero.
|
|
37
46
|
|
|
38
47
|
## Commands
|
|
39
48
|
|
|
40
49
|
```text
|
|
41
|
-
nodii-dev login [--no-browser]
|
|
42
|
-
nodii-dev login --hmac --person ID (--secret-stdin | --from-aws)
|
|
50
|
+
nodii-dev login [--no-browser] [--scope KEYS]
|
|
43
51
|
nodii-dev logout
|
|
44
|
-
nodii-dev whoami
|
|
52
|
+
nodii-dev whoami # OAuth identity plus the registered agent
|
|
45
53
|
nodii-dev config show
|
|
46
54
|
|
|
47
55
|
nodii-dev api list [--tag TAG] [--json]
|
|
@@ -134,17 +142,92 @@ nodii-dev people refresh-names
|
|
|
134
142
|
nodii-dev setup # preview files that would change
|
|
135
143
|
nodii-dev setup --yes # merge and write the harness
|
|
136
144
|
nodii-dev setup --check # exit non-zero when it has drifted
|
|
145
|
+
|
|
146
|
+
nodii-dev rulebook list [--section rulebook|services] [--kind KIND] [--q TEXT]
|
|
147
|
+
nodii-dev rulebook show CODE [--version V] # the current text, from Dev
|
|
148
|
+
nodii-dev rulebook diff CODE [--from V] [--to V]
|
|
149
|
+
|
|
150
|
+
nodii-dev docs check PATH... # local M-05 checks only
|
|
151
|
+
nodii-dev docs validate PATH... --class CLASS # Dev's dry run of the upload
|
|
152
|
+
nodii-dev docs upload PATH... --class ruling|conformance|editorial
|
|
153
|
+
[--base CODE=VERSION ...] [--decision DECISION.json]
|
|
154
|
+
[--conformance-ref PR|REPO@SHA] [--meaning-unchanged REASON]
|
|
155
|
+
[--wait [--wait-minutes N]]
|
|
156
|
+
nodii-dev docs ratify --domain KEY [--domain KEY ...] --decision DECISION.json [--wait]
|
|
157
|
+
nodii-dev docs parked [CODE] [--status pending|acknowledged]
|
|
158
|
+
|
|
159
|
+
nodii-dev harness install [--include-drafts] [--adopt PATH,...] [--dry-run]
|
|
160
|
+
nodii-dev harness update [--include-drafts] [--adopt PATH,...] [--dry-run]
|
|
161
|
+
nodii-dev harness update --check # exit 1 when Dev would write anything different
|
|
137
162
|
```
|
|
138
163
|
|
|
164
|
+
## AD documents
|
|
165
|
+
|
|
166
|
+
AD documents (the rulebook and per-service feature docs) live in Dev, one
|
|
167
|
+
current text per document with its version history (M-05). `docs upload`
|
|
168
|
+
takes files or folders (folders are searched for `.md` files, skipping `_`
|
|
169
|
+
and `.` entries) and checks every document locally before sending anything:
|
|
170
|
+
front matter, the section order for its kind, unique clause ids that use the
|
|
171
|
+
document's code, no bare decision ids (`D123`; cite `pre:D123`), and the
|
|
172
|
+
parked (`Undecided`) items, which it lists. All problems are printed with
|
|
173
|
+
Dev's error codes, and nothing is sent until there are none. Dev then runs the
|
|
174
|
+
same checks, plus the ones that need its data, in one transaction.
|
|
175
|
+
|
|
176
|
+
- `--class` is required on every write (M05-8). A `ruling` carries its
|
|
177
|
+
decision (`--decision`, with `amends`), and the decision locks with the new
|
|
178
|
+
versions or nothing is written. An `editorial` write that changes a Rules
|
|
179
|
+
clause is refused unless `--meaning-unchanged REASON` is given (M05-10).
|
|
180
|
+
- A new document is based on nothing. For a document Dev already has, pass
|
|
181
|
+
the version you started from with `--base CODE=VERSION` (M05-11). The CLI
|
|
182
|
+
never fills it in from Dev, so a stale edit is refused instead of
|
|
183
|
+
overwriting newer text.
|
|
184
|
+
- **Parked items:** when a document has parked items the operator has not
|
|
185
|
+
acknowledged, Dev refuses the upload and records the list. The CLI prints
|
|
186
|
+
it and exits `4`. The operator acknowledges it in Dev (this CLI is an OAuth
|
|
187
|
+
app and cannot). Re-run the upload then, or pass `--wait` to poll and retry
|
|
188
|
+
once it is acknowledged.
|
|
189
|
+
- `docs ratify` is the bulk ratification mode: one decision locks v1.0 of
|
|
190
|
+
every draft document in the named domains, which then become AD (M05-2).
|
|
191
|
+
Upload the drafts first (`--class conformance`), then ratify domain by
|
|
192
|
+
domain. The decision file holds `title`, `context`, `options`, `ruling`,
|
|
193
|
+
`consequences` and `provenance`; Dev mints the `DEC-nnnn` id and generates
|
|
194
|
+
the amends. A domain that is already AD can be named again to ratify drafts
|
|
195
|
+
added to it since (a new feature doc in a ratified service).
|
|
196
|
+
- `docs validate` also prints Dev's warnings for each document (they never
|
|
197
|
+
block) and any problems with the decision's amends.
|
|
198
|
+
|
|
199
|
+
Like every other command, these reach Dev only through the platform edge
|
|
200
|
+
(`/devops/api/v1/documents`, `/domains`, `/harness`, …) with the OAuth login.
|
|
201
|
+
|
|
202
|
+
## Agent harness
|
|
203
|
+
|
|
204
|
+
`harness install` writes the repository's agent harness as Dev generates it
|
|
205
|
+
from the ratified methodology: the `CLAUDE.md` and `AGENTS.md` pointer
|
|
206
|
+
blocks, one pointer skill per methodology document, the Claude Code hooks
|
|
207
|
+
merged into `.claude/settings.json`, and Dev's `.nodii/harness.json`. Every
|
|
208
|
+
generated file carries the methodology version it came from. Nothing about
|
|
209
|
+
the rules is authored locally. Run it in the service's own repository: it
|
|
210
|
+
installs one service at a time, and there is no fleet mode. `--include-drafts`
|
|
211
|
+
uses draft methodology while none is ratified.
|
|
212
|
+
|
|
213
|
+
The CLI records what it wrote in `.nodii/harness-state.json` and never touches
|
|
214
|
+
anything else. An existing file it did not write is refused, unless the
|
|
215
|
+
operator names it with `--adopt PATH` (a `CLAUDE.md` then keeps its text and
|
|
216
|
+
gains the managed block; `settings.json` keeps its other keys and hooks).
|
|
217
|
+
`harness update` re-syncs: it prints the methodology version change, which
|
|
218
|
+
source documents moved, and each file created, updated or removed. It
|
|
219
|
+
removes only files, blocks and hook entries it wrote, and it refuses (writing
|
|
220
|
+
nothing) when one of its files was edited by hand.
|
|
221
|
+
|
|
139
222
|
## Build lanes and repository setup
|
|
140
223
|
|
|
141
224
|
`lane start` creates and starts a lane. It infers the repository, branch and
|
|
142
225
|
worktree from git unless overridden, and resolves `--issue` keys to the UUIDs
|
|
143
|
-
required by
|
|
226
|
+
required by Dev. Lane keys are passed directly to every lane and Built
|
|
144
227
|
acknowledgement route. `next` reads the lane's generated
|
|
145
228
|
API steps and prints the exact next `lane step` command. Server refusals,
|
|
146
229
|
including operator-only actions, workflow blocks, lane limits and Built items
|
|
147
|
-
that are not on dev, retain
|
|
230
|
+
that are not on dev, retain Dev's error code/message and exit non-zero.
|
|
148
231
|
|
|
149
232
|
`setup` installs the Claude Code workflow harness in the current repository.
|
|
150
233
|
It writes `.claude/skills/nodii-build-workflow/SKILL.md`, merges SessionStart,
|
|
@@ -152,15 +235,16 @@ Stop and Bash PostToolUse hooks into `.claude/settings.json`, and maintains one
|
|
|
152
235
|
marked section in an existing `CLAUDE.md` or `AGENTS.md` (creating `CLAUDE.md`
|
|
153
236
|
when neither exists). Existing settings and hooks are preserved. The default
|
|
154
237
|
is a read-only preview; `--yes` applies, and `--check` is suitable for drift
|
|
155
|
-
checks. Setup also checks
|
|
156
|
-
exposing credential
|
|
238
|
+
checks. Setup also checks the OAuth login (a token refresh, then the registered
|
|
239
|
+
agent) and prints `nodii-dev login` guidance without exposing credential
|
|
240
|
+
details.
|
|
157
241
|
|
|
158
|
-
Heartbeat notes are optional and limited by
|
|
242
|
+
Heartbeat notes are optional and limited by Dev to 500 characters.
|
|
159
243
|
Prioritize and deprioritize require a 1–500 character reason, which the CLI
|
|
160
|
-
sends to
|
|
244
|
+
sends to Dev. `lane review` records the review gate.
|
|
161
245
|
|
|
162
246
|
The CLI does not duplicate authorization policy. It sends requests and prints
|
|
163
|
-
|
|
247
|
+
Dev's refusal unchanged. Stop, Built acknowledgement, and machine
|
|
164
248
|
create/update/coordinator changes require a staff person login. Machine agent
|
|
165
249
|
assignment is for coordinators; lane-limit and repository-grant changes are for
|
|
166
250
|
the target agent's coordinator or staff. Agent registration does not accept
|
|
@@ -177,19 +261,23 @@ nodii-dev requests resolve UUID --commit-sha abc1234 --resolution-md "shipped"
|
|
|
177
261
|
nodii-dev open-questions answer UUID --decision-id D1420
|
|
178
262
|
```
|
|
179
263
|
|
|
180
|
-
The
|
|
264
|
+
The CLI bundles Dev's OpenAPI document as the edge routes it (the edge does not
|
|
265
|
+
serve Dev's own document), so `api list` works offline and lists only
|
|
266
|
+
operations the edge exposes. The first-class resource families cover every tag: services,
|
|
181
267
|
feature docs, contracts (gRPC, REST, outbox, sagas, tables), libraries,
|
|
182
268
|
workers, projects, slices, SQL lookups, issues, backlogs, builds, changes,
|
|
183
|
-
|
|
269
|
+
runtime, people, agents, inbox/gates, design, runbooks,
|
|
184
270
|
doctrine and exceptions, changelog, health verdicts, approval kinds,
|
|
185
271
|
notification registry, skills, questions, decisions, drift, requests,
|
|
186
272
|
pipelines, runners, routing, usage, audit, reconciliation, cron, composite
|
|
187
|
-
surfaces, service edges, lanes, swaps, ideas,
|
|
273
|
+
surfaces, service edges, lanes, swaps, ideas, terminology, and the AD era: `rulebook`
|
|
274
|
+
(documents, plus `rulebook versions CODE`), `ad-decisions`, `domains`, `standardizations`,
|
|
275
|
+
`archive` (`archive resolve --ref pre:D1366`), and `harness methodology`. `api list` is the authoritative discovery view;
|
|
188
276
|
`api OPERATION_ID` makes every operation callable even without an alias.
|
|
189
277
|
|
|
190
278
|
`figma check` exits `0` when allowed and `3` when denied. The pre-hook permits
|
|
191
279
|
non-Figma tools and allowlisted Figma reads, but defaults to denying every
|
|
192
|
-
Figma write if the file key is absent,
|
|
280
|
+
Figma write if the file key is absent, Dev cannot be reached, or the lock
|
|
193
281
|
is denied. It exits `2`, which makes Claude Code block the call. The post-hook
|
|
194
282
|
best-effort logs the write and never blocks. Per D1433, Codex remains read-only
|
|
195
283
|
for Figma; this package does not write to Figma itself.
|
package/dist/api.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { stdin } from "node:process";
|
|
3
|
-
import { CliError,
|
|
3
|
+
import { CliError, devRawRequest, encode } from "./core.js";
|
|
4
4
|
|
|
5
5
|
const methods = new Set(["get", "post", "put", "patch", "delete", "head", "options"]);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
// The Dev API as the platform edge routes it, bundled with the package (the
|
|
7
|
+
// edge does not serve Dev's own document). Refresh: `npm run openapi:snapshot`.
|
|
8
|
+
let bundled;
|
|
9
|
+
export async function loadOpenApi() {
|
|
10
|
+
bundled ??= JSON.parse(await readFile(new URL("./devops-openapi.json", import.meta.url), "utf8"));
|
|
11
|
+
return bundled;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export function operationsFrom(spec) {
|
|
@@ -86,20 +87,22 @@ export function flagsToOperation(entry, positional, flags) {
|
|
|
86
87
|
|
|
87
88
|
export async function callOperation(entry, params, body) {
|
|
88
89
|
const request = buildOperationRequest(entry, params, body);
|
|
89
|
-
return
|
|
90
|
+
return devRawRequest(request.method, request.path, body === undefined ? undefined : JSON.stringify(body));
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
export const GROUPS = {
|
|
93
94
|
services: "Services", "feature-docs": "FeatureDocs", contracts: ["GrpcInterfaces", "RestInterfaces", "Outbox", "OutboxTopics", "Sagas", "Tables"],
|
|
94
95
|
sagas: "Sagas", "outbox-topics": ["Outbox", "OutboxTopics"], tables: "Tables", libraries: "Libraries", workers: "Workers",
|
|
95
|
-
projects: "Projects", issues: "Issues", backlog: "Backlogs", backlogs: "Backlogs", builds: "Delivery", changes: "Delivery",
|
|
96
|
+
projects: "Projects", issues: "Issues", backlog: "Backlogs", backlogs: "Backlogs", builds: "Delivery", changes: "Delivery",
|
|
96
97
|
runtime: "Runtime", people: "People", agents: "Agents", inbox: "Inbox", gate: "Inbox", design: "Design", runbooks: "Runbooks",
|
|
97
|
-
doctrine: ["Doctrine", "DoctrineExceptions"],
|
|
98
|
+
doctrine: ["Doctrine", "DoctrineExceptions"], changelog: "Changelog", "health-verdicts": "HealthVerdicts",
|
|
98
99
|
"approval-kinds": "ApprovalKinds", "notification-registry": "Notification registry", skills: "Skills", "open-questions": "OpenQuestions",
|
|
99
100
|
decisions: "Decisions", drift: "Drift", requests: "Requests", pipelines: "Pipelines", slices: "Slices", "sql-lookups": "SqlLookups",
|
|
100
101
|
runners: "Runners", routing: "Routing", usage: "Usage", audit: "AuditLog", reconciliation: "Reconciliation", cron: "Cron", health: "Health",
|
|
101
102
|
composite: "Composite", "service-edges": "ServiceEdges", lanes: "Lanes",
|
|
102
103
|
swaps: "Swaps", ideas: "Ideas", terminology: "Terminology",
|
|
104
|
+
rulebook: "ad-documents", "ad-decisions": "ad-decisions", domains: "ad-domains", standardizations: "standardizations",
|
|
105
|
+
archive: "archive", harness: "harness",
|
|
103
106
|
};
|
|
104
107
|
|
|
105
108
|
export const ALIASES = {
|
|
@@ -123,12 +126,12 @@ export const ALIASES = {
|
|
|
123
126
|
"projects:list": "listServiceProjects", "projects:show": "getProject", "projects:create": "createProject", "projects:update": "updateProject",
|
|
124
127
|
"builds:list": "listBuilds", "builds:show": "getBuild", "builds:report": "reportBuild",
|
|
125
128
|
"changes:list": "listChanges", "changes:show": "getChange", "changes:mark": "markChange",
|
|
126
|
-
"
|
|
129
|
+
"runtime:list": "listRuntimeInventory", "runtime:show": "getServiceRuntime",
|
|
127
130
|
"people:list": "listPeople", "people:show": "getPerson", "agents:list": "listAgents", "agents:show": "getAgent",
|
|
128
131
|
"gate:fleet": "getFleetGate", "gate:service": "getServiceGate", "gate:dry-run": "getGateDryRun",
|
|
129
132
|
"runbooks:list": "listRunbooks", "runbooks:show": "getRunbook", "runbooks:create": "registerRunbook", "runbooks:update": "updateRunbook",
|
|
130
133
|
"doctrine:list": "listDoctrine", "doctrine:show": "getDoctrine", "doctrine:create": "createDoctrine", "doctrine:revise": "reviseDoctrine",
|
|
131
|
-
"
|
|
134
|
+
"changelog:list": "listChangelog", "changelog:append": "appendChangelog",
|
|
132
135
|
"health-verdicts:list": "listHealthVerdicts", "health-verdicts:post": "postHealthVerdict",
|
|
133
136
|
"approval-kinds:list": "listApprovalKinds", "approval-kinds:show": "getApprovalKind", "approval-kinds:create": "createApprovalKind",
|
|
134
137
|
"notification-registry:list": "listNotificationEvents", "notification-registry:show": "getNotificationEvent", "notification-registry:propose": "proposeNotificationEvent",
|
|
@@ -142,6 +145,12 @@ export const ALIASES = {
|
|
|
142
145
|
"service-edges:list": "listServiceEdges", "service-edges:show": "getServiceEdgesForService",
|
|
143
146
|
"swaps:list": "listSwaps", "swaps:show": "getSwap", "swaps:create": "createSwap", "swaps:close": "closeSwap",
|
|
144
147
|
"ideas:list": "listIdeas", "ideas:show": "getIdea", "ideas:create": "createIdea", "ideas:status": "updateIdeaStatus",
|
|
148
|
+
"rulebook:versions": "listAdDocumentVersions", "rulebook:parked": "getAdDocumentParked",
|
|
149
|
+
"ad-decisions:list": "listAdDecisions", "ad-decisions:show": "getAdDecision", "ad-decisions:lock": "lockAndAmendAdDecision",
|
|
150
|
+
"domains:list": "listAdDomains", "domains:show": "getAdDomain",
|
|
151
|
+
"standardizations:list": "listStandardizations", "standardizations:show": "getStandardization", "standardizations:update": "updateStandardization",
|
|
152
|
+
"archive:search": "searchPreDevArchive", "archive:resolve": "resolvePreCitation",
|
|
153
|
+
"harness:show": "generateHarness", "harness:methodology": "getHarnessMethodologyVersion",
|
|
145
154
|
"terminology:list": "listTerminology", "terminology:show": "getTerminologyTerm", "terminology:create": "createTerminologyTerm", "terminology:update": "updateTerminologyTerm",
|
|
146
155
|
};
|
|
147
156
|
|