@nanopm/cli 0.1.17 → 0.1.18

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.
Files changed (2) hide show
  1. package/dist/index.js +37 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5369,9 +5369,10 @@ function stepsLeft(plan, done) {
5369
5369
  function buildDir(home, jobId) {
5370
5370
  return `${home.replace(/\/+$/, "")}/.cache/nanopm/builds/${jobId}`;
5371
5371
  }
5372
- function buildBranch(ref, title) {
5372
+ function buildBranch(ref, title, jobId) {
5373
5373
  const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
5374
- return `nano/${ref.toLowerCase()}${slug ? `-${slug}` : ""}`;
5374
+ const own = jobId.replace(/[^a-z0-9]/gi, "").slice(0, 6).toLowerCase();
5375
+ return `nano/${ref.toLowerCase()}${slug ? `-${slug}` : ""}-${own}`;
5375
5376
  }
5376
5377
  var REGISTRIES = {
5377
5378
  "package-lock.json": ["registry.npmjs.org"],
@@ -5420,7 +5421,7 @@ var isDecideForMe = (answer) => /^\s*decide(\s+for\s+me)?\s*\.?\s*$/i.test(answe
5420
5421
  function answerForAgent(answer) {
5421
5422
  return isDecideForMe(answer) ? DECIDE_FOR_ME : answer;
5422
5423
  }
5423
- var BUILD_HISTORY_KINDS = ["worktree", "plan", "step", "question", "answer", "paused", "pr", "handed", "throw", "thrown"];
5424
+ var BUILD_HISTORY_KINDS = ["worktree", "plan", "step", "question", "answer", "paused", "pr", "handed", "throw", "thrown", "closed"];
5424
5425
  function originOf(job) {
5425
5426
  const named = (job.params ?? {}).origin;
5426
5427
  return typeof named === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(named) ? named : job.id;
@@ -5662,11 +5663,12 @@ async function ghReady(cwd) {
5662
5663
  return /ENOENT/.test(errorMessage(err)) ? "the GitHub CLI is not installed on this machine: brew install gh, then gh auth login" : "the GitHub CLI is not signed in on this machine: run gh auth login in your terminal";
5663
5664
  }
5664
5665
  }
5665
- async function pullRequestMerged(cwd, number) {
5666
+ async function pullRequestState(cwd, number) {
5666
5667
  try {
5667
- return await gh(cwd, ["pr", "view", String(number), "--json", "state", "--jq", ".state"]) === "MERGED";
5668
+ const { state, headRefName } = JSON.parse(await gh(cwd, ["pr", "view", String(number), "--json", "state,headRefName"]));
5669
+ return (state === "MERGED" || state === "CLOSED" || state === "OPEN") && typeof headRefName === "string" ? { state, head: headRefName } : null;
5668
5670
  } catch {
5669
- return false;
5671
+ return null;
5670
5672
  }
5671
5673
  }
5672
5674
  async function openPullRequest(cwd, pr) {
@@ -11226,7 +11228,7 @@ async function prepareBuild(client, job, clone, adapter) {
11226
11228
  await startSolution(client, job.project_id, solution.ref, job.id);
11227
11229
  return { ok: true, build: { solution, clone, ...place, worktree: worktree2, network: await network(place.dir), history } };
11228
11230
  }
11229
- const branch = buildBranch(solution.ref, solution.title);
11231
+ const branch = buildBranch(solution.ref, solution.title, job.id);
11230
11232
  await mkdir5(join13(dir, ".."), { recursive: true, mode: 448 });
11231
11233
  const { base, fork, worktree } = await addWorktree(clone, dir, branch);
11232
11234
  made = true;
@@ -11513,26 +11515,40 @@ async function throwAwayBuilds(client, daemonId, userId) {
11513
11515
  }
11514
11516
  return thrown;
11515
11517
  }
11516
- async function shippedBuilds(client, daemonId, userId) {
11517
- const { data: building } = await client.from("solutions").select("id, ref, project_id").eq("status", "building");
11518
+ async function settledBuilds(client, daemonId, userId) {
11519
+ const { data: building } = await client.from("solutions").select("id, ref, project_id").eq("status", "building").is("superseded_by", null);
11518
11520
  if (!building?.length) return [];
11519
11521
  const [{ data: built }, { data: clones }] = await Promise.all([
11520
- client.from("jobs").select("id, params, pr:result->pr").eq("skill", BUILD_SKILL).eq("status", "succeeded").eq("assigned_daemon_id", daemonId).eq("requested_by", userId).in("params->>solution_id", building.map((s) => s.id)),
11522
+ client.from("jobs").select("id, project_id, params, created_at, pr:result->pr").eq("skill", BUILD_SKILL).eq("status", "succeeded").eq("assigned_daemon_id", daemonId).eq("requested_by", userId).in("params->>solution_id", building.map((s) => s.id)).order("created_at", { ascending: false }),
11521
11523
  client.from("clones").select("project_id, repo_path").eq("daemon_id", daemonId)
11522
11524
  ]);
11525
+ const newest = [...new Map((built ?? []).reverse().map((j) => [j.params?.solution_id, j])).values()];
11526
+ const { data: closed } = newest.length ? await client.from("job_events").select("job_id").in("job_id", newest.map((j) => j.id)).eq("kind", "closed") : { data: [] };
11523
11527
  const cloneOf = new Map((clones ?? []).map((c) => [c.project_id, c.repo_path]));
11524
- const shipped = [];
11525
- for (const j of built ?? []) {
11528
+ const settled2 = [];
11529
+ for (const j of newest.filter((n) => !closed?.some((c) => c.job_id === n.id))) {
11526
11530
  const solution = building.find((s) => s.id === j.params?.solution_id);
11527
11531
  const number = j.pr?.number;
11528
11532
  const clone = solution ? cloneOf.get(solution.project_id) : void 0;
11529
- if (!solution || typeof number !== "number" || number <= 0 || !clone || !existsSync5(clone) || !await pullRequestMerged(clone, number)) continue;
11530
- const { error } = await client.rpc("finish_solution", { p_project_id: solution.project_id, p_ref: solution.ref, p_job_id: j.id });
11531
- if (error) continue;
11532
- await logActivity({ client }, { id: j.id, project_id: solution.project_id }, "shipped", `Pull request #${number} merged: ${solution.ref} shipped`);
11533
- shipped.push(j.id);
11534
- }
11535
- return shipped;
11533
+ if (!solution || typeof number !== "number" || number <= 0 || !clone || !existsSync5(clone)) continue;
11534
+ const [{ place }, pr] = await Promise.all([loadHistory(client, j), pullRequestState(clone, number)]);
11535
+ if (!place || !pr || pr.head !== place.branch) continue;
11536
+ const at = { id: j.id, project_id: solution.project_id };
11537
+ if (pr.state === "MERGED") {
11538
+ const { error } = await client.rpc("finish_solution", { p_project_id: solution.project_id, p_ref: solution.ref, p_job_id: j.id });
11539
+ if (error) continue;
11540
+ await logActivity({ client }, at, "shipped", `Pull request #${number} merged: ${solution.ref} shipped`);
11541
+ settled2.push({ id: j.id, ref: solution.ref, merged: true });
11542
+ } else if (pr.state === "CLOSED") {
11543
+ const { error } = await client.rpc("unstart_solution", { p_project_id: solution.project_id, p_ref: solution.ref, p_to: wasOf(j.params) });
11544
+ if (error) continue;
11545
+ await deleteBranch(clone, place.branch);
11546
+ await appendJobEvent(client, j.id, "closed", { number }, "nanopm");
11547
+ await logActivity({ client }, at, "closed", `Pull request #${number} closed without merging: ${solution.ref} back on the roadmap`);
11548
+ settled2.push({ id: j.id, ref: solution.ref, merged: false });
11549
+ }
11550
+ }
11551
+ return settled2;
11536
11552
  }
11537
11553
  async function tellTheApp(accessToken, jobId, fetchImpl = fetch) {
11538
11554
  try {
@@ -11696,7 +11712,7 @@ async function runDaemon(options = {}) {
11696
11712
  }
11697
11713
  if (!options.once && Date.now() - lastShipCheck > SHIP_CHECK_MS) {
11698
11714
  lastShipCheck = Date.now();
11699
- for (const id of await shippedBuilds(auth.client, daemonId, auth.userId).catch(() => [])) log(`build ${id}: its pull request merged, shipped`);
11715
+ for (const b of await settledBuilds(auth.client, daemonId, auth.userId).catch(() => [])) log(`build ${b.id}: its pull request ${b.merged ? `merged, ${b.ref} shipped` : `closed without merging, ${b.ref} back on the roadmap`}`);
11700
11716
  }
11701
11717
  if (!options.once && Date.now() - lastDeployCheck > DEPLOY_CHECK_MS) {
11702
11718
  lastDeployCheck = Date.now();
@@ -14651,7 +14667,7 @@ import { promisify as promisify8 } from "util";
14651
14667
  // package.json
14652
14668
  var package_default = {
14653
14669
  name: "@nanopm/cli",
14654
- version: "0.1.17",
14670
+ version: "0.1.18",
14655
14671
  description: "An autonomous product manager for builders who run several small products. Runs on your machine, drives your own coding harness.",
14656
14672
  type: "module",
14657
14673
  license: "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanopm/cli",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "An autonomous product manager for builders who run several small products. Runs on your machine, drives your own coding harness.",
5
5
  "type": "module",
6
6
  "license": "MIT",