@tablation/crew 0.23.0 → 0.24.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
CHANGED
|
@@ -7684,6 +7684,45 @@ Still failing: ${n.detail ?? n.headline}`, memberId);
|
|
|
7684
7684
|
}
|
|
7685
7685
|
}
|
|
7686
7686
|
|
|
7687
|
+
// src/projects-cmd.ts
|
|
7688
|
+
async function buildProjectsReport(routes, open) {
|
|
7689
|
+
return Promise.all(routes.map(async (r) => {
|
|
7690
|
+
const areaId = r.areaId ?? null;
|
|
7691
|
+
try {
|
|
7692
|
+
const rows = await open(r.route).projectRowsWithModes();
|
|
7693
|
+
return {
|
|
7694
|
+
route: r.route,
|
|
7695
|
+
areaId,
|
|
7696
|
+
projects: rows.map((p) => ({
|
|
7697
|
+
id: p.id,
|
|
7698
|
+
name: p.name ?? p.id,
|
|
7699
|
+
issuePrefix: p.issue_prefix ?? null,
|
|
7700
|
+
workMode: p.mode,
|
|
7701
|
+
current: p.id === areaId
|
|
7702
|
+
}))
|
|
7703
|
+
};
|
|
7704
|
+
} catch (e) {
|
|
7705
|
+
return { route: r.route, areaId, error: e.message };
|
|
7706
|
+
}
|
|
7707
|
+
}));
|
|
7708
|
+
}
|
|
7709
|
+
function formatProjectsReport(report) {
|
|
7710
|
+
const lines = [];
|
|
7711
|
+
for (const r of report) {
|
|
7712
|
+
lines.push(`route ${r.route}`);
|
|
7713
|
+
if ("error" in r) {
|
|
7714
|
+
lines.push(` error: ${r.error}`);
|
|
7715
|
+
continue;
|
|
7716
|
+
}
|
|
7717
|
+
if (r.projects.length === 0) lines.push(" (no projects readable)");
|
|
7718
|
+
for (const p of r.projects) {
|
|
7719
|
+
lines.push(` ${p.current ? "*" : " "} ${p.name} ${p.issuePrefix ?? "-"} ${p.workMode} ${p.id}`);
|
|
7720
|
+
}
|
|
7721
|
+
}
|
|
7722
|
+
return `${lines.join("\n")}
|
|
7723
|
+
`;
|
|
7724
|
+
}
|
|
7725
|
+
|
|
7687
7726
|
// src/cli.ts
|
|
7688
7727
|
import { StaleWriteError as StaleWriteError8 } from "@tablation/client";
|
|
7689
7728
|
|
|
@@ -10522,6 +10561,7 @@ function usage() {
|
|
|
10522
10561
|
crew deploy [route] release now, even with nothing new to merge
|
|
10523
10562
|
crew watch [route] live view of what the crew is doing
|
|
10524
10563
|
crew status [route] [--json] paused/running state; --json for a machine reader
|
|
10564
|
+
crew projects [--route R] [--json] the Projects rows each route can read (id, name, prefix, work mode)
|
|
10525
10565
|
crew doctor [route] [--fix] preflight; --fix enables clean routes and offers crew install
|
|
10526
10566
|
crew ports [route] which checkout owns which ports, and what is up
|
|
10527
10567
|
crew reap [route] kill orphaned servers, drop worktrees for closed tickets
|
|
@@ -10685,7 +10725,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
10685
10725
|
const releaseFleetWide = ["merge", "deploy", "release"].includes(command) && flag("fleet");
|
|
10686
10726
|
const DAEMON_SUBCOMMANDS = /* @__PURE__ */ new Set(["start", "stop", "status", "restart"]);
|
|
10687
10727
|
const named = command === "daemon" && DAEMON_SUBCOMMANDS.has(positional[1] ?? "") ? positional[2] : positional[1];
|
|
10688
|
-
const fleetWide = command === "inbox" || command === "connect" || command === "agents" || command === "skills" || command === "logbook" || command === "repos" || releaseFleetWide || command === "pause" || command === "resume" || FLEET_CAPABLE.has(command) && !named && cfg.routes.length > 1;
|
|
10728
|
+
const fleetWide = command === "inbox" || command === "connect" || command === "agents" || command === "skills" || command === "logbook" || command === "repos" || command === "projects" || releaseFleetWide || command === "pause" || command === "resume" || FLEET_CAPABLE.has(command) && !named && cfg.routes.length > 1;
|
|
10689
10729
|
let route;
|
|
10690
10730
|
try {
|
|
10691
10731
|
route = fleetWide ? cfg.routes[0] : findRoute(cfg, named);
|
|
@@ -13000,6 +13040,23 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
13000
13040
|
}
|
|
13001
13041
|
break;
|
|
13002
13042
|
}
|
|
13043
|
+
case "projects": {
|
|
13044
|
+
const only = value("route") ?? positional[1];
|
|
13045
|
+
const wanted = only ? cfg.routes.filter((r) => r.route === only) : cfg.routes;
|
|
13046
|
+
if (only && wanted.length === 0) {
|
|
13047
|
+
process.stderr.write(`crew projects: no route "${only}" (have: ${cfg.routes.map((r) => r.route).join(", ")})
|
|
13048
|
+
`);
|
|
13049
|
+
process.exit(2);
|
|
13050
|
+
}
|
|
13051
|
+
const report = await buildProjectsReport(
|
|
13052
|
+
wanted.map((r) => ({ route: r.route, areaId: r.resolved?.areaId })),
|
|
13053
|
+
(name) => new Tracker(wanted.find((r) => r.route === name), cfg.ship)
|
|
13054
|
+
);
|
|
13055
|
+
process.stdout.write(flag("json") ? `${JSON.stringify({ routes: report }, null, 2)}
|
|
13056
|
+
` : formatProjectsReport(report));
|
|
13057
|
+
if (report.length > 0 && report.every((r) => "error" in r)) process.exitCode = 1;
|
|
13058
|
+
break;
|
|
13059
|
+
}
|
|
13003
13060
|
case "status": {
|
|
13004
13061
|
const fairness = state.fairness(route.route);
|
|
13005
13062
|
const waiting = fairness.waiting();
|
package/package.json
CHANGED
|
@@ -148,7 +148,7 @@ human review, so "probably fine" is not a pass.
|
|
|
148
148
|
branch you expected. A person built it; the operator has to push it.
|
|
149
149
|
- **It doesn't** → `status` = `in_progress`, `assignee_id` = the building
|
|
150
150
|
lane's own Crew row id from the roster above — the dev seat if
|
|
151
|
-
`needs_design` is false or null, the design seat if true. **
|
|
151
|
+
`needs_design` is false or null, the design seat if true. **Exceptions:** in a `hybrid` project (the digest's `mode` column) an unassigned ticket is off limits to every lane, so clearing the assignee would strand the bounce: assign the building seat on this ship (ids under "Seats on this ship" in the Environment section, else the roster) and, if the Issues table has a `held_by_ship_id` column, still clear that. In an `automatic` project, when the Issues table has a `held_by_ship_id` column, **clear** `assignee_id` *and* `held_by_ship_id` instead of naming a seat — the
|
|
152
152
|
hold on a `qa` ticket is yours, as verifier, and seats are per ship, so
|
|
153
153
|
naming this ship's seat would hand the bounce to a ship that never built
|
|
154
154
|
it. An unassigned, unheld `in_progress` ticket is picked up by whichever
|
|
@@ -134,7 +134,7 @@ human review, so "probably fine" is not a pass.
|
|
|
134
134
|
builder: set `needs_info` and assign the operator, with a comment naming the
|
|
135
135
|
branch you expected. A person built it; the operator has to push it.
|
|
136
136
|
- **It doesn't** → `status` = `in_progress`, `assignee_id` = the dev
|
|
137
|
-
seat's own Crew row id from the roster above. **
|
|
137
|
+
seat's own Crew row id from the roster above. **Exceptions:** in a `hybrid` project (the digest's `mode` column) an unassigned ticket is off limits to every lane, so clearing the assignee would strand the bounce: assign the building seat on this ship (ids under "Seats on this ship" in the Environment section, else the roster) and, if the Issues table has a `held_by_ship_id` column, still clear that. In an `automatic` project, when the Issues table has a `held_by_ship_id` column, **clear** `assignee_id` *and* `held_by_ship_id` instead of naming a seat — the
|
|
138
138
|
hold on a `qa` ticket is yours, as verifier, and seats are per ship, so
|
|
139
139
|
naming this ship's seat would hand the bounce to a ship that never built
|
|
140
140
|
it. An unassigned, unheld `in_progress` ticket is picked up by whichever
|