@tablation/crew 0.79.9 → 0.79.10
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 +55 -25
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4326,7 +4326,7 @@ function reconcileHeldWorktrees(state, repo, log, stillRefused) {
|
|
|
4326
4326
|
}
|
|
4327
4327
|
}
|
|
4328
4328
|
function openShipAttention(state, nowMs = Date.now()) {
|
|
4329
|
-
const stale = staleRelease(state.releaseHeartbeat().at(), nowMs);
|
|
4329
|
+
const stale = state.releaseInProgress() ? null : staleRelease(state.releaseHeartbeat().at(), nowMs);
|
|
4330
4330
|
const stored = state.shipAttention().previous();
|
|
4331
4331
|
return stale ? [...stored, stale] : stored;
|
|
4332
4332
|
}
|
|
@@ -5465,7 +5465,7 @@ var HandoffTranscriptTracker = class {
|
|
|
5465
5465
|
};
|
|
5466
5466
|
|
|
5467
5467
|
// src/pending-handoff.ts
|
|
5468
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync8, readdirSync as
|
|
5468
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync8, readdirSync as readdirSync6, readFileSync as readFileSync13, rmSync as rmSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
5469
5469
|
import { join as join16 } from "path";
|
|
5470
5470
|
|
|
5471
5471
|
// src/ticket-branch.ts
|
|
@@ -5476,7 +5476,7 @@ import { hostname } from "os";
|
|
|
5476
5476
|
import { TablationClient } from "@tablation/client";
|
|
5477
5477
|
|
|
5478
5478
|
// src/state.ts
|
|
5479
|
-
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync12, mkdirSync as mkdirSync7, rmSync as rmSync7, statSync as statSync4 } from "fs";
|
|
5479
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync12, mkdirSync as mkdirSync7, rmSync as rmSync7, statSync as statSync4, readdirSync as readdirSync5 } from "fs";
|
|
5480
5480
|
import { join as join13 } from "path";
|
|
5481
5481
|
var EPOCH = "1970-01-01T00:00:00.000Z";
|
|
5482
5482
|
var State = class _State {
|
|
@@ -5605,6 +5605,35 @@ var State = class _State {
|
|
|
5605
5605
|
}
|
|
5606
5606
|
};
|
|
5607
5607
|
}
|
|
5608
|
+
/**
|
|
5609
|
+
* Whether a release is running right now: any `.release-<scope>.lock` in the
|
|
5610
|
+
* state directory naming a live process (the locks `releasePhase` takes per
|
|
5611
|
+
* scope). A lock naming a dead pid is ignored, as `acquire` ignores it.
|
|
5612
|
+
*/
|
|
5613
|
+
releaseInProgress() {
|
|
5614
|
+
let names;
|
|
5615
|
+
try {
|
|
5616
|
+
names = readdirSync5(this.dir);
|
|
5617
|
+
} catch {
|
|
5618
|
+
return false;
|
|
5619
|
+
}
|
|
5620
|
+
for (const n of names) {
|
|
5621
|
+
if (!/^\.release-.+\.lock$/.test(n)) continue;
|
|
5622
|
+
let pid = 0;
|
|
5623
|
+
try {
|
|
5624
|
+
pid = Number.parseInt(readFileSync12(this.path(n), "utf8").trim(), 10);
|
|
5625
|
+
} catch {
|
|
5626
|
+
continue;
|
|
5627
|
+
}
|
|
5628
|
+
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
5629
|
+
try {
|
|
5630
|
+
process.kill(pid, 0);
|
|
5631
|
+
return true;
|
|
5632
|
+
} catch {
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
return false;
|
|
5636
|
+
}
|
|
5608
5637
|
/**
|
|
5609
5638
|
* Like `acquire`, but for a resource with `max` interchangeable slots
|
|
5610
5639
|
* rather than one exclusive holder — this machine's overall concurrency
|
|
@@ -7519,7 +7548,7 @@ function listPendingHandoffs(stateDir, route) {
|
|
|
7519
7548
|
const dir = pendingDirFor(stateDir);
|
|
7520
7549
|
if (!existsSync15(dir)) return [];
|
|
7521
7550
|
const out = [];
|
|
7522
|
-
for (const f of
|
|
7551
|
+
for (const f of readdirSync6(dir).filter((n) => n.endsWith(".json")).sort()) {
|
|
7523
7552
|
try {
|
|
7524
7553
|
const rec = JSON.parse(readFileSync13(join16(dir, f), "utf8"));
|
|
7525
7554
|
if (rec.version === 1 && rec.ticketRecordId && (!route || rec.route === route)) out.push(rec);
|
|
@@ -7639,7 +7668,7 @@ function expandSkillMarkers(text, lookup, opts = {}) {
|
|
|
7639
7668
|
}
|
|
7640
7669
|
|
|
7641
7670
|
// src/skills.ts
|
|
7642
|
-
import { readFileSync as readFileSync15, readdirSync as
|
|
7671
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync7, existsSync as existsSync17 } from "fs";
|
|
7643
7672
|
import { join as join18 } from "path";
|
|
7644
7673
|
import { parse as parseYaml } from "yaml";
|
|
7645
7674
|
import { TablationClient as TablationClient3, StaleWriteError as StaleWriteError3, TablationApiError as TablationApiError2 } from "@tablation/client";
|
|
@@ -8138,7 +8167,7 @@ function parseSkillFile(path) {
|
|
|
8138
8167
|
function listLocalSkills(promptsDir) {
|
|
8139
8168
|
const dir = join18(promptsDir, "skills");
|
|
8140
8169
|
if (!existsSync17(dir)) return [];
|
|
8141
|
-
return
|
|
8170
|
+
return readdirSync7(dir).filter((f) => f.endsWith(".md")).map((f) => parseSkillFile(join18(dir, f)));
|
|
8142
8171
|
}
|
|
8143
8172
|
async function syncSkills(route, opts) {
|
|
8144
8173
|
if (!route.resolved) {
|
|
@@ -9725,7 +9754,7 @@ async function signOutSessions(o) {
|
|
|
9725
9754
|
}
|
|
9726
9755
|
|
|
9727
9756
|
// src/reset.ts
|
|
9728
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync12, readFileSync as readFileSync19, readdirSync as
|
|
9757
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync12, readFileSync as readFileSync19, readdirSync as readdirSync8, rmSync as rmSync11, statSync as statSync6, writeFileSync as writeFileSync13 } from "fs";
|
|
9729
9758
|
import { dirname as dirname9, join as join22 } from "path";
|
|
9730
9759
|
import { hostFromUrl as hostFromUrl3 } from "@tablation/client";
|
|
9731
9760
|
function clonedCheckoutsFile(stateDir) {
|
|
@@ -9820,7 +9849,7 @@ function removeState(stateDir, dryRun) {
|
|
|
9820
9849
|
const out = [];
|
|
9821
9850
|
const targets = [join22(stateDir, "resolved"), join22(stateDir, "keys"), clonedCheckoutsFile(stateDir), join22(stateDir, "connect-session.json"), join22(stateDir, "reload-requested"), join22(stateDir, "daemon.started")];
|
|
9822
9851
|
try {
|
|
9823
|
-
for (const name of
|
|
9852
|
+
for (const name of readdirSync8(stateDir)) {
|
|
9824
9853
|
if (name.startsWith(".") && statSync6(join22(stateDir, name)).isFile()) targets.push(join22(stateDir, name));
|
|
9825
9854
|
}
|
|
9826
9855
|
} catch {
|
|
@@ -15506,7 +15535,7 @@ function schedulerInstalled(plan, exists, crontab) {
|
|
|
15506
15535
|
}
|
|
15507
15536
|
|
|
15508
15537
|
// src/worktree-sweep.ts
|
|
15509
|
-
import { existsSync as existsSync27, readFileSync as readFileSync25, readdirSync as
|
|
15538
|
+
import { existsSync as existsSync27, readFileSync as readFileSync25, readdirSync as readdirSync9 } from "fs";
|
|
15510
15539
|
import { basename as basename11, dirname as dirname18, join as join30, resolve as resolve4 } from "path";
|
|
15511
15540
|
function planWorktreeSweep(target, tickets, contract) {
|
|
15512
15541
|
const terminal = new Set(contract.statuses.resolved.filter((s) => s !== contract.statuses.verified));
|
|
@@ -15566,7 +15595,7 @@ function siblingWorktreeDirs(target) {
|
|
|
15566
15595
|
const registered = new Set(worktrees(target.dir).map((w) => resolve4(w.path)));
|
|
15567
15596
|
let names;
|
|
15568
15597
|
try {
|
|
15569
|
-
names =
|
|
15598
|
+
names = readdirSync9(parent);
|
|
15570
15599
|
} catch {
|
|
15571
15600
|
return [];
|
|
15572
15601
|
}
|
|
@@ -15782,14 +15811,14 @@ function applyRemoteBranchCleanup(cwd, remote, branches2, dryRun, log) {
|
|
|
15782
15811
|
}
|
|
15783
15812
|
|
|
15784
15813
|
// src/stream-sweep.ts
|
|
15785
|
-
import { existsSync as existsSync28, readdirSync as
|
|
15814
|
+
import { existsSync as existsSync28, readdirSync as readdirSync10, rmSync as rmSync13, statSync as statSync8 } from "fs";
|
|
15786
15815
|
import { join as join31 } from "path";
|
|
15787
15816
|
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
15788
15817
|
function planStreamSweep(stateDir, retentionDays, now = Date.now()) {
|
|
15789
15818
|
const dir = join31(stateDir, "streams");
|
|
15790
15819
|
if (!existsSync28(dir)) return [];
|
|
15791
15820
|
const cutoff = now - retentionDays * DAY_MS2;
|
|
15792
|
-
return
|
|
15821
|
+
return readdirSync10(dir).map((name) => join31(dir, name)).filter((path) => {
|
|
15793
15822
|
try {
|
|
15794
15823
|
return statSync8(path).mtimeMs < cutoff;
|
|
15795
15824
|
} catch {
|
|
@@ -15817,7 +15846,7 @@ function applyStreamSweep(paths, dryRun, log) {
|
|
|
15817
15846
|
function planEventsSweep(stateDir, retentionDays, now = Date.now()) {
|
|
15818
15847
|
if (!existsSync28(stateDir)) return [];
|
|
15819
15848
|
const cutoff = now - retentionDays * DAY_MS2;
|
|
15820
|
-
return
|
|
15849
|
+
return readdirSync10(stateDir).filter((name) => ROTATED_EVENTS_RE.test(name)).map((name) => join31(stateDir, name)).filter((path) => {
|
|
15821
15850
|
try {
|
|
15822
15851
|
return statSync8(path).mtimeMs < cutoff;
|
|
15823
15852
|
} catch {
|
|
@@ -15827,7 +15856,7 @@ function planEventsSweep(stateDir, retentionDays, now = Date.now()) {
|
|
|
15827
15856
|
}
|
|
15828
15857
|
|
|
15829
15858
|
// src/cli.ts
|
|
15830
|
-
import { realpathSync as realpathSync3, readFileSync as readFileSync31, existsSync as existsSync34, mkdirSync as mkdirSync22, writeFileSync as writeFileSync23, rmSync as rmSync15, unlinkSync as unlinkSync5, copyFileSync as copyFileSync2, renameSync as renameSync3, statSync as statSync10, readdirSync as
|
|
15859
|
+
import { realpathSync as realpathSync3, readFileSync as readFileSync31, existsSync as existsSync34, mkdirSync as mkdirSync22, writeFileSync as writeFileSync23, rmSync as rmSync15, unlinkSync as unlinkSync5, copyFileSync as copyFileSync2, renameSync as renameSync3, statSync as statSync10, readdirSync as readdirSync15 } from "fs";
|
|
15831
15860
|
import { createInterface } from "readline/promises";
|
|
15832
15861
|
import { dirname as dirOf, resolve as resolvePath } from "path";
|
|
15833
15862
|
|
|
@@ -16084,7 +16113,7 @@ function syncAllPassengerCheckouts(cfg) {
|
|
|
16084
16113
|
|
|
16085
16114
|
// src/tunnel.ts
|
|
16086
16115
|
import { spawn as spawn5 } from "child_process";
|
|
16087
|
-
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync27, writeFileSync as writeFileSync20, unlinkSync as unlinkSync3, readdirSync as
|
|
16116
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync27, writeFileSync as writeFileSync20, unlinkSync as unlinkSync3, readdirSync as readdirSync11 } from "fs";
|
|
16088
16117
|
import { randomInt } from "crypto";
|
|
16089
16118
|
import { join as join33 } from "path";
|
|
16090
16119
|
var DEFAULT_SPAWN_OPTIONS = { stdio: "ignore", detached: true };
|
|
@@ -16266,7 +16295,7 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
|
|
|
16266
16295
|
function readAllPersistedWorkspaceIds(stateDir) {
|
|
16267
16296
|
const dir = join33(stateDir, "passengers");
|
|
16268
16297
|
if (!existsSync30(dir)) return [];
|
|
16269
|
-
return
|
|
16298
|
+
return readdirSync11(dir).filter((f) => f.endsWith(".json") && !f.endsWith("-sync.json")).map((f) => f.slice(0, -".json".length));
|
|
16270
16299
|
}
|
|
16271
16300
|
|
|
16272
16301
|
// src/mcp-endpoint-registry.ts
|
|
@@ -16386,7 +16415,7 @@ async function unregisterEndpoint(workspaceId, info, d) {
|
|
|
16386
16415
|
import { createServer as createHttpServer } from "http";
|
|
16387
16416
|
import { spawn as spawn6 } from "child_process";
|
|
16388
16417
|
import { randomBytes } from "crypto";
|
|
16389
|
-
import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync28, writeFileSync as writeFileSync21, unlinkSync as unlinkSync4, readdirSync as
|
|
16418
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync28, writeFileSync as writeFileSync21, unlinkSync as unlinkSync4, readdirSync as readdirSync12 } from "fs";
|
|
16390
16419
|
import { join as join34 } from "path";
|
|
16391
16420
|
|
|
16392
16421
|
// src/secret-compare.ts
|
|
@@ -16513,7 +16542,7 @@ function readAllPersistedSyncWorkspaceIds(stateDir) {
|
|
|
16513
16542
|
const dir = join34(stateDir, "passengers");
|
|
16514
16543
|
if (!existsSync31(dir)) return [];
|
|
16515
16544
|
const suffix = "-sync.json";
|
|
16516
|
-
return
|
|
16545
|
+
return readdirSync12(dir).filter((f) => f.endsWith(suffix)).map((f) => f.slice(0, -suffix.length));
|
|
16517
16546
|
}
|
|
16518
16547
|
function syncPassengerSyncDaemons(plans, cfg, stateDir, deps = {}) {
|
|
16519
16548
|
const alive = deps.isPidAlive ?? isPidAlive;
|
|
@@ -16599,11 +16628,11 @@ function describeCause(err) {
|
|
|
16599
16628
|
}
|
|
16600
16629
|
|
|
16601
16630
|
// src/daemon.ts
|
|
16602
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync21, readFileSync as readFileSync30, readdirSync as
|
|
16631
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync21, readFileSync as readFileSync30, readdirSync as readdirSync14, rmSync as rmSync14, statSync as statSync9, writeFileSync as writeFileSync22 } from "fs";
|
|
16603
16632
|
import { join as join36 } from "path";
|
|
16604
16633
|
|
|
16605
16634
|
// src/interrupted.ts
|
|
16606
|
-
import { existsSync as existsSync32, readdirSync as
|
|
16635
|
+
import { existsSync as existsSync32, readdirSync as readdirSync13, readFileSync as readFileSync29 } from "fs";
|
|
16607
16636
|
import { join as join35 } from "path";
|
|
16608
16637
|
var INTERRUPTED_MARKER = calloutHeader("NOTE", "Interrupted");
|
|
16609
16638
|
function interruptedComment(b) {
|
|
@@ -16635,7 +16664,7 @@ function orphanedStreams(o) {
|
|
|
16635
16664
|
if (!existsSync32(dir)) return [];
|
|
16636
16665
|
const ownerAlive = o.isOwnerAlive ?? pidAlive;
|
|
16637
16666
|
const out = [];
|
|
16638
|
-
for (const name of
|
|
16667
|
+
for (const name of readdirSync13(dir)) {
|
|
16639
16668
|
if (!name.endsWith(".jsonl") || name.endsWith(".events.jsonl")) continue;
|
|
16640
16669
|
const streamPath = join35(dir, name);
|
|
16641
16670
|
if (runFinished(streamPath)) continue;
|
|
@@ -16756,7 +16785,7 @@ function latestMtime(path) {
|
|
|
16756
16785
|
if (stat.isFile()) return stat.mtimeMs;
|
|
16757
16786
|
if (!stat.isDirectory()) return 0;
|
|
16758
16787
|
let latest = stat.mtimeMs;
|
|
16759
|
-
for (const entry of
|
|
16788
|
+
for (const entry of readdirSync14(path, { withFileTypes: true })) {
|
|
16760
16789
|
latest = Math.max(latest, latestMtime(join36(path, entry.name)));
|
|
16761
16790
|
}
|
|
16762
16791
|
return latest;
|
|
@@ -17531,6 +17560,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
17531
17560
|
}, releaseRefused = function() {
|
|
17532
17561
|
const why = state.releaseSkipReason();
|
|
17533
17562
|
if (!why) return false;
|
|
17563
|
+
if (!dryRun) state.releaseHeartbeat().touch();
|
|
17534
17564
|
emit.emit(`${why} \u2014 release skipped`, { step: "release" });
|
|
17535
17565
|
return true;
|
|
17536
17566
|
}, doctorMachineId = function(stateDir) {
|
|
@@ -19281,7 +19311,7 @@ ${changed2.map((c) => ` - ${c}
|
|
|
19281
19311
|
if (!existsSync34(dir)) throw new ReposError(`${dir} does not exist on disk`);
|
|
19282
19312
|
const files = { exists: (r) => existsSync34(resolvePath(dir, r)), list: (r) => {
|
|
19283
19313
|
try {
|
|
19284
|
-
return
|
|
19314
|
+
return readdirSync15(resolvePath(dir, r));
|
|
19285
19315
|
} catch {
|
|
19286
19316
|
return [];
|
|
19287
19317
|
}
|
|
@@ -19478,7 +19508,7 @@ ${changed2.map((c) => ` - ${c}
|
|
|
19478
19508
|
` : `${human}
|
|
19479
19509
|
`);
|
|
19480
19510
|
const plan2 = planRepoClone({ text, base, route: routeName, name: addName, resolved: resolvedRemotes, dir: value("dir"), isCheckout });
|
|
19481
|
-
if (existsSync34(plan2.target) && (existsSync34(`${plan2.target}/.git`) ||
|
|
19511
|
+
if (existsSync34(plan2.target) && (existsSync34(`${plan2.target}/.git`) || readdirSync15(plan2.target).length > 0)) {
|
|
19482
19512
|
throw new ReposError(
|
|
19483
19513
|
existsSync34(`${plan2.target}/.git`) ? `${plan2.target} is already a checkout \u2014 attach it with \`crew repos add ${routeName} ${plan2.name} ${plan2.target}\`` : `${plan2.target} exists and is not empty \u2014 pass --dir to clone somewhere else`
|
|
19484
19514
|
);
|
|
@@ -21030,7 +21060,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
21030
21060
|
}
|
|
21031
21061
|
const projectId = route.resolved.areaId ?? resolveRepoProject(await tracker.projectRows(), value("project"));
|
|
21032
21062
|
const fresh = !existsSync34(join37(dir, ".git"));
|
|
21033
|
-
if (existsSync34(dir) && fresh &&
|
|
21063
|
+
if (existsSync34(dir) && fresh && readdirSync15(dir).length > 0) fail(`${dir} exists and is not a git checkout \u2014 move it aside`);
|
|
21034
21064
|
if (dryRun) {
|
|
21035
21065
|
say("dry-run", { dir, newCheckout: fresh, repoRow: row?.id ?? null }, `would ${fresh ? "create" : "reuse"} ${dir}${row ? "" : ", create the Repos row"}, and file one ${tracker.contract.statuses.approved} ticket`);
|
|
21036
21066
|
break;
|
package/package.json
CHANGED