@nodii/dev 0.6.27 → 0.6.29

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
@@ -97,6 +97,8 @@ nodii-dev agent heartbeat
97
97
  nodii-dev agents spawn SERVICE [--repo-root DIR]
98
98
  nodii-dev agents cowork-tick [--json]
99
99
  nodii-dev agents cowork-tick --plist [--interval SECONDS]
100
+ nodii-dev watchdog install [--interval SECONDS]
101
+ nodii-dev watchdog sweep
100
102
 
101
103
  nodii-dev issues list [--service ID] [--project KEY] [--status STATUS]
102
104
  [--kind KIND] [--priority PRIORITY] [--claimed true|false]
@@ -135,6 +137,8 @@ nodii-dev libraries register-version LIBRARY_ID --version VERSION
135
137
  nodii-dev state diff
136
138
  nodii-dev heartbeat audit [SERVICE]
137
139
 
140
+ nodii-dev run [--kind build|test_run|subagent|deploy] [--name TEXT] -- COMMAND [ARGS...]
141
+
138
142
  nodii-dev design entries [--kind KIND] [--group GROUP] [--q TEXT]
139
143
  nodii-dev design entry KEY
140
144
  nodii-dev design guide PAGE_TYPE
@@ -308,7 +312,9 @@ nodii-dev lane step KEY --side backend|frontend --start|--done|--block STEP [--r
308
312
  # --reason is kept as a lane note; on a step already blocked,
309
313
  # --block --reason records the new reason (Dev issue 125 moves it onto the step)
310
314
  nodii-dev lane evidence KEY --pr|--commit|--figma|--deploy|--dev-check REF
315
+ nodii-dev lane subagent-quota KEY N
311
316
  nodii-dev lane heartbeat KEY [--note TEXT]
317
+ nodii-dev lane resume KEY
312
318
  nodii-dev lane review KEY --file REVIEW.json
313
319
  nodii-dev lane reviews KEY
314
320
  nodii-dev lane land KEY
@@ -345,7 +351,7 @@ nodii-dev rulebook diff CODE [--from V] [--to V]
345
351
  nodii-dev docs check PATH... # local M-05 checks only
346
352
  nodii-dev docs validate PATH... --class CLASS # Dev's dry run of the upload
347
353
  nodii-dev docs upload PATH... --class ruling|conformance|editorial
348
- [--base CODE=VERSION ...] [--decision DECISION.json]
354
+ [--base CODE=VERSION ...] [--decision DECISION.json] [--pending]
349
355
  [--conformance-ref PR|REPO@SHA] [--meaning-unchanged REASON]
350
356
  [--wait [--wait-minutes N]]
351
357
  nodii-dev docs ratify --domain KEY [--domain KEY ...] --decision DECISION.json [--wait]
@@ -355,8 +361,22 @@ nodii-dev harness install [--include-drafts] [--adopt PATH,...] [--dry-run] [--s
355
361
  nodii-dev harness update [--include-drafts] [--adopt PATH,...] [--dry-run] [--system]
356
362
  nodii-dev harness check [--json] # 0 current, 1 differs from Dev, 2 no harness
357
363
  nodii-dev harness update --check # the same check
364
+ nodii-dev watchdog install [--interval SECONDS] # install/update com.nodii.watchdog in ~/Library/LaunchAgents
365
+ nodii-dev watchdog sweep # launchd entrypoint; normally not run by hand
358
366
  ```
359
367
 
368
+ The per-Mac watchdog runs outside agent sessions. Run `watchdog install` once
369
+ with the machine coordinator's config; it refuses a lane or unassigned agent.
370
+ Every sweep reports three host facts to Dev: watched run processes that exited
371
+ without ending their run, `/tmp/cc-socks/<pid>.sock` sockets whose process is
372
+ gone, and watched worktrees whose HEAD has commits absent from its configured
373
+ remote branch. Each observation is posted to the watched run by the machine
374
+ coordinator; `process_dead` transitions it to explicit `orphan` immediately.
375
+ Run launchers and wrappers persist one owner-only record per process under
376
+ `~/.config/nodii-dev/watchdog/runs/`; the plist itself contains only absolute
377
+ command/config paths, its schedule, and log paths, while OAuth credentials
378
+ remain in the machine keychain.
379
+
360
380
  `harness install` and `harness update` merge the safety hooks into both
361
381
  `.claude/settings.json` and `.codex/hooks.json`; every installed hook invokes
362
382
  only `nodii-dev`. The
@@ -542,9 +562,12 @@ Dev's error codes, and nothing is sent until there are none. Dev then runs the
542
562
  same checks, plus the ones that need its data, in one transaction.
543
563
 
544
564
  - `--class` is required on every write (M05-8). A `ruling` carries its
545
- decision (`--decision`, with `amends`), and the decision locks with the new
546
- versions or nothing is written. An `editorial` write that changes a Rules
547
- clause is refused unless `--meaning-unchanged REASON` is given (M05-10).
565
+ decision (`--decision`, with `amends`). Agents must add `--pending`: Dev
566
+ stores the ruling versions under a pending decision without activating
567
+ them, and a signed-in staff person locks it later. Omitting `--pending`
568
+ requests the staff-only immediate lock-and-amend action. An `editorial`
569
+ write that changes a Rules clause is refused unless
570
+ `--meaning-unchanged REASON` is given (M05-10).
548
571
  - A new document is based on nothing. For a document Dev already has, pass
549
572
  the version you started from with `--base CODE=VERSION` (M05-11). The CLI
550
573
  never fills it in from Dev, so a stale edit is refused instead of
@@ -686,8 +709,61 @@ Doctor may refresh the access token, as any command does. The permission table
686
709
  is kept by hand from Dev's route policy until Dev's OpenAPI names each
687
710
  operation's permission (requested in Dev).
688
711
 
712
+ ## Watched commands and Results
713
+
714
+ The harness launcher supplies `NODII_DEV_RUN_ID`, the UUID of the current lane,
715
+ coordinator, or subagent run. Use `nodii-dev run -- COMMAND ARGS...` for work
716
+ whose completion must survive the calling agent. The command registers a child
717
+ run with that UUID as its waiter, starts an out-of-process supervisor, and
718
+ preserves the command's exit code. `--kind` defaults to `build`; `--name`
719
+ overrides the executable name shown in Dev without storing command arguments.
720
+
721
+ The supervisor heartbeats once a minute while the command runs. At completion
722
+ it records the executable, exit code, signal when applicable, and the final 8
723
+ KiB of combined stdout/stderr. Credential-shaped values, bearer tokens, private
724
+ keys, and credentials embedded in URLs are redacted before the tail leaves the
725
+ machine. The command is executed directly, never through a shell. Because the
726
+ supervisor is detached from the launching process, the terminal record still
727
+ lands when that process is killed.
728
+
729
+ Every subsequent `nodii-dev` call in the waiter context prints unacknowledged
730
+ Results before doing its requested work. A Result is acknowledged only after
731
+ it renders successfully. Hook calls deliberately leave Results pending because
732
+ their output may be swallowed; the next visible call prints and acknowledges
733
+ them. Unacknowledged amendments will join this preflight when the amendment API
734
+ from AGENT-HARNESS-14 is available.
735
+
689
736
  ## Build lanes and repository setup
690
737
 
738
+ `coordinator start --machine NAME` registers the machine's one watched
739
+ coordinator run and shows its running lanes, orphaned runs and unclaimed
740
+ results. A live second coordinator is refused; a coordinator whose heartbeat
741
+ watchdog has recorded it orphaned is recorded as the predecessor of the
742
+ takeover.
743
+
744
+ `lane launch KEY` replaces the manual worktree/start/process sequence. It
745
+ requires the issue (whose title supplies both lane title and objective), done
746
+ check, build kind and side, runtime profile and model, subagent quota, and
747
+ repeated `--repo NAME=/SOURCE` plus
748
+ `--branch NAME=BRANCH` pairs. The Hub preflight checks the coordinator waiter,
749
+ target agent and machine, fresh account-capacity telemetry, repository grants,
750
+ lane limit, open issues and (when `--figma` is present) the authenticated Figma
751
+ account. Only after that passes does the CLI create one worktree per repository,
752
+ atomically register the lane and watched run, and launch the runtime with the
753
+ single-line brief `You are lane KEY. Run nodii-dev lane gather.`. Ordinary
754
+ notes use `--notes`; a scope-narrowing note uses `--narrowing-note` and must
755
+ also name the remainder's destination with `--narrowing-remainder`.
756
+ The launched process uses the already-provisioned lowercase identity (for
757
+ example `~/.config/nodii-dev/agents/lane-ah-12.json`), never the coordinator's
758
+ Dev identity.
759
+
760
+ Objective, scope and rule changes are durable `lane amend` records, never chat
761
+ messages. Every CLI call from a launched worktree checks the current watched
762
+ run's acknowledgement version. A pending change is printed and blocks the
763
+ call until `lane gather --delta` serves the current rules and acknowledges the
764
+ newest displayed version. `NODII_DEV_RUN_ID` makes this check per subagent run,
765
+ so one child cannot acknowledge for its siblings.
766
+
691
767
  `lane start` creates and starts a lane. It infers the repository (by short
692
768
  name, as Dev compares it), branch and worktree from git unless overridden, and resolves `--issue` keys to the UUIDs
693
769
  required by Dev. Lane keys are passed directly to every lane and Built
@@ -697,6 +773,23 @@ serves for that step (see Rule delivery). Server refusals,
697
773
  including operator-only actions, workflow blocks, lane limits and Built items
698
774
  that are not on dev, retain Dev's error code/message and exit non-zero.
699
775
 
776
+ The machine coordinator sets a lane's subagent capacity with `lane
777
+ subagent-quota KEY N` (`0` to `100`). Registering a subagent run consumes one
778
+ slot; Dev refuses another registration with `SUBAGENT_QUOTA_REACHED` when the
779
+ lane is full. A `done`, `handed_off`, or `failed` subagent run no longer counts,
780
+ so the watchdog marking a killed process failed frees the slot.
781
+
782
+ `lane resume` asks Dev to reserve a fresh run for an orphaned lane, then launches
783
+ the allowlisted Codex or Claude runtime as a detached headless process in the
784
+ same worktree. Dev keeps the lane's finished steps intact and returns the next
785
+ unfinished step together with its bounded recovery packet. The CLI sends that
786
+ packet over the new process's stdin (never its argv), saves its exact PID and
787
+ append-only log under `~/.config/nodii-dev/runs/<run-id>/`, and reports a local
788
+ spawn failure back to Dev so the reservation is not left running. Human output
789
+ identifies the replacement run, PID, step and last pushed commit without
790
+ echoing the dead run's log tail; `--json` retains the complete server response.
791
+ Dev refuses a third attempt after two identical deaths.
792
+
700
793
  `setup` installs the Claude Code and Codex workflow harnesses in the current repository.
701
794
  It writes `.claude/skills/nodii-build-workflow/SKILL.md`, merges SessionStart,
702
795
  Stop and tool hooks into `.claude/settings.json` and `.codex/hooks.json`, and maintains one
@@ -778,7 +871,8 @@ runtime, people, agents, inbox/gates, design, runbooks,
778
871
  doctrine and exceptions, changelog, health verdicts, approval kinds,
779
872
  notification registry, skills, questions, decisions, drift, requests,
780
873
  pipelines, runners, routing, usage, audit, reconciliation, cron, composite
781
- surfaces, service edges, lanes, swaps, ideas, terminology, and the AD era: `rulebook`
874
+ surfaces, service edges, lanes, swaps, ideas, terminology, watched runs,
875
+ releases, operate surfaces, and the AD era: `rulebook`
782
876
  (documents, plus `rulebook versions CODE`), `ad-decisions`, `domains`, `standardizations`,
783
877
  `archive` (`archive resolve --ref pre:D1366`), and `harness methodology`. `api list` is the authoritative discovery view;
784
878
  `api OPERATION_ID` makes every operation callable even without an alias.
package/dist/api.js CHANGED
@@ -99,10 +99,12 @@ export const GROUPS = {
99
99
  "approval-kinds": "ApprovalKinds", "notification-registry": "Notification registry", skills: "Skills", "open-questions": "OpenQuestions",
100
100
  decisions: "Decisions", drift: "Drift", requests: "Requests", pipelines: "Pipelines", slices: "Slices", "sql-lookups": "SqlLookups",
101
101
  runners: "Runners", routing: "Routing", usage: "Usage", audit: "AuditLog", reconciliation: "Reconciliation", cron: "Cron", health: "Health",
102
- composite: "Composite", "service-edges": "ServiceEdges", lanes: "Lanes",
102
+ composite: "Composite", "service-edges": "ServiceEdges", lanes: "Lanes", runs: "Runs",
103
+ releases: "Releases", operate: "Operate",
103
104
  swaps: "Swaps", ideas: "Ideas", terminology: "Terminology", credentials: "Credentials",
104
105
  rulebook: "ad-documents", "ad-decisions": "ad-decisions", domains: "ad-domains", standardizations: "standardizations",
105
106
  archive: "archive", harness: "harness", utils: "utils",
107
+ runs: "Runs", releases: "Releases", operate: "Operate",
106
108
  // DEC-0020 rule delivery; `rules core|report|cap` are first-class (upload.js).
107
109
  rules: "rulebook",
108
110
  };
@@ -153,6 +155,8 @@ export const ALIASES = {
153
155
  "standardizations:list": "listStandardizations", "standardizations:show": "getStandardization", "standardizations:update": "updateStandardization",
154
156
  "archive:search": "searchPreDevArchive", "archive:resolve": "resolvePreCitation",
155
157
  "harness:show": "generateHarness", "harness:methodology": "getHarnessMethodologyVersion",
158
+ "runs:register": "registerRun", "runs:show": "getRun", "runs:heartbeat": "heartbeatRun", "runs:end": "endRun",
159
+ "runs:results": "listRunResults", "runs:acknowledge": "acknowledgeResult",
156
160
  "terminology:list": "listTerminology", "terminology:show": "getTerminologyTerm", "terminology:create": "createTerminologyTerm", "terminology:update": "updateTerminologyTerm",
157
161
  };
158
162
 
package/dist/cli.js CHANGED
@@ -53,6 +53,7 @@ export { figmaLock, submitMode } from "./figma.js";
53
53
  import { docsCommand, rulebookCommand, rulesCommand } from "./upload.js";
54
54
  import { changeSetCommand, guidelineCommand } from "./guidelines.js";
55
55
  import { designCheck, designCheckText, designRoles, designRolesText } from "./design.js";
56
+ import { watchdogCommand } from "./watchdog.js";
56
57
  import {
57
58
  ALIASES,
58
59
  GROUPS,
@@ -74,6 +75,18 @@ import {
74
75
  nextCommand,
75
76
  peopleCommand,
76
77
  } from "./lanes.js";
78
+ import {
79
+ amendmentGuard,
80
+ amendLaneCommand,
81
+ coordinatorCommand,
82
+ gatherLaneCommand,
83
+ launchLaneCommand,
84
+ } from "./starting.js";
85
+ import {
86
+ launchRunSupervisor,
87
+ showWaitingResults,
88
+ superviseRun,
89
+ } from "./runs.js";
77
90
 
78
91
  const HELP = `nodii-dev ${VERSION}
79
92
 
@@ -127,8 +140,10 @@ Usage: nodii-dev <command> [options] [--json]
127
140
  # --system stages managed hooks and only prints operator-reviewed sudo commands
128
141
  harness check # 0 current, 1 differs from Dev, 2 not installed
129
142
  harness update --check # the same check
143
+ watchdog install [--interval SECONDS] # install/update the per-Mac launchd liveness sweep (default 60s)
144
+ watchdog sweep # launchd entrypoint: report dead runs, stale sockets, unpushed worktrees
130
145
  docs check|validate|upload <path...> --class ruling|conformance|editorial
131
- [--base CODE=VERSION] [--decision FILE] [--conformance-ref REF]
146
+ [--base CODE=VERSION] [--decision FILE] [--pending] [--conformance-ref REF]
132
147
  [--meaning-unchanged REASON] [--wait]
133
148
  docs ratify --domain KEY [--domain KEY ...] --decision FILE [--wait]
134
149
  docs parked [CODE] [--status pending|acknowledged]
@@ -137,11 +152,27 @@ Usage: nodii-dev <command> [options] [--json]
137
152
  rules report [--section S] [--lane KEY] # delivery totals per document; rules served per lane
138
153
  rules cap TOKENS # operator: set the core token cap (default 3000)
139
154
 
155
+ coordinator start --machine NAME # register this machine's one watched coordinator; refuses a live second
156
+ lane launch <key> --done-check TEXT --kind KIND --side SIDE
157
+ --issue KEY --repo NAME=/SOURCE --branch NAME=BRANCH [--repo ... --branch ...]
158
+ --machine NAME --runtime claude|codex --profile PATH --model MODEL --subagents N
159
+ [--base NAME=REF] [--worktree NAME=PATH] [--owned-path NAME=PATH]
160
+ [--figma FILE[=COMPONENT_SET[,SET]]] [--notes TEXT]
161
+ [--narrowing-note TEXT --narrowing-remainder DESTINATION]
162
+ # authoritative preflight, one worktree per repo, watched launch
163
+ # uses the provisioned agents/lane-<key>.json Dev identity
164
+ lane amend <key> --objective|--scope|--rules TEXT --reason TEXT
165
+ lane gather [<key>] [--delta] # infers a launched worktree; Delta required after an amendment
166
+ run [--kind build|test_run|subagent|deploy] [--name TEXT] -- <command> [args...]
167
+ # watched command: registers with NODII_DEV_RUN_ID,
168
+ # heartbeats, and records exit code + redacted log tail
169
+
140
170
  lane start <key> --title TEXT --kind KIND --side SIDE [--repo REPO] [--issue ISSUE]
141
171
  lane step <key> --side SIDE --start|--done|--block <step> [--reason TEXT]
142
172
  # --block --reason on a blocked step records its new reason
143
173
  lane evidence <key> --pr|--commit|--figma|--deploy|--dev-check REF
144
- lane heartbeat|land|verify|prioritize|deprioritize|stop <key>
174
+ lane subagent-quota <key> <n> # coordinator assigns 0-100 subagent slots
175
+ lane heartbeat|resume|land|verify|prioritize|deprioritize|stop <key>
145
176
  lane review <key> --file REVIEW.json # base/head, outcome and clause-cited findings
146
177
  lane reviews <key> # stored review history for the lane
147
178
  lane non-issue <key> --reason TEXT --evidence TEXT --reroute KEY[,KEY]|none
@@ -164,7 +195,8 @@ contracts, sagas, outbox-topics, tables, libraries, workers, projects, issues,
164
195
  backlogs, builds, changes, deploy-reports, runtime, people, agents, inbox,
165
196
  gate, design, runbooks, doctrine, changelog, health-verdicts, approval-kinds,
166
197
  notification-registry, skills, open-questions, decisions, drift, requests,
167
- rulebook, ad-decisions, domains, standardizations, archive, harness, and utils.
198
+ rulebook, ad-decisions, domains, standardizations, archive, harness, utils,
199
+ runs, releases, and operate.
168
200
 
169
201
  Run a command with --help or see the package README for all flags.`;
170
202
 
@@ -401,10 +433,55 @@ export async function figmaFileAdd(value, flags, { request = devRequest } = {})
401
433
  }
402
434
 
403
435
  export async function main(argv = process.argv.slice(2)) {
436
+ // Amendment acknowledgement is a lane-wide backstop, including otherwise
437
+ // local commands such as help and version.
438
+ if (argv[0] !== "__run-supervisor") {
439
+ await amendmentGuard(argv);
440
+ await showWaitingResults({ acknowledge: argv[0] !== "hook" });
441
+ }
404
442
  if (argv.length === 1 && ["--version", "-v"].includes(argv[0]))
405
443
  return console.log(VERSION);
406
444
  if (argv.length === 1 && ["--help", "-h"].includes(argv[0]))
407
445
  return console.log(HELP);
446
+ if (["run", "__run-supervisor"].includes(argv[0])) {
447
+ const boundary = argv.indexOf("--");
448
+ if (boundary === -1 || boundary === argv.length - 1)
449
+ throw new CliError("USAGE", "run needs a command after `--`.", 2);
450
+ const { args: optionArgs, flags: runFlags } = parseArgs(
451
+ argv.slice(1, boundary),
452
+ );
453
+ if (optionArgs.length)
454
+ throw new CliError(
455
+ "USAGE",
456
+ `Unexpected run argument before \`--\`: ${optionArgs.join(" ")}`,
457
+ 2,
458
+ );
459
+ const kind = runFlags.kind;
460
+ const name = runFlags.name;
461
+ if (Array.isArray(kind) || kind === true)
462
+ throw new CliError("USAGE", "run --kind needs one value.", 2);
463
+ if (Array.isArray(name) || name === true)
464
+ throw new CliError("USAGE", "run --name needs one value.", 2);
465
+ const command = argv.slice(boundary + 1);
466
+ if (argv[0] === "__run-supervisor") {
467
+ const ignoreBrokenPipe = (error) => {
468
+ if (error?.code !== "EPIPE") throw error;
469
+ };
470
+ stdout.on("error", ignoreBrokenPipe);
471
+ process.stderr.on("error", ignoreBrokenPipe);
472
+ try {
473
+ const result = await superviseRun({ command, kind, name });
474
+ process.exitCode = result.exitCode;
475
+ return;
476
+ } finally {
477
+ stdout.off("error", ignoreBrokenPipe);
478
+ process.stderr.off("error", ignoreBrokenPipe);
479
+ }
480
+ }
481
+ const exitCode = await launchRunSupervisor(command, { kind, name });
482
+ process.exitCode = exitCode;
483
+ return;
484
+ }
408
485
  const { args, flags: f } = parseArgs(argv);
