@nodii/dev 0.6.41 → 0.6.43

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
@@ -357,6 +357,9 @@ nodii-dev lane step KEY --side backend|frontend --start|--done|--block STEP [--r
357
357
  # --reason is kept as a lane note; on a step already blocked,
358
358
  # --block --reason records the new reason (Dev issue 125 moves it onto the step)
359
359
  nodii-dev lane evidence KEY --pr|--commit|--figma|--deploy|--dev-check REF
360
+ nodii-dev lane done-check KEY --evidence TEXT|URL
361
+ # the lane's done check is met (NODII-DEV-CLI-4); a launched
362
+ # run that exits after it ends finished, not orphaned
360
363
  nodii-dev lane subagent-quota KEY N
361
364
  nodii-dev lane heartbeat KEY [--note TEXT]
362
365
  nodii-dev lane resume KEY
@@ -922,8 +925,9 @@ Dev identity.
922
925
  A launched or resumed runtime runs under a detached lane supervisor (an
923
926
  internal `nodii-dev __lane-supervisor` process), which sees its exit code and
924
927
  reports it to Dev as the lane's identity (NODII-DEV-CLI-1). It first reads the
925
- lane's status. A lane whose done check is recorded (its `dev_check` step done,
926
- or the lane `on_dev`, `non_issue` or `stopped`) has finished. On it, exit 0 with a clean worktree ends the run
928
+ lane's status. A lane whose done check is recorded (`nodii-dev lane done-check
929
+ KEY --evidence TEXT|URL`, its `dev_check` step done, or the lane `on_dev`,
930
+ `non_issue` or `stopped`) has finished. On it, exit 0 with a clean worktree ends the run
927
931
  `done`, exit 0 with uncommitted or untracked files ends it `handed_off` and names
928
932
  them, and any other exit ends it `failed`. None of these counts as a death. A
929
933
  process that stops before the done check is recorded is unfinished, whatever
package/dist/cli.js CHANGED
@@ -219,6 +219,7 @@ Usage: nodii-dev <command> [options] [--json]
219
219
  lane step <key> --side SIDE --not-applicable gather --reason-code pre_harness_lane [--note TEXT]
220
220
  # coordinator only: Gather never applied (pre-Gather lane); never "done"
221
221
  lane evidence <key> --pr|--commit|--figma|--deploy|--dev-check REF
222
+ lane done-check <key> --evidence TEXT|URL # the done check is met; a launched run that exits after it ends finished
222
223
  lane subagent-quota <key> <n> # coordinator assigns 0-100 subagent slots
223
224
  lane heartbeat|resume|land|verify|prioritize|deprioritize|stop <key>
224
225
  lane review <key> --file REVIEW.json # base/head, outcome and clause-cited findings
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.41";
7
+ export const VERSION = "0.6.43";
8
8
  export const configPath = () =>
9
9
  process.env.NODII_DEV_CONFIG_PATH ??
10
10
  join(homedir(), ".config/nodii-dev/config.json");
@@ -10,8 +10,8 @@ import { saveWatchedRun, watchdogRunDir } from "./watchdog.js";
10
10
  * NODII-DEV-CLI-1: a launched or resumed lane's runtime is the child of this
11
11
  * supervisor, so its exit code is known. The supervisor reports it to Dev
12
12
  * with the worktree's clean/dirty state and the lane's status. A lane whose
13
- * done check is recorded (its dev_check step done, or the lane on_dev,
14
- * non_issue or stopped) has finished: its run
13
+ * done check is recorded (`lane done-check`, NODII-DEV-CLI-4; its dev_check
14
+ * step done; or the lane on_dev, non_issue or stopped) has finished: its run
15
15
  * ends, never as a death. A process that stops before that is unfinished,
16
16
  * whatever its exit code: it is reported as a process exit, which Dev orphans
17
17
  * so `lane resume` relaunches it (hub-58 scope add). Before this, the
@@ -76,14 +76,15 @@ async function send(request, path, body, attempts = 3) {
76
76
  }
77
77
 
78
78
  /**
79
- * The lane's Dev status and whether its done check is recorded: a dev_check
80
- * step done, or a terminal lane. Unreadable reads as unfinished.
79
+ * The lane's Dev status and whether its done check is recorded: a recorded
80
+ * done check, a dev_check step done, or a terminal lane. Unreadable reads as
81
+ * unfinished.
81
82
  */
82
83
  async function laneProgress(request, laneKey) {
83
84
  try {
84
85
  const lane = (await request("GET", `/api/v1/lanes/${encode(laneKey)}`)).data;
85
86
  const devChecked = (lane?.steps ?? []).some((step) => step.stepKey === "dev_check" && step.state === "done");
86
- return { status: lane?.status ?? null, finished: devChecked || FINISHED_LANE.has(lane?.status) };
87
+ return { status: lane?.status ?? null, finished: Boolean(lane?.doneCheckRecorded) || devChecked || FINISHED_LANE.has(lane?.status) };
87
88
  } catch {
88
89
  return { status: null, finished: false };
89
90
  }
package/dist/lanes.js CHANGED
@@ -113,14 +113,17 @@ async function laneContract(id, request, options) {
113
113
  try {
114
114
  return (await request("GET", `/api/v1/lanes/${encode(id)}/contract`, undefined, options)).data?.text ?? null;
115
115
  } catch (error) {
116
- // A Dev from before the Lane contract route: say so, never hide it.
117
- if (error?.code === "HTTP_404" || error?.code === "NOT_FOUND") return "(this Dev does not serve the Lane contract yet; read the lane with `nodii-dev lane show`)";
116
+ // A Dev or edge without the Lane contract route (the edge answers an
117
+ // unknown route `unroutable`): say so, never fail the Gather on it.
118
+ if (["unroutable", "HTTP_404", "NOT_FOUND", "ROUTE_NOT_FOUND"].includes(error?.code)) return "(Dev does not serve the Lane contract here yet. Record your pick: the recorded Gather prints the full contract. Until then, `nodii-dev lane show` and `nodii-dev issues show <issue>` hold it.)";
118
119
  throw error;
119
120
  }
120
121
  }
121
122
  // Gather never ends on a bare "finished" (hub-58): the next step is the task.
123
+ // Dev has moved the lane past gather by now (NODII-DEV-CLI-3); recording the
124
+ // done check is what lets a launched run end finished (NODII-DEV-CLI-4).
122
125
  const nextStepText = (ref, doneCheck) =>
123
- `Gather is finished. Next: Task. Work the objective until ${doneCheck} is met, then run \`nodii-dev lane land ${ref}\` (or the lane's finish command). Don't stop before that.`;
126
+ `Gather is finished. Next: Task. Work the objective until ${doneCheck} is met, record it with \`nodii-dev lane done-check ${ref} --evidence TEXT|URL\`, then run \`nodii-dev lane land ${ref}\` (or the lane's finish command). Don't stop before that.`;
124
127
  const agentShortlistText = (ref, data, flags) => [
125
128
  ...contractLines(data),
126
129
  `Trigger shortlist ${data.shortlistId} · ${JSON.stringify(data.objective)}`,
@@ -515,6 +518,11 @@ export async function laneCommand(action, args, flags, { request = devRequest, c
515
518
  const lane = (await request("GET", `/api/v1/lanes/${encode(id)}`)).data;
516
519
  const step = lane.steps.find((x) => x.side === side && (x.id === stepRef || x.stepKey === stepRef));
517
520
  if (!step) throw new CliError("STEP_NOT_FOUND", `No ${side} step ${stepRef} on ${ref}.`, 1);
521
+ // Dev finishes gather and starts the next step itself when Gather's Freeze
522
+ // is written (NODII-DEV-CLI-3), so asking for that again is already true.
523
+ const already = { done: "done", start: "current" }[selected[0]];
524
+ if (already && step.state === already)
525
+ return { payload: { data: step }, human: `${ref}: ${side}/${step.stepKey} is already ${already}.` };
518
526
  // hub-58: Gather is the only step a coordinator may rule not applicable.
519
527
  if (ruling && step.stepKey !== "gather") throw new CliError("USAGE", "--not-applicable covers only the gather step.", 2);
520
528
  // GATHER-NA: coordinator only; Dev refuses a lane identity (COORDINATOR_REQUIRED).
@@ -548,6 +556,17 @@ export async function laneCommand(action, args, flags, { request = devRequest, c
548
556
  const payload = await request("POST", `/api/v1/lanes/${encode(id)}/evidence`, body);
549
557
  return { payload, human: `${ref}: recorded ${body.kind} evidence.` };
550
558
  }
559
+ if (action === "done-check") {
560
+ // NODII-DEV-CLI-4: the agent met the lane's done check. A launched run that
561
+ // exits after this ends finished instead of orphaned (lane-supervisor.js).
562
+ const value = typeof flags.evidence === "string" ? flags.evidence.trim() : "";
563
+ if (!value) throw new CliError("USAGE", "lane done-check needs --evidence TEXT|URL: what shows the lane's done check is met.", 2);
564
+ const body = { kind: "done_check", ...(/^https?:\/\//i.test(value) && URL.canParse(value) ? { url: value } : { ref: value }), ...via };
565
+ const payload = await request("POST", `/api/v1/lanes/${encode(id)}/evidence`, body);
566
+ if (!payload?.data?.doneCheckRecorded)
567
+ throw new CliError("DONE_CHECK_NOT_RECORDED", `Dev took the evidence but does not show ${ref}'s done check as recorded; it predates NODII-DEV-CLI-4. The run would still end orphaned.`, 1);
568
+ return { payload, human: `${ref}: done check recorded. The lane's run ends finished when its process exits.` };
569
+ }
551
570
  if (action === "heartbeat") {
552
571
  return { payload: await request("POST", `/api/v1/lanes/${encode(id)}/heartbeat`, { ...(flags.note !== undefined ? { note: flags.note } : {}), ...via }), human: `${ref}: heartbeat recorded.` };
553
572
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodii/dev",
3
- "version": "0.6.41",
3
+ "version": "0.6.43",
4
4
  "description": "Agent CLI for Nodii Dev, reached through the platform edge",
5
5
  "type": "module",
6
6
  "bin": {