@tablation/crew 0.64.0 → 0.66.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 +85 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1449,6 +1449,7 @@ var HOOK_NAMES = [
|
|
|
1449
1449
|
"ports",
|
|
1450
1450
|
"isolate",
|
|
1451
1451
|
"handoff",
|
|
1452
|
+
"ci_status",
|
|
1452
1453
|
"version",
|
|
1453
1454
|
"bump",
|
|
1454
1455
|
"pr",
|
|
@@ -2792,7 +2793,8 @@ var HOOK_PURPOSE = [
|
|
|
2792
2793
|
["ports", "this worktree's port assignments; prints KEY=value overrides to export"],
|
|
2793
2794
|
["handoff", "leave the operator able to open what you built; put its output in your progress comment"],
|
|
2794
2795
|
["test", "run the suite"],
|
|
2795
|
-
["build", "build it"]
|
|
2796
|
+
["build", "build it"],
|
|
2797
|
+
["ci_status", "after you push and before you hand off: exit 0 means CI is green for your branch; on failure fix and push again, and say in your progress comment if it is still pending"]
|
|
2796
2798
|
];
|
|
2797
2799
|
function hookTable(repo) {
|
|
2798
2800
|
const declared = HOOK_PURPOSE.filter(([name]) => repo.hooks[name]);
|
|
@@ -13027,6 +13029,62 @@ function configuredRepos(text, route, base) {
|
|
|
13027
13029
|
const dir = m.get("dir");
|
|
13028
13030
|
return dir ? [{ name: basename7(String(dir)), dir: expandDir(String(dir), base) }] : [];
|
|
13029
13031
|
}
|
|
13032
|
+
function routeSetsHooks(text, route, name) {
|
|
13033
|
+
const m = routeMapOf(parseDocument(text), route);
|
|
13034
|
+
const repos = m.get("repos", true);
|
|
13035
|
+
let target = m;
|
|
13036
|
+
if (isMap(repos)) target = repos.get(name, true);
|
|
13037
|
+
if (!isMap(target)) return false;
|
|
13038
|
+
const hooks = target.get("hooks", true);
|
|
13039
|
+
return isMap(hooks) && hooks.items.length > 0;
|
|
13040
|
+
}
|
|
13041
|
+
function listRepoRows(i) {
|
|
13042
|
+
const checkouts = configuredRepos(i.text, i.route, i.base);
|
|
13043
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
13044
|
+
const hooksSourceOf = (c) => i.exists(c.dir) && i.repoHasHooks(c.dir) ? "repo" : routeSetsHooks(i.text, i.route, c.name) ? "route" : "none";
|
|
13045
|
+
const originFor = (c, remote) => {
|
|
13046
|
+
const o = i.originOf(c.dir) ?? null;
|
|
13047
|
+
if (!o) return null;
|
|
13048
|
+
return remote !== null && normalizeRemote(o) === normalizeRemote(remote) ? null : o;
|
|
13049
|
+
};
|
|
13050
|
+
const rows = [];
|
|
13051
|
+
const names = i.resolved?.repoNames ?? {};
|
|
13052
|
+
const remotes = i.resolved?.repoRemotes ?? {};
|
|
13053
|
+
for (const [id, name] of Object.entries(names)) {
|
|
13054
|
+
const remote = remotes[id] ?? null;
|
|
13055
|
+
const want = normalizeRemote(remote);
|
|
13056
|
+
let idx = checkouts.findIndex((c2, n) => !claimed.has(n) && want !== void 0 && normalizeRemote(i.originOf(c2.dir)) === want);
|
|
13057
|
+
if (idx < 0) idx = checkouts.findIndex((c2, n) => !claimed.has(n) && c2.name === name);
|
|
13058
|
+
const c = idx >= 0 ? checkouts[idx] : void 0;
|
|
13059
|
+
if (idx >= 0) claimed.add(idx);
|
|
13060
|
+
rows.push({
|
|
13061
|
+
name,
|
|
13062
|
+
remote,
|
|
13063
|
+
repoRowId: id,
|
|
13064
|
+
attached: c !== void 0,
|
|
13065
|
+
dir: c?.dir ?? null,
|
|
13066
|
+
exists: c ? i.exists(c.dir) : false,
|
|
13067
|
+
origin: c ? originFor(c, remote) : null,
|
|
13068
|
+
matchedRow: c ? name : null,
|
|
13069
|
+
hooksSource: c ? hooksSourceOf(c) : "none"
|
|
13070
|
+
});
|
|
13071
|
+
}
|
|
13072
|
+
checkouts.forEach((c, n) => {
|
|
13073
|
+
if (claimed.has(n)) return;
|
|
13074
|
+
rows.push({
|
|
13075
|
+
name: c.name,
|
|
13076
|
+
remote: null,
|
|
13077
|
+
repoRowId: null,
|
|
13078
|
+
attached: true,
|
|
13079
|
+
dir: c.dir,
|
|
13080
|
+
exists: i.exists(c.dir),
|
|
13081
|
+
origin: originFor(c, null),
|
|
13082
|
+
matchedRow: null,
|
|
13083
|
+
hooksSource: hooksSourceOf(c)
|
|
13084
|
+
});
|
|
13085
|
+
});
|
|
13086
|
+
return rows;
|
|
13087
|
+
}
|
|
13030
13088
|
function planRepoAdd(i) {
|
|
13031
13089
|
const doc = parseDocument(i.text);
|
|
13032
13090
|
if (doc.errors.length > 0) throw new ReposError(`config is not valid YAML \u2014 ${doc.errors[0].message}`);
|
|
@@ -13225,11 +13283,11 @@ function detectRecipes(f) {
|
|
|
13225
13283
|
{
|
|
13226
13284
|
id: "github-actions-ci-status",
|
|
13227
13285
|
title: "Check CI status before hand-off",
|
|
13228
|
-
description: "Ask GitHub whether the latest run on the branch passed before a ticket is handed to QA
|
|
13286
|
+
description: "Ask GitHub whether the latest run on the branch passed before a ticket is handed to QA (`hooks.ci_status`).",
|
|
13229
13287
|
evidence,
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
writable:
|
|
13288
|
+
// `gh` prints the conclusion and exits 0 either way, so the test is on the text.
|
|
13289
|
+
hooks: { ci_status: `test "$(gh run list --branch "$CREW_BRANCH" --limit 1 --json conclusion -q '.[0].conclusion')" = success` },
|
|
13290
|
+
writable: true,
|
|
13233
13291
|
defaultOn: false
|
|
13234
13292
|
}
|
|
13235
13293
|
];
|
|
@@ -15416,7 +15474,7 @@ function usage() {
|
|
|
15416
15474
|
crew repos add [ROUTE] [NAME] [PATH] attach a local checkout to a route in crew.yaml (--dry-run previews)
|
|
15417
15475
|
crew repos clone [ROUTE] NAME clone a Repos row's remote into the route directory and attach it (--dir PATH, --dry-run, --json)
|
|
15418
15476
|
crew repos hooks [ROUTE] NAME suggest test/build hooks for a checkout (--agent, --write route|repo, --recipes, --json)
|
|
15419
|
-
crew repos list ROUTE the checkouts a route has, with the tracker's Repos row each matches
|
|
15477
|
+
crew repos list ROUTE the checkouts a route has, with the tracker's Repos row each matches (--json: every Repos row too)
|
|
15420
15478
|
crew logbook list [route] recent Agent Log entries, filterable by --role/--ticket
|
|
15421
15479
|
crew logbook show [route] ID [--prompt] one entry; --prompt reconstructs and verifies its prompt
|
|
15422
15480
|
crew passengers [route] sync Host Passengers containers/tunnels once; what the passengers unit invokes
|
|
@@ -17104,7 +17162,7 @@ ${changed2.map((c) => ` - ${c}
|
|
|
17104
17162
|
case "repos": {
|
|
17105
17163
|
const sub = positional[1];
|
|
17106
17164
|
const usage2 = () => {
|
|
17107
|
-
process.stderr.write("crew repos add [workspace/project] [name] [path] [--name N] [--project P] [--dry-run] [--no-create]\ncrew repos clone [workspace/project] <name> [--dir PATH] [--dry-run] [--json]\ncrew repos list <workspace/project
|
|
17165
|
+
process.stderr.write("crew repos add [workspace/project] [name] [path] [--name N] [--project P] [--dry-run] [--no-create]\ncrew repos clone [workspace/project] <name> [--dir PATH] [--dry-run] [--json]\ncrew repos list <workspace/project> [--json]\ncrew repos hooks [workspace/project] <name> [--suggest] [--agent] [--write route|repo] [--recipes ID,ID] [--json]\n");
|
|
17108
17166
|
process.exit(2);
|
|
17109
17167
|
};
|
|
17110
17168
|
if (sub !== "add" && sub !== "list" && sub !== "clone" && sub !== "hooks") usage2();
|
|
@@ -17254,6 +17312,26 @@ ${changed2.map((c) => ` - ${c}
|
|
|
17254
17312
|
const base = dirname19(cfg.configFile);
|
|
17255
17313
|
try {
|
|
17256
17314
|
if (sub === "list") {
|
|
17315
|
+
if (flag("json")) {
|
|
17316
|
+
const rows = listRepoRows({
|
|
17317
|
+
text,
|
|
17318
|
+
route: routeName,
|
|
17319
|
+
base,
|
|
17320
|
+
resolved: resolvedRemotes,
|
|
17321
|
+
originOf,
|
|
17322
|
+
exists: (d) => existsSync31(d),
|
|
17323
|
+
repoHasHooks: (d) => REPO_CONFIG_FILENAMES.some((f) => {
|
|
17324
|
+
try {
|
|
17325
|
+
return Object.keys(parseRepoConfig(readFileSync25(resolvePath(d, f), "utf8"), f).hooks).length > 0;
|
|
17326
|
+
} catch {
|
|
17327
|
+
return false;
|
|
17328
|
+
}
|
|
17329
|
+
})
|
|
17330
|
+
});
|
|
17331
|
+
process.stdout.write(`${JSON.stringify({ route: routeName, repos: rows })}
|
|
17332
|
+
`);
|
|
17333
|
+
break;
|
|
17334
|
+
}
|
|
17257
17335
|
const repos = configuredRepos(text, routeName, base);
|
|
17258
17336
|
if (repos.length === 0) process.stdout.write(`route ${routeName} has no checkout configured \u2014 \`crew repos add ${routeName} <path>\`
|
|
17259
17337
|
`);
|
package/package.json
CHANGED