409
486
  const json = Boolean(f.json);
410
487
  const [command, action, ...rest] = args;
@@ -471,6 +548,10 @@ export async function main(argv = process.argv.slice(2)) {
471
548
  if (rest.length) throw new CliError("USAGE", `harness ${action} takes no arguments, got: ${rest.join(" ")}. Write a flag value as --include-drafts=false.`, 2);
472
549
  return emitCommand(await harnessCommand(action, f));
473
550
  }
551
+ if (command === "watchdog") {
552
+ if (rest.length) throw new CliError("USAGE", `watchdog ${action ?? ""} takes no arguments, got: ${rest.join(" ")}.`, 2);
553
+ return emitCommand(await watchdogCommand(action, f));
554
+ }
474
555
  if (command === "docs") return emitCommand(await docsCommand(action, rest, f));
475
556
  if (command === "rulebook" && ["list", "show", "diff"].includes(action)) return emitCommand(await rulebookCommand(action, rest, f));
476
557
  if (command === "rules") return emitCommand(await rulesCommand(action, rest, f));
@@ -489,6 +570,10 @@ export async function main(argv = process.argv.slice(2)) {
489
570
  }
490
571
  return;
491
572
  }
573
+ if (command === "coordinator") return emitCommand(await coordinatorCommand(action, f));
574
+ if (command === "lane" && action === "launch") return emitCommand(await launchLaneCommand(rest[0], f));
575
+ if (command === "lane" && action === "amend") return emitCommand(await amendLaneCommand(rest[0], f));
576
+ if (command === "lane" && action === "gather") return emitCommand(await gatherLaneCommand(rest[0], f));
492
577
  if (command === "lane") return emitCommand(await laneCommand(action, rest, f));
