@nodii/dev 0.6.5 → 0.6.7

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/dist/doctor.js CHANGED
@@ -22,7 +22,7 @@ export const LANE_PERMISSIONS = [
22
22
  { key: "devops.agents.write", for: "agent register|heartbeat" },
23
23
  { key: "devops.machines.manage", for: "machine show (this agent's machine and coordinator)" },
24
24
  { key: "devops.decisions.read", for: "figma check" },
25
- { key: "devops.decisions.write", for: "figma lock|log-write|submit|apply|published|abandon" },
25
+ { key: "devops.decisions.write", for: "figma lock|log-write|submit|apply|published|abandon|withdraw" },
26
26
  { key: "devops.decisions.lock", for: "figma release" },
27
27
  { key: "devops.rulebook.read", for: "rulebook show" },
28
28
  ];
package/dist/lanes.js CHANGED
@@ -48,7 +48,55 @@ function evidence(flags) {
48
48
  return { kind: flag === "figma" ? "figma_frame" : flag.replace("-", "_"), ...(URL.canParse(value) ? { url: value } : { ref: value }), ...via };
49
49
  }
50
50
 
51
- export async function laneCommand(action, args, flags, { request = devRequest, config = readConfig, gitContext = inferGitContext } = {}) {
51
+ const list = (value) => String(value).split(",").map((x) => x.trim()).filter(Boolean);
52
+
53
+ /**
54
+ * DEC-0011 (MW1-28.1): the body for `lane non-issue`. A re-route needs at
55
+ * least one issue key or an explicit `none`, and the branch work is either
56
+ * carried into a named issue with its commits or dropped with a reason, never
57
+ * left unsaid. Without --commits, the commits are the lane's branch commits
58
+ * that are not on origin/main, read from the lane's recorded worktree.
59
+ */
60
+ export async function nonIssueBody(flags, laneCommits) {
61
+ const reason = requireFlag(flags, "reason");
62
+ const evidence = requireFlag(flags, "evidence");
63
+ const rerouteFlag = requireFlag(flags, "reroute");
64
+ const reroute = rerouteFlag === "none" ? "none" : list(rerouteFlag);
65
+ if (reroute !== "none" && !reroute.length) throw new CliError("USAGE", "--reroute needs at least one issue key, or none when the evidence shows no defect anywhere.", 2);
66
+ const branchFlag = flags.branch;
67
+ const usage = "--branch must say what happens to the lane's branch work: carried:ISSUE_KEY or dropped[:REASON].";
68
+ if (typeof branchFlag !== "string" || !branchFlag) throw new CliError("USAGE", usage, 2);
69
+ const at = branchFlag.indexOf(":");
70
+ const disposition = at === -1 ? branchFlag : branchFlag.slice(0, at);
71
+ const detail = at === -1 ? "" : branchFlag.slice(at + 1).trim();
72
+ if (!(disposition === "carried" && detail) && disposition !== "dropped") throw new CliError("USAGE", usage, 2);
73
+ const given = flags.commits !== undefined ? list(requireFlag(flags, "commits")) : undefined;
74
+ // dropped:REASON states its own reason, so it needs no commit lookup.
75
+ const commits = given ?? (disposition === "dropped" && detail ? undefined : await laneCommits());
76
+ if (commits && commits.length > MAX_COMMITS) throw new CliError("USAGE", `That is ${commits.length} commits; Dev records at most ${MAX_COMMITS}. Pass --commits with the ones that matter, or --branch dropped:REASON.`, 2);
77
+ let branch;
78
+ if (disposition === "carried") {
79
+ if (!commits.length) throw new CliError("USAGE", "Carried work needs its commits: the lane's branch has none beyond origin/main. Pass --commits SHA[,SHA], or --branch dropped:REASON.", 2);
80
+ branch = { disposition, issueKey: detail, commits };
81
+ } else if (detail) branch = { disposition, reason: detail, ...(commits ? { commits } : {}) };
82
+ else if (!commits.length) branch = { disposition, reason: "no commits beyond origin/main" };
83
+ else throw new CliError("USAGE", `The lane's branch has ${commits.length} commits beyond origin/main. Say why they are dropped: --branch dropped:REASON.`, 2);
84
+ return { reason, evidence, reroute, branch, ...via };
85
+ }
86
+
87
+ const MAX_COMMITS = 200;
88
+
89
+ /** The lane's branch commits not on origin/main (as last fetched), from its recorded worktree. */
90
+ export async function branchCommits(lane) {
91
+ try {
92
+ const out = (await execFileAsync("git", ["-C", lane.worktree, "rev-list", `origin/main..${lane.branch}`], { encoding: "utf8" })).stdout.trim();
93
+ return out ? out.split("\n") : [];
94
+ } catch {
95
+ throw new CliError("GIT_REQUIRED", `Cannot read the commits of ${lane.branch} in ${lane.worktree}. Pass --commits SHA[,SHA], or --branch dropped:REASON.`, 2);
96
+ }
97
+ }
98
+
99
+ export async function laneCommand(action, args, flags, { request = devRequest, config = readConfig, gitContext = inferGitContext, commitsOf = branchCommits } = {}) {
52
100
  if (action === "list") {
53
101
  const c = flags.mine ? await config() : null;
54
102
  const payload = await request("GET", `/api/v1/lanes${query({ kind: flags.kind, status: flags.status, machine: flags.machine, agent: flags.mine ? c.agentId : flags.agent, "waiting-on": flags["waiting-on"], stuck: flags.stuck, cursor: flags.cursor, limit: flags.limit })}`);
@@ -108,6 +156,14 @@ export async function laneCommand(action, args, flags, { request = devRequest, c
108
156
  return { payload, human: `${ref}: ${action}d.` };
109
157
  }
110
158
  if (action === "stop") return { payload: await request("POST", `/api/v1/lanes/${encode(id)}/stop`, { reason: requireFlag(flags, "reason"), ...via }), human: `${ref}: stopped.` };
159
+ if (action === "non-issue") {
160
+ const body = await nonIssueBody(flags, async () => commitsOf((await request("GET", `/api/v1/lanes/${encode(id)}`)).data));
161
+ const payload = await request("POST", `/api/v1/lanes/${encode(id)}/non-issue`, body);
162
+ const { closedIssues = [], openIssues = [] } = payload?.data?.nonIssue ?? {};
163
+ const closed = closedIssues.length ? ` ${closedIssues.join(", ")} moved to wont_do.` : "";
164
+ const open = openIssues.length ? ` ${openIssues.join(", ")} left open: another active lane works on it.` : "";
165
+ return { payload, human: `${ref}: non_issue; slot freed.${closed}${open}` };
166
+ }
111
167
  throw new CliError("USAGE", `Unknown lane action: ${action}`, 2);
112
168
  }
113
169
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodii/dev",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Agent CLI for Nodii Dev, reached through the platform edge",
5
5
  "type": "module",
6
6
  "bin": {