@tablation/crew 0.126.11 → 0.126.12

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/cli.js +41 -11
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -13595,7 +13595,7 @@ function doctorSelftestLines(stored, toolchains) {
13595
13595
  // src/cli.ts
13596
13596
  import { resolve as resolve7, dirname as dirname34, join as join56, basename as basename16 } from "path";
13597
13597
  import { fileURLToPath as fileURLToPath2 } from "url";
13598
- import { hostname as hostname4, homedir as homedir11 } from "os";
13598
+ import { hostname as hostname5, homedir as homedir11 } from "os";
13599
13599
  import { spawnSync as spawnSync11 } from "child_process";
13600
13600
  import { parse as parseYaml2 } from "yaml";
13601
13601
 
@@ -17463,7 +17463,7 @@ function flagWizardAnswers(f, env) {
17463
17463
  // src/release-run.ts
17464
17464
  import { readFileSync as readFileSync36, writeFileSync as writeFileSync31, existsSync as existsSync39, copyFileSync, mkdirSync as mkdirSync28, mkdtempSync as mkdtempSync3, rmSync as rmSync19 } from "fs";
17465
17465
  import { dirname as dirname24, join as join43 } from "path";
17466
- import { tmpdir as tmpdir5 } from "os";
17466
+ import { tmpdir as tmpdir5, hostname as hostname4 } from "os";
17467
17467
 
17468
17468
  // src/release.ts
17469
17469
  function describeUnplaceable(unplaceable, verifiedStatus) {
@@ -18150,6 +18150,17 @@ async function confirmExternalReleased(o, closures) {
18150
18150
  return { ...c, confirmed, version };
18151
18151
  });
18152
18152
  }
18153
+ var mergeFailed = (r) => typeof r === "object" && ("conflict" in r || "error" in r);
18154
+ function ensureCommitterIdentity(o) {
18155
+ if (gitOk(o.cwd, ["var", "GIT_COMMITTER_IDENT"])) return;
18156
+ const ship = hostname4().split(".")[0] || "ship";
18157
+ git(o.cwd, ["config", "user.name", `Crew (${ship})`]);
18158
+ git(o.cwd, ["config", "user.email", `crew@${ship}`]);
18159
+ o.emit.warn(`no git committer identity here \u2014 set a checkout-local one, Crew (${ship}), for the release commit`);
18160
+ }
18161
+ function isConflict(message, unmergedPaths) {
18162
+ return unmergedPaths.length > 0 || /CONFLICT \(|Automatic merge failed|unmerged (files|paths)/i.test(message);
18163
+ }
18153
18164
  function mergeOne(o, c) {
18154
18165
  const subject = c.entries[0] ?? `${c.ticket.title ?? c.ticket.issue_id} (${c.ticket.issue_id})`;
18155
18166
  if (o.dryRun) {
@@ -18157,7 +18168,11 @@ function mergeOne(o, c) {
18157
18168
  return { applied: true };
18158
18169
  }
18159
18170
  const before = headSha(o.cwd);
18171
+ const clearFailure = () => {
18172
+ o.attention?.clear(`release_merge_failed:${o.scope ?? "release"}`);
18173
+ };
18160
18174
  try {
18175
+ ensureCommitterIdentity(o);
18161
18176
  git(o.cwd, ["merge", "--squash", c.branch]);
18162
18177
  if (!git(o.cwd, ["diff", "--cached", "--name-only"])) {
18163
18178
  git(o.cwd, ["reset", "--hard", before]);
@@ -18165,6 +18180,7 @@ function mergeOne(o, c) {
18165
18180
  `${c.branch} is already contained in the integration branch \u2014 nothing to apply`,
18166
18181
  { ticket: c.ticket.issue_id }
18167
18182
  );
18183
+ clearFailure();
18168
18184
  return "noop";
18169
18185
  }
18170
18186
  const tip = gitOk(o.cwd, ["rev-parse", "--verify", "-q", `${c.branch}^{commit}`]);
@@ -18176,12 +18192,25 @@ ${BRANCH_TIP_TRAILER}: ${tip}` : "";
18176
18192
  Closes ${c.ticket.issue_id}.${trailer}`]);
18177
18193
  const sha = headSha(o.cwd);
18178
18194
  o.emit.emit(`merged ${c.branch}`, { ticket: c.ticket.issue_id });
18195
+ clearFailure();
18179
18196
  return { applied: true, sha };
18180
18197
  } catch (e) {
18181
18198
  const paths = (gitOk(o.cwd, ["diff", "--name-only", "--diff-filter=U"]) ?? "").split("\n").filter(Boolean);
18182
18199
  gitOk(o.cwd, ["reset", "--hard", before]);
18183
- o.emit.error(`could not merge ${c.branch}: ${e.message}`, { ticket: c.ticket.issue_id });
18184
- return { conflict: { candidate: c, paths, message: e.message } };
18200
+ const message = e.message;
18201
+ o.emit.error(`could not merge ${c.branch}: ${message}`, { ticket: c.ticket.issue_id });
18202
+ if (!isConflict(message, paths)) {
18203
+ if (o.attention) {
18204
+ void o.attention.raise({
18205
+ kind: "release_merge_failed",
18206
+ key: `release_merge_failed:${o.scope ?? "release"}`,
18207
+ message: `${o.scope ?? "release"}: could not merge ${c.branch} (${c.ticket.issue_id}) \u2014 not a conflict, so the ticket stays verified and is retried: ${message.slice(0, 400)}`,
18208
+ since: (/* @__PURE__ */ new Date()).toISOString()
18209
+ });
18210
+ }
18211
+ return { error: message };
18212
+ }
18213
+ return { conflict: { candidate: c, paths, message } };
18185
18214
  }
18186
18215
  }
18187
18216
  async function bump(o, size) {
@@ -18576,7 +18605,7 @@ async function isolateAndRetry(o, name, output, merged, preMerge, decision, fres
18576
18605
  for (const c of applied) {
18577
18606
  gitOk(o.cwd, ["reset", "--hard", preMerge]);
18578
18607
  const m = mergeOne(o, c);
18579
- if (typeof m === "object" && "conflict" in m) continue;
18608
+ if (mergeFailed(m)) continue;
18580
18609
  const r = await hook(o, name);
18581
18610
  if (r && r.code !== 0) {
18582
18611
  o.emit.warn(`${c.branch} fails the ${name} hook on its own`, { ticket: c.ticket.issue_id });
@@ -18588,8 +18617,8 @@ async function isolateAndRetry(o, name, output, merged, preMerge, decision, fres
18588
18617
  for (const [i, j] of pairs) {
18589
18618
  gitOk(o.cwd, ["reset", "--hard", preMerge]);
18590
18619
  const a = mergeOne(o, applied[i]);
18591
- const b = typeof a === "object" && "conflict" in a ? a : mergeOne(o, applied[j]);
18592
- if (typeof b === "object" && "conflict" in b) continue;
18620
+ const b = mergeFailed(a) ? a : mergeOne(o, applied[j]);
18621
+ if (mergeFailed(b)) continue;
18593
18622
  const r = await hook(o, name);
18594
18623
  if (r && r.code !== 0) {
18595
18624
  o.emit.warn(`${applied[j].branch} fails the ${name} hook together with ${applied[i].branch}`, { ticket: applied[j].ticket.issue_id });
@@ -18606,7 +18635,7 @@ async function isolateAndRetry(o, name, output, merged, preMerge, decision, fres
18606
18635
  let clean = true;
18607
18636
  for (const c of applied.slice(0, mid)) {
18608
18637
  const m = mergeOne(o, c);
18609
- if (typeof m === "object" && "conflict" in m) {
18638
+ if (mergeFailed(m)) {
18610
18639
  clean = false;
18611
18640
  break;
18612
18641
  }
@@ -18677,6 +18706,7 @@ async function mergeAndRelease(o, decision, fresh, releaseBranch, isolated = fal
18677
18706
  conflicts.push(r.conflict);
18678
18707
  continue;
18679
18708
  }
18709
+ if (typeof r === "object" && "error" in r) continue;
18680
18710
  if (typeof r === "object" && r.applied) {
18681
18711
  applied++;
18682
18712
  c.sha = r.sha;
@@ -25385,7 +25415,7 @@ if (command === "passenger-sync-daemon") {
25385
25415
  };
25386
25416
  if (command === "connect" && !flag("sign-out") && usesFlagAnswers(wizardFlags, connectIsTTY) && shouldRunWizard({ isTTY: true, crewHome: CREW_HOME })) {
25387
25417
  const flagged = flagWizardAnswers(wizardFlags, {
25388
- hostname: hostname4(),
25418
+ hostname: hostname5(),
25389
25419
  platform: hostPlatform(),
25390
25420
  pathEnv: process.env.PATH ?? "",
25391
25421
  nodePath: process.execPath,
@@ -25410,7 +25440,7 @@ if (command === "passenger-sync-daemon") {
25410
25440
  let answers;
25411
25441
  try {
25412
25442
  answers = await runWizard(prompter, {
25413
- hostname: hostname4(),
25443
+ hostname: hostname5(),
25414
25444
  platform: hostPlatform(),
25415
25445
  pathEnv: process.env.PATH ?? "",
25416
25446
  nodePath: process.execPath,
@@ -27967,7 +27997,7 @@ ${reconstruction.prompt}
27967
27997
  let result;
27968
27998
  try {
27969
27999
  result = await loginWithDeviceCode(`${baseUrl}/api`, {
27970
- deviceName: `crew on ${hostname4()}`,
28000
+ deviceName: `crew on ${hostname5()}`,
27971
28001
  // Lets the approval page preselect the workspace this connect is for.
27972
28002
  // A bare `crew connect` has none and passes nothing.
27973
28003
  ...workspace ? { workspaceSlug: workspace } : {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.126.11",
3
+ "version": "0.126.12",
4
4
  "description": "A standing team of headless agents that picks work off a Tablation board, does it on a machine you control, and reports back.",
5
5
  "type": "module",
6
6
  "license": "MIT",