493
578
  if (command === "next") return emitCommand(await nextCommand(action, f));
494
579
  if (command === "built") return emitCommand(await builtCommand(action, rest, f));
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.27";
7
+ export const VERSION = "0.6.29";
8
8
  export const configPath = () =>
9
9
  process.env.NODII_DEV_CONFIG_PATH ??
10
10
  join(homedir(), ".config/nodii-dev/config.json");
@@ -199,12 +199,16 @@ export async function checkLogin() {
199
199
  export const encode = (value) => encodeURIComponent(value);
200
200
  // Switches never take the next token as their value, so
201
201
  // `docs upload --wait rulebook/` keeps rulebook/ as a path.
202
- const SWITCHES = new Set(["json", "wait", "dry-run", "check", "all", "fleet", "help", "yes", "mine", "no-browser", "include-drafts", "drafted", "library", "async", "sync", "force", "system"]);
202
+ const SWITCHES = new Set(["json", "wait", "pending", "dry-run", "check", "all", "fleet", "help", "yes", "mine", "no-browser", "include-drafts", "drafted", "library", "async", "sync", "force", "system", "delta"]);
203
203
  export function parseArgs(argv) {
204
204
  const flags = {};
205
205
  const args = [];
206
206
  for (let i = 0; i < argv.length; i++) {
207
207
  const token = argv[i];
208
+ if (token === "--") {
209
+ args.push(...argv.slice(i + 1));
210
+ break;
211
+ }
208
212
  if (!token.startsWith("--")) {
209
213
  args.push(token);
210
214
  continue;