@tablation/crew 0.52.0 → 0.53.0
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/cli.js +36 -24
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1435,8 +1435,8 @@ var TOP_LEVEL = /* @__PURE__ */ new Set([
|
|
|
1435
1435
|
"labels",
|
|
1436
1436
|
"release"
|
|
1437
1437
|
]);
|
|
1438
|
-
var BRANCH_KEYS = /* @__PURE__ */ new Set(["base", "name", "push", "remote"]);
|
|
1439
|
-
var PLACEHOLDER = /\{(key|number|slug|role|prefix|tag)\}/g;
|
|
1438
|
+
var BRANCH_KEYS = /* @__PURE__ */ new Set(["base", "name", "push", "remote", "lowercase"]);
|
|
1439
|
+
var PLACEHOLDER = /\{(key|number|slug|role|prefix|tag|issue)\}/g;
|
|
1440
1440
|
var WORKTREE_PLACEHOLDERS = ["dir", "issue", "number", "key", "slug", "role", "prefix", "tag"];
|
|
1441
1441
|
function worktreeNameProblem(template) {
|
|
1442
1442
|
const valid = `Valid placeholders: ${WORKTREE_PLACEHOLDERS.map((p) => `{${p}}`).join(" ")}.`;
|
|
@@ -1528,7 +1528,7 @@ function parseRepoConfig(text, file) {
|
|
|
1528
1528
|
if (!PLACEHOLDER.test(branchName)) {
|
|
1529
1529
|
PLACEHOLDER.lastIndex = 0;
|
|
1530
1530
|
throw new RepoConfigError(
|
|
1531
|
-
`${file}: branch.name ("${branchName}") names no placeholder \u2014 every ticket would get the same branch. Use at least one of {key} {number} {slug} {role}.`
|
|
1531
|
+
`${file}: branch.name ("${branchName}") names no placeholder \u2014 every ticket would get the same branch. Use at least one of {key} {number} {slug} {role} {prefix} {tag} {issue}.`
|
|
1532
1532
|
);
|
|
1533
1533
|
}
|
|
1534
1534
|
PLACEHOLDER.lastIndex = 0;
|
|
@@ -1536,7 +1536,8 @@ function parseRepoConfig(text, file) {
|
|
|
1536
1536
|
base: String(raw.branch?.base ?? "main"),
|
|
1537
1537
|
name: branchName,
|
|
1538
1538
|
push: String(raw.branch?.push ?? branchName),
|
|
1539
|
-
remote: String(raw.branch?.remote ?? "origin")
|
|
1539
|
+
remote: String(raw.branch?.remote ?? "origin"),
|
|
1540
|
+
...raw.branch?.lowercase !== void 0 ? { lowercase: parseLowercase(raw.branch.lowercase, file) } : {}
|
|
1540
1541
|
};
|
|
1541
1542
|
const copyRaw = raw.worktrees?.copy;
|
|
1542
1543
|
if (copyRaw !== void 0 && !Array.isArray(copyRaw)) {
|
|
@@ -1733,9 +1734,13 @@ function slugify(title, maxLength = 40) {
|
|
|
1733
1734
|
const s = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, maxLength).replace(/-+$/, "");
|
|
1734
1735
|
return s || "work";
|
|
1735
1736
|
}
|
|
1737
|
+
function parseLowercase(v, where) {
|
|
1738
|
+
if (typeof v !== "boolean") throw new RepoConfigError(`${where}: branch.lowercase must be true or false`);
|
|
1739
|
+
return v;
|
|
1740
|
+
}
|
|
1736
1741
|
function renderBranchName(template, ctx) {
|
|
1737
1742
|
const number = ctx.key.replace(/^\D+/, "");
|
|
1738
|
-
|
|
1743
|
+
const rendered = template.replace(PLACEHOLDER, (_m, name) => {
|
|
1739
1744
|
switch (name) {
|
|
1740
1745
|
case "key":
|
|
1741
1746
|
return ctx.key;
|
|
@@ -1749,14 +1754,16 @@ function renderBranchName(template, ctx) {
|
|
|
1749
1754
|
return ctx.tag ?? ctx.key;
|
|
1750
1755
|
case "prefix":
|
|
1751
1756
|
return ctx.prefix ?? "";
|
|
1757
|
+
case "issue":
|
|
1758
|
+
return (ctx.tag ?? ctx.key).toLowerCase();
|
|
1752
1759
|
default:
|
|
1753
1760
|
return "";
|
|
1754
1761
|
}
|
|
1755
1762
|
});
|
|
1763
|
+
return ctx.lowercase ? rendered.toLowerCase() : rendered;
|
|
1756
1764
|
}
|
|
1757
1765
|
function renderWorktreeName(template, ctx) {
|
|
1758
|
-
|
|
1759
|
-
return renderBranchName(template.replace(/\{dir\}/g, ctx.dir).replace(/\{issue\}/g, issue), ctx);
|
|
1766
|
+
return renderBranchName(template.replace(/\{dir\}/g, ctx.dir), ctx);
|
|
1760
1767
|
}
|
|
1761
1768
|
function defaultWorktreePrefix(dir) {
|
|
1762
1769
|
const name = basename2(dir.replace(/[/\\]+$/, ""));
|
|
@@ -1856,7 +1863,8 @@ function resolveRepoConfig(repo, ship, dir) {
|
|
|
1856
1863
|
repo?.branch.remote === "origin" ? void 0 : repo?.branch.remote,
|
|
1857
1864
|
ship?.branch?.remote,
|
|
1858
1865
|
"origin"
|
|
1859
|
-
)
|
|
1866
|
+
),
|
|
1867
|
+
...pick("branch.lowercase", repo?.branch.lowercase, ship?.branch?.lowercase, false) ? { lowercase: true } : {}
|
|
1860
1868
|
},
|
|
1861
1869
|
// Unlike every other field here, platform has no ship-level fallback: what
|
|
1862
1870
|
// a repo needs of a host is a fact about that repo alone (its build
|
|
@@ -2055,7 +2063,7 @@ function parseWorktreeName(v, where, file) {
|
|
|
2055
2063
|
return String(v);
|
|
2056
2064
|
}
|
|
2057
2065
|
var REPO_ENTRY_KEYS = /* @__PURE__ */ new Set(["dir", "hooks", "labels", "release", "branch", "hostPassengers", "worktreeName", "toolchain"]);
|
|
2058
|
-
var BRANCH_OVERRIDE_KEYS = /* @__PURE__ */ new Set(["base", "name", "push", "remote"]);
|
|
2066
|
+
var BRANCH_OVERRIDE_KEYS = /* @__PURE__ */ new Set(["base", "name", "push", "remote", "lowercase"]);
|
|
2059
2067
|
var RELEASE_OVERRIDE_KEYS = /* @__PURE__ */ new Set([
|
|
2060
2068
|
"mode",
|
|
2061
2069
|
"ci",
|
|
@@ -2139,8 +2147,12 @@ function parseBranchOverride(raw, where, file) {
|
|
|
2139
2147
|
const name = raw.name !== void 0 ? String(raw.name) : void 0;
|
|
2140
2148
|
const push = raw.push !== void 0 ? String(raw.push) : void 0;
|
|
2141
2149
|
const remote = raw.remote !== void 0 ? String(raw.remote) : void 0;
|
|
2142
|
-
if (
|
|
2143
|
-
|
|
2150
|
+
if (raw.lowercase !== void 0 && typeof raw.lowercase !== "boolean") {
|
|
2151
|
+
throw new ConfigError(`${file}: ${where}.branch.lowercase must be true or false`);
|
|
2152
|
+
}
|
|
2153
|
+
const lowercase = raw.lowercase;
|
|
2154
|
+
if (base === void 0 && name === void 0 && push === void 0 && remote === void 0 && lowercase === void 0) return void 0;
|
|
2155
|
+
return { base, name, push, remote, ...lowercase !== void 0 ? { lowercase } : {} };
|
|
2144
2156
|
}
|
|
2145
2157
|
function mergeRouteRelease(route, override) {
|
|
2146
2158
|
const provider = override?.ci?.provider ?? route.ci?.provider;
|
|
@@ -6355,13 +6367,13 @@ ${waiting.map((t) => `| ${displayKey2(t)} | ${t.status} | ${blockers(t, i)} |`).
|
|
|
6355
6367
|
|
|
6356
6368
|
// src/ticket-branch.ts
|
|
6357
6369
|
import { basename as basename5 } from "path";
|
|
6358
|
-
function branchRenderer(t, role) {
|
|
6370
|
+
function branchRenderer(t, role, lowercase) {
|
|
6359
6371
|
const { tag, prefix } = ticketBranchContext(t);
|
|
6360
|
-
return (template) => renderBranchName(template, { key: t.issue_id, title: t.title ?? void 0, role, tag, prefix });
|
|
6372
|
+
return (template) => renderBranchName(template, { key: t.issue_id, title: t.title ?? void 0, role, tag, prefix, lowercase });
|
|
6361
6373
|
}
|
|
6362
6374
|
function worktreeForTicket(dir, cfg, t, role) {
|
|
6363
6375
|
const { prefix } = ticketBranchContext(t);
|
|
6364
|
-
const branchName = branchRenderer(t, role)(effectiveBranchTemplate(cfg, prefix));
|
|
6376
|
+
const branchName = branchRenderer(t, role, cfg.branch.lowercase)(effectiveBranchTemplate(cfg, prefix));
|
|
6365
6377
|
const number = t.issue_id.replace(/^\D+/, "");
|
|
6366
6378
|
const { tag } = ticketBranchContext(t);
|
|
6367
6379
|
return effectiveWorktreeDirName(cfg, dir, branchName, number, (template) => renderWorktreeName(template, {
|
|
@@ -6380,10 +6392,10 @@ function branchTemplates(cfg, t) {
|
|
|
6380
6392
|
return { name, push };
|
|
6381
6393
|
}
|
|
6382
6394
|
function pushedBranchForTicket(cfg, t, role) {
|
|
6383
|
-
return branchRenderer(t, role)(branchTemplates(cfg, t).push);
|
|
6395
|
+
return branchRenderer(t, role, cfg.branch.lowercase)(branchTemplates(cfg, t).push);
|
|
6384
6396
|
}
|
|
6385
6397
|
function existingBranchForTicket(dir, cfg, t, role) {
|
|
6386
|
-
return branchForIssue(dir, t.issue_id, branchTemplates(cfg, t), branchRenderer(t, role));
|
|
6398
|
+
return branchForIssue(dir, t.issue_id, branchTemplates(cfg, t), branchRenderer(t, role, cfg.branch.lowercase));
|
|
6387
6399
|
}
|
|
6388
6400
|
function locateBranchForTicket(dir, cfg, t, role, fetchedDirs) {
|
|
6389
6401
|
const local = existingBranchForTicket(dir, cfg, t, role);
|
|
@@ -6394,7 +6406,7 @@ function locateBranchForTicket(dir, cfg, t, role, fetchedDirs) {
|
|
|
6394
6406
|
fetchedDirs.add(dir);
|
|
6395
6407
|
fetchRemote(dir, remote);
|
|
6396
6408
|
}
|
|
6397
|
-
const found = remoteBranchForIssue(dir, remote, t.issue_id, branchTemplates(cfg, t), branchRenderer(t, role));
|
|
6409
|
+
const found = remoteBranchForIssue(dir, remote, t.issue_id, branchTemplates(cfg, t), branchRenderer(t, role, cfg.branch.lowercase));
|
|
6398
6410
|
return found ? { branch: found, where: "remote" } : null;
|
|
6399
6411
|
}
|
|
6400
6412
|
function materializeBranchForTicket(dir, cfg, t, role, onProblem) {
|
|
@@ -6712,14 +6724,14 @@ function writeDigest(o, d, role, stateDir) {
|
|
|
6712
6724
|
};
|
|
6713
6725
|
const fetchedDirs = /* @__PURE__ */ new Set();
|
|
6714
6726
|
const dirFor = (t) => dirForRepo(o.route, t.repo_id);
|
|
6715
|
-
const render2 = (t) => branchRenderer(t, role);
|
|
6727
|
+
const render2 = (t, lowercase) => branchRenderer(t, role, lowercase);
|
|
6716
6728
|
const input = {
|
|
6717
6729
|
dirFor,
|
|
6718
6730
|
repoStop: repoStopFor(openShipAttention(o.state), o.route),
|
|
6719
6731
|
branchFor: (t) => {
|
|
6720
6732
|
const cfg = repoFor(dirFor(t) ?? o.route.dir);
|
|
6721
6733
|
const { prefix } = ticketBranchContext(t);
|
|
6722
|
-
return render2(t)(effectiveBranchTemplate(cfg, prefix));
|
|
6734
|
+
return render2(t, cfg.branch.lowercase)(effectiveBranchTemplate(cfg, prefix));
|
|
6723
6735
|
},
|
|
6724
6736
|
// ISSUE-1028: the agent previously had to derive this itself from the
|
|
6725
6737
|
// Environment section's own worked example, which is rendered before
|
|
@@ -7210,7 +7222,7 @@ function repoPrefix(repo) {
|
|
|
7210
7222
|
function branchExample(repo, key) {
|
|
7211
7223
|
const prefix = repoPrefix(repo);
|
|
7212
7224
|
const template = effectiveBranchTemplate(repo, prefix);
|
|
7213
|
-
return renderBranchName(template, { key, title: "Fix the widget", role: "dev", prefix });
|
|
7225
|
+
return renderBranchName(template, { key, title: "Fix the widget", role: "dev", prefix, lowercase: repo.branch.lowercase });
|
|
7214
7226
|
}
|
|
7215
7227
|
function repoSection(r, key, heading) {
|
|
7216
7228
|
const repo = r.config;
|
|
@@ -8957,7 +8969,7 @@ var describeRunWorktreePlan = (p) => {
|
|
|
8957
8969
|
var planIsUsable = (p) => p.action !== "leave-dirty" && p.action !== "leave-unpushed";
|
|
8958
8970
|
function newBranchName(cfg, t, role) {
|
|
8959
8971
|
const { prefix } = ticketBranchContext(t);
|
|
8960
|
-
return branchRenderer(t, role)(effectiveBranchTemplate(cfg, prefix));
|
|
8972
|
+
return branchRenderer(t, role, cfg.branch.lowercase)(effectiveBranchTemplate(cfg, prefix));
|
|
8961
8973
|
}
|
|
8962
8974
|
function planRunWorktree(dir, cfg, t, role, opts = {}) {
|
|
8963
8975
|
const { remote, base } = cfg.branch;
|
|
@@ -9721,9 +9733,9 @@ function reviewProblems(repo, contract) {
|
|
|
9721
9733
|
if (!reviewApplies(repo, contract)) return [];
|
|
9722
9734
|
const problems = [];
|
|
9723
9735
|
const template = repo.branch.push ?? repo.branch.name;
|
|
9724
|
-
if (!/\{(key|number|tag)\}/.test(template)) {
|
|
9736
|
+
if (!/\{(key|number|tag|issue)\}/.test(template)) {
|
|
9725
9737
|
problems.push(
|
|
9726
|
-
`branch.push "${template}" names none of {key}, {number} or {
|
|
9738
|
+
`branch.push "${template}" names none of {key}, {number}, {tag} or {issue} \u2014 with release.mode "external" and a reviewing status, the pushed branch is the only link back to its ticket`
|
|
9727
9739
|
);
|
|
9728
9740
|
}
|
|
9729
9741
|
return problems;
|
|
@@ -16139,7 +16151,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
16139
16151
|
const branch = found.branch ?? branchForIssue(target.dir, `ISSUE-${n}`, {
|
|
16140
16152
|
name: target.config.branch.name,
|
|
16141
16153
|
push: target.config.branch.push
|
|
16142
|
-
}, (t) => renderBranchName(t, { key: `ISSUE-${n}
|
|
16154
|
+
}, (t) => renderBranchName(t, { key: `ISSUE-${n}`, lowercase: target.config.branch.lowercase }));
|
|
16143
16155
|
const pids = pidsInWorktree(wt, num);
|
|
16144
16156
|
if (pids.length) {
|
|
16145
16157
|
emit.emit(`${dryRun ? "would kill" : "killing"} processes still inside ${wt}: ${pids.join(" ")}`);
|
package/package.json
CHANGED