@tablation/crew 0.6.0 → 0.6.1
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/README.md +1 -1
- package/dist/cli.js +48 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -207,7 +207,7 @@ crew ports [route] which checkout owns which ports, and what is up
|
|
|
207
207
|
crew reap [route] kill servers left behind by removed worktrees
|
|
208
208
|
crew drop [route] NNN remove a merged ticket's worktree and branch
|
|
209
209
|
crew sync [route] fast-forward the checkout and its worktrees from the remote
|
|
210
|
-
crew pause|resume [route] [R] pause everything, or
|
|
210
|
+
crew pause|resume [route] [R|release] pause everything, one role, or releases only (passengers keep running)
|
|
211
211
|
crew log [route] tail the log
|
|
212
212
|
crew inbox [--member NAME] your tickets across every workspace
|
|
213
213
|
crew connect WS[/PROJECT] resolve a workspace/project's ids into the state tree
|
package/dist/cli.js
CHANGED
|
@@ -1219,6 +1219,31 @@ var State = class _State {
|
|
|
1219
1219
|
resume(role) {
|
|
1220
1220
|
rmSync(role ? this.path(`.role-paused-${role}`) : this.path(".crew-paused"), { force: true });
|
|
1221
1221
|
}
|
|
1222
|
+
/**
|
|
1223
|
+
* The release phase (merge, deploy, release) has its own sentinel, one
|
|
1224
|
+
* level below the whole-crew pause: `crew pause release` stops shipping
|
|
1225
|
+
* while agents keep working.
|
|
1226
|
+
*/
|
|
1227
|
+
isReleasePaused() {
|
|
1228
|
+
return existsSync3(this.path(".release-paused"));
|
|
1229
|
+
}
|
|
1230
|
+
setReleasePaused(paused) {
|
|
1231
|
+
if (paused) writeFileSync(this.path(".release-paused"), "");
|
|
1232
|
+
else rmSync(this.path(".release-paused"), { force: true });
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Why a release cycle must not run right now, or null when it may. Every
|
|
1236
|
+
* release entry point checks this first — the release timer, `crew release`,
|
|
1237
|
+
* `crew merge`, `crew deploy` and the inline release a `run` cycle used to
|
|
1238
|
+
* do — so a paused ship cannot merge, deploy, or file release alerts.
|
|
1239
|
+
* A release already in flight when the pause lands finishes; only new
|
|
1240
|
+
* cycles are refused.
|
|
1241
|
+
*/
|
|
1242
|
+
releaseSkipReason() {
|
|
1243
|
+
if (this.isPaused()) return "the crew is paused";
|
|
1244
|
+
if (this.isReleasePaused()) return "releases are paused";
|
|
1245
|
+
return null;
|
|
1246
|
+
}
|
|
1222
1247
|
/**
|
|
1223
1248
|
* Take an exclusive lock, or report who holds it.
|
|
1224
1249
|
*
|
|
@@ -8525,6 +8550,7 @@ var SpawnBreaker = class {
|
|
|
8525
8550
|
}
|
|
8526
8551
|
};
|
|
8527
8552
|
async function runOnePass(o) {
|
|
8553
|
+
if (o.state.isPaused()) return { pending: [], started: [], skipped: [] };
|
|
8528
8554
|
await hydrateApiKeys([o.route], o.getSessionStore);
|
|
8529
8555
|
const emit = o.newEmitter();
|
|
8530
8556
|
const decide = o.decide ?? decideCycle;
|
|
@@ -8852,7 +8878,8 @@ function usage() {
|
|
|
8852
8878
|
crew rotate-passenger-url [route] force a Host Passengers tunnel to reconnect with a fresh public URL
|
|
8853
8879
|
crew unassign [route] NNN hand back a session's ticket \u2014 clears assignee, next cycle picks it up
|
|
8854
8880
|
crew sync [route] fast-forward the checkout and its worktrees from the remote
|
|
8855
|
-
crew pause|resume [route] [R] pause everything, or
|
|
8881
|
+
crew pause|resume [route] [R|release] pause everything, one role, or releases only (merge/deploy/release; passengers keeps running).
|
|
8882
|
+
resume with no argument clears only the whole-crew pause; a role or release pause needs its own resume
|
|
8856
8883
|
crew log [route] tail the log
|
|
8857
8884
|
crew inbox [--member NAME] your tickets across every workspace (or a colleague's)
|
|
8858
8885
|
crew connect resolve a workspace's ids into a crew.yaml block
|
|
@@ -8953,6 +8980,11 @@ if (command === "passenger-sync-daemon") {
|
|
|
8953
8980
|
urlFor: (slug) => publicUrlFor(slug, relayHost, cfg.ship.relayHttpPort, cfg.ship.relayPublicDomain),
|
|
8954
8981
|
warn: (m) => emit.warn(m, { step: "passengers" })
|
|
8955
8982
|
};
|
|
8983
|
+
}, releaseRefused = function() {
|
|
8984
|
+
const why = state.releaseSkipReason();
|
|
8985
|
+
if (!why) return false;
|
|
8986
|
+
emit.emit(`${why} \u2014 release skipped`, { step: "release" });
|
|
8987
|
+
return true;
|
|
8956
8988
|
}, reportUnplaceable = function(c, unplaceable, verified, emit2) {
|
|
8957
8989
|
if (unplaceableReported.has(c.route)) return;
|
|
8958
8990
|
unplaceableReported.add(c.route);
|
|
@@ -8961,7 +8993,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
8961
8993
|
else emit2.emit(note.message, { step: "release" });
|
|
8962
8994
|
}
|
|
8963
8995
|
};
|
|
8964
|
-
requireArmed2 = requireArmed, parseTicketNumber2 = parseTicketNumber, passengerApiKeys2 = passengerApiKeys, endpointApiFor2 = endpointApiFor, endpointReconcileDeps2 = endpointReconcileDeps, reportUnplaceable2 = reportUnplaceable;
|
|
8996
|
+
requireArmed2 = requireArmed, parseTicketNumber2 = parseTicketNumber, passengerApiKeys2 = passengerApiKeys, endpointApiFor2 = endpointApiFor, endpointReconcileDeps2 = endpointReconcileDeps, releaseRefused2 = releaseRefused, reportUnplaceable2 = reportUnplaceable;
|
|
8965
8997
|
let cfg;
|
|
8966
8998
|
let firstRun;
|
|
8967
8999
|
try {
|
|
@@ -9003,7 +9035,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
9003
9035
|
const releaseFleetWide = ["merge", "deploy", "release"].includes(command) && flag("fleet");
|
|
9004
9036
|
const DAEMON_SUBCOMMANDS = /* @__PURE__ */ new Set(["start", "stop", "status", "restart"]);
|
|
9005
9037
|
const named = command === "daemon" && DAEMON_SUBCOMMANDS.has(positional[1] ?? "") ? positional[2] : positional[1];
|
|
9006
|
-
const fleetWide = command === "inbox" || command === "connect" || command === "agents" || command === "skills" || command === "logbook" || command === "repos" || releaseFleetWide || FLEET_CAPABLE.has(command) && !named && cfg.routes.length > 1;
|
|
9038
|
+
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;
|
|
9007
9039
|
let route;
|
|
9008
9040
|
try {
|
|
9009
9041
|
route = fleetWide ? cfg.routes[0] : findRoute(cfg, named);
|
|
@@ -9093,6 +9125,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
9093
9125
|
}
|
|
9094
9126
|
}
|
|
9095
9127
|
async function releaseFleet(opts = {}) {
|
|
9128
|
+
if (releaseRefused()) return;
|
|
9096
9129
|
const summaries = [];
|
|
9097
9130
|
if (!dryRun) state.releaseHeartbeat().touch();
|
|
9098
9131
|
for (const c of cfg.routes) {
|
|
@@ -9103,6 +9136,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
9103
9136
|
if (!dryRun) state.releaseHeartbeat().touch();
|
|
9104
9137
|
}
|
|
9105
9138
|
async function releaseTargets(opts = {}) {
|
|
9139
|
+
if (releaseRefused()) return;
|
|
9106
9140
|
const only = value("repo");
|
|
9107
9141
|
const targets = reposOf(route);
|
|
9108
9142
|
const chosen = only ? targets.filter((t) => t.name === only) : targets;
|
|
@@ -11022,6 +11056,12 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
11022
11056
|
}
|
|
11023
11057
|
case "pause":
|
|
11024
11058
|
case "resume": {
|
|
11059
|
+
if (positional[1] === "release" || positional[2] === "release") {
|
|
11060
|
+
state.setReleasePaused(command === "pause");
|
|
11061
|
+
process.stdout.write(`${command}d releases
|
|
11062
|
+
`);
|
|
11063
|
+
break;
|
|
11064
|
+
}
|
|
11025
11065
|
const role = positional[2] ?? (["dev", "design", "qa"].includes(positional[1] ?? "") ? positional[1] : void 0);
|
|
11026
11066
|
if (command === "pause") state.pause(role);
|
|
11027
11067
|
else state.resume(role);
|
|
@@ -11113,6 +11153,9 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
11113
11153
|
},
|
|
11114
11154
|
crew: {
|
|
11115
11155
|
paused: state.isPaused(),
|
|
11156
|
+
// The release timer honors the whole-crew pause too, so this is
|
|
11157
|
+
// true whenever releases are stopped for either reason.
|
|
11158
|
+
releasePaused: state.releaseSkipReason() !== null,
|
|
11116
11159
|
roles: ROLE_NAMES.map((r) => ({ name: r, label: ROLE_LABEL[r], paused: state.isRolePaused(r) })),
|
|
11117
11160
|
seats: seats2
|
|
11118
11161
|
},
|
|
@@ -11156,6 +11199,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
11156
11199
|
route: ${route.route} -> ${route.dir}
|
|
11157
11200
|
enabled: ${route.enabled}
|
|
11158
11201
|
crew: ${state.isPaused() ? "paused" : "active"}
|
|
11202
|
+
release: ${state.releaseSkipReason() ? "paused" : "active"}
|
|
11159
11203
|
watermark: ${state.watermark()}
|
|
11160
11204
|
`
|
|
11161
11205
|
);
|
|
@@ -11357,4 +11401,5 @@ var parseTicketNumber2;
|
|
|
11357
11401
|
var passengerApiKeys2;
|
|
11358
11402
|
var endpointApiFor2;
|
|
11359
11403
|
var endpointReconcileDeps2;
|
|
11404
|
+
var releaseRefused2;
|
|
11360
11405
|
var reportUnplaceable2;
|
package/package.json
CHANGED