@pitboss/cli 0.4.13 → 0.4.14

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
@@ -18006,11 +18006,26 @@ var dist_default7 = createPrompt((config, done) => {
18006
18006
  // src/config.ts
18007
18007
  import { homedir } from "node:os";
18008
18008
  import { join, dirname } from "node:path";
18009
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync, existsSync, renameSync, rmSync as rmSync2, lstatSync, statSync } from "node:fs";
18009
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync, existsSync, renameSync, rmSync as rmSync2, lstatSync, statSync, readdirSync } from "node:fs";
18010
18010
  import { randomBytes } from "node:crypto";
18011
18011
  var configDirOverride = () => process.env.PITBOSS_CONFIG_DIR || process.env.RELAI_CONFIG_DIR || void 0;
18012
+ function defaultConfigRoot() {
18013
+ const shipster = join(homedir(), ".config", "shipster");
18014
+ const pitboss = join(homedir(), ".config", "pitboss");
18015
+ if (existsSync(join(shipster, "config.json"))) return shipster;
18016
+ if (existsSync(join(pitboss, "config.json")) || existsSync(join(pitboss, "agents.json"))) return pitboss;
18017
+ if (existsSync(shipster)) return shipster;
18018
+ return dirHasEntries(pitboss) ? pitboss : shipster;
18019
+ }
18020
+ function dirHasEntries(dir) {
18021
+ try {
18022
+ return readdirSync(dir).length > 0;
18023
+ } catch {
18024
+ return false;
18025
+ }
18026
+ }
18012
18027
  function configDir() {
18013
- return configDirOverride() ?? join(homedir(), ".config", "pitboss");
18028
+ return configDirOverride() ?? defaultConfigRoot();
18014
18029
  }
18015
18030
  function configPath() {
18016
18031
  return join(configDir(), "config.json");
@@ -18984,7 +18999,7 @@ import { join as join4 } from "node:path";
18984
18999
 
18985
19000
  // src/lib/wake.ts
18986
19001
  import { execFileSync } from "node:child_process";
18987
- import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, realpathSync, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
19002
+ import { mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync3, realpathSync, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
18988
19003
  import { createHash, randomBytes as randomBytes2 } from "node:crypto";
18989
19004
  import { join as join2, resolve } from "node:path";
18990
19005
  var EVENT_ID = /^evt_[A-Za-z0-9_-]{1,64}$/;
@@ -19098,7 +19113,7 @@ function resetFollowups(dir, key) {
19098
19113
  function resetAgentFollowups(dir, agentId) {
19099
19114
  let names2;
19100
19115
  try {
19101
- names2 = readdirSync(dir);
19116
+ names2 = readdirSync2(dir);
19102
19117
  } catch {
19103
19118
  return;
19104
19119
  }
@@ -19128,7 +19143,7 @@ function psCommand(pid) {
19128
19143
  function watcherAlive(dir, key, { commandOf = psCommand } = {}) {
19129
19144
  let names2;
19130
19145
  try {
19131
- names2 = readdirSync(dir);
19146
+ names2 = readdirSync2(dir);
19132
19147
  } catch {
19133
19148
  return false;
19134
19149
  }
@@ -19833,12 +19848,11 @@ async function cloneFromBase(run4, base2, dest, repoUrl, env2, opts) {
19833
19848
  }
19834
19849
 
19835
19850
  // src/lib/agents-state.ts
19836
- import { homedir as homedir3 } from "node:os";
19837
19851
  import { join as join5, resolve as resolve2, dirname as dirname2 } from "node:path";
19838
19852
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync3, realpathSync as realpathSync2 } from "node:fs";
19839
19853
  var stateOverridden = () => Boolean(process.env.PITBOSS_AGENTS_STATE || process.env.RELAI_AGENTS_STATE);
19840
19854
  function statePath() {
19841
- return process.env.PITBOSS_AGENTS_STATE || process.env.RELAI_AGENTS_STATE || join5(homedir3(), ".config", "pitboss", "agents.json");
19855
+ return process.env.PITBOSS_AGENTS_STATE || process.env.RELAI_AGENTS_STATE || join5(defaultConfigRoot(), "agents.json");
19842
19856
  }
19843
19857
  function agentsStatePath() {
19844
19858
  return statePath();
@@ -20188,7 +20202,7 @@ function logoutCommand(opts = {}) {
20188
20202
  // src/commands/join.ts
20189
20203
  import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync8, appendFileSync, realpathSync as realpathSync3 } from "node:fs";
20190
20204
  import { dirname as dirname5, join as join8 } from "node:path";
20191
- import { homedir as homedir4 } from "node:os";
20205
+ import { homedir as homedir3 } from "node:os";
20192
20206
 
20193
20207
  // src/lib/mcp-entry.ts
20194
20208
  var MCP_SERVER_ENTRY = {
@@ -20505,7 +20519,7 @@ async function run(opts) {
20505
20519
  const api = (opts.api ?? DEFAULT_API).replace(/\/+$/, "");
20506
20520
  const cwd = process.cwd();
20507
20521
  const { root, remote, repoName } = describeRepo(cwd);
20508
- const home = homedir4();
20522
+ const home = homedir3();
20509
20523
  const host = detectHostRuntime();
20510
20524
  console.log(source_default.bold("\npitboss join\n"));
20511
20525
  console.log(` Repo ${source_default.cyan(repoName)}${remote ? source_default.dim(` (${remote})`) : ""}`);
@@ -21586,7 +21600,8 @@ function plannedCount({ budgetMs, workers, baselineMs }) {
21586
21600
  }
21587
21601
 
21588
21602
  // src/mutate/config.ts
21589
- var CONFIG_PATH = ".pitboss/mutate.json";
21603
+ var CONFIG_PATH = ".shipster/mutate.json";
21604
+ var LEGACY_CONFIG_PATH = ".pitboss/mutate.json";
21590
21605
  function globToRegExp(glob) {
21591
21606
  let out = "";
21592
21607
  for (let i = 0; i < glob.length; i++) {
@@ -21602,30 +21617,30 @@ function globToRegExp(glob) {
21602
21617
  return new RegExp(`^${out}$`);
21603
21618
  }
21604
21619
  var strings = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string" && v.length > 0) : [];
21605
- function parseMutateConfig(text) {
21620
+ function parseMutateConfig(text, label = CONFIG_PATH) {
21606
21621
  const fallback2 = { riskyPatterns: PRIORITY_PATTERNS, paths: [], pool: null };
21607
21622
  if (text === null) return fallback2;
21608
21623
  let raw;
21609
21624
  try {
21610
21625
  raw = JSON.parse(text);
21611
21626
  } catch {
21612
- throw new Error(`${CONFIG_PATH} is not valid JSON`);
21627
+ throw new Error(`${label} is not valid JSON`);
21613
21628
  }
21614
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new Error(`${CONFIG_PATH} must be a JSON object`);
21629
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new Error(`${label} must be a JSON object`);
21615
21630
  const obj = raw;
21616
21631
  const risky = strings(obj.risky);
21617
21632
  const pool = obj.pool;
21618
21633
  let hook2 = null;
21619
21634
  if (pool && typeof pool === "object") {
21620
- if (typeof pool.module !== "string" || pool.module.length === 0) throw new Error(`${CONFIG_PATH}: pool.module must be a path`);
21635
+ if (typeof pool.module !== "string" || pool.module.length === 0) throw new Error(`${label}: pool.module must be a path`);
21621
21636
  const workers = typeof pool.workers === "number" && Number.isInteger(pool.workers) && pool.workers >= 1 ? Math.min(pool.workers, 16) : 1;
21622
21637
  hook2 = { module: pool.module, workers };
21623
21638
  }
21624
21639
  return { riskyPatterns: risky.length > 0 ? risky.map(globToRegExp) : PRIORITY_PATTERNS, paths: strings(obj.paths), pool: hook2 };
21625
21640
  }
21626
21641
  function loadMutateConfig(root) {
21627
- const file = join12(root, CONFIG_PATH);
21628
- return parseMutateConfig(existsSync7(file) ? readFileSync11(file, "utf8") : null);
21642
+ const rel = [CONFIG_PATH, LEGACY_CONFIG_PATH].find((p) => existsSync7(join12(root, p)));
21643
+ return parseMutateConfig(rel ? readFileSync11(join12(root, rel), "utf8") : null, rel ?? CONFIG_PATH);
21629
21644
  }
21630
21645
  var VITEST_CONFIGS = ["vitest.config.ts", "vitest.config.mts", "vitest.config.js", "vitest.config.mjs"];
21631
21646
  function findPackageDir(root, file, exists = existsSync7) {
@@ -22328,7 +22343,7 @@ async function mutateDiffCommand(opts) {
22328
22343
  // src/commands/onboard.ts
22329
22344
  import { execFileSync as execFileSync10 } from "node:child_process";
22330
22345
  import { accessSync, constants, existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync16, realpathSync as realpathSync6, writeFileSync as writeFileSync13 } from "node:fs";
22331
- import { homedir as homedir7 } from "node:os";
22346
+ import { homedir as homedir6 } from "node:os";
22332
22347
  import { delimiter, join as join22 } from "node:path";
22333
22348
  import { createInterface as createInterface2 } from "node:readline/promises";
22334
22349
 
@@ -22867,7 +22882,7 @@ var GIT_TIMEOUT_MS = 5e3;
22867
22882
  var LESSONS_MAX_BUFFER = 64 * 1024;
22868
22883
  var TREE_MAX_BUFFER = 32 * 1024 * 1024;
22869
22884
  var MAX_TREE_ENTRIES = 2e5;
22870
- var LESSONS_PATH = ".pitboss/lessons.md";
22885
+ var LESSONS_PATHS = [".shipster/lessons.md", ".pitboss/lessons.md"];
22871
22886
  var BRANCH_RE = /^[A-Za-z0-9._/-]{1,100}$/;
22872
22887
  var SHA_RE = /^[0-9a-f]{40}$/;
22873
22888
  var BLOB_MODES = /* @__PURE__ */ new Set(["100644", "100755"]);
@@ -22919,25 +22934,31 @@ function entryFor(repoPath, sha) {
22919
22934
  }
22920
22935
  return entry;
22921
22936
  }
22922
- async function readLessons(repoPath, exec4, resolved) {
22923
- const ref = resolved.sha;
22937
+ async function blobAt(exec4, repoPath, ref, path3) {
22924
22938
  let listing;
22925
22939
  try {
22926
- listing = await git2(exec4, repoPath, ["ls-tree", "-z", ref, "--", LESSONS_PATH]);
22940
+ listing = await git2(exec4, repoPath, ["ls-tree", "-z", ref, "--", path3]);
22927
22941
  } catch {
22928
22942
  return null;
22929
22943
  }
22930
22944
  const row = listing.split("\0").find((r) => r !== "");
22931
- const match = row?.match(/^(\d{6}) (\w+) ([0-9a-f]{40})\t(.+)$/);
22932
- if (!match || match[4] !== LESSONS_PATH || match[2] !== "blob" || !BLOB_MODES.has(match[1])) return null;
22933
- let text;
22945
+ if (!row) return void 0;
22946
+ const match = row.match(/^(\d{6}) (\w+) ([0-9a-f]{40})\t(.+)$/);
22947
+ if (!match || match[4] !== path3 || match[2] !== "blob" || !BLOB_MODES.has(match[1])) return null;
22934
22948
  try {
22935
- text = await git2(exec4, repoPath, ["cat-file", "blob", match[3]]);
22949
+ return await git2(exec4, repoPath, ["cat-file", "blob", match[3]]);
22936
22950
  } catch {
22937
22951
  return null;
22938
22952
  }
22939
- if (text.includes("\0")) return null;
22940
- return { text, branch: resolved.branch, sha: resolved.sha };
22953
+ }
22954
+ async function readLessons(repoPath, exec4, resolved) {
22955
+ for (const path3 of LESSONS_PATHS) {
22956
+ const text = await blobAt(exec4, repoPath, resolved.sha, path3);
22957
+ if (text === void 0) continue;
22958
+ if (text === null || text.includes("\0")) return null;
22959
+ return { text, branch: resolved.branch, sha: resolved.sha };
22960
+ }
22961
+ return null;
22941
22962
  }
22942
22963
  async function loadLessons(repoPath, exec4) {
22943
22964
  const resolved = await resolveDefaultBranch(repoPath, exec4);
@@ -23950,7 +23971,7 @@ function grantFromEnv(env2 = process.env) {
23950
23971
  }
23951
23972
 
23952
23973
  // ../claude-worker/src/capacity-store.ts
23953
- import { existsSync as existsSync9, mkdirSync as mkdirSync8, readdirSync as readdirSync2, readFileSync as readFileSync14, renameSync as renameSync4, writeFileSync as writeFileSync9 } from "node:fs";
23974
+ import { existsSync as existsSync9, mkdirSync as mkdirSync8, readdirSync as readdirSync3, readFileSync as readFileSync14, renameSync as renameSync4, writeFileSync as writeFileSync9 } from "node:fs";
23954
23975
  import { join as join14 } from "node:path";
23955
23976
  import { randomBytes as randomBytes6 } from "node:crypto";
23956
23977
 
@@ -24043,7 +24064,7 @@ function readCapacity(dir, now) {
24043
24064
  if (!existsSync9(dir)) return out;
24044
24065
  let names2;
24045
24066
  try {
24046
- names2 = readdirSync2(dir);
24067
+ names2 = readdirSync3(dir);
24047
24068
  } catch {
24048
24069
  return out;
24049
24070
  }
@@ -24502,10 +24523,10 @@ var copilotAdapter = {
24502
24523
  // ../claude-worker/src/adapters/codex.ts
24503
24524
  import { spawn as spawn6 } from "child_process";
24504
24525
  import { chmodSync, mkdirSync as mkdirSync9, unlinkSync as unlinkSync3, writeFileSync as writeFileSync11 } from "fs";
24505
- import { homedir as homedir5 } from "os";
24526
+ import { homedir as homedir4 } from "os";
24506
24527
  import { join as join17 } from "path";
24507
24528
  var bin3 = () => process.env.CODEX_BIN ?? "codex";
24508
- var codexHome = () => process.env.CODEX_HOME ?? join17(homedir5(), ".codex");
24529
+ var codexHome = () => process.env.CODEX_HOME ?? join17(homedir4(), ".codex");
24509
24530
  var QUOTA2 = [/usage limit/i, /rate limit reached for/i, /upgrade to (plus|pro)/i];
24510
24531
  var CREDENTIALS = [/not logged in/i, /codex login/i, /401 unauthorized/i];
24511
24532
  function codexArgs(repoPath, prompt, profile, model) {
@@ -24843,7 +24864,7 @@ function originHost(origin) {
24843
24864
 
24844
24865
  // src/node/spec.ts
24845
24866
  import { existsSync as existsSync11, realpathSync as realpathSync4, statSync as statSync2 } from "node:fs";
24846
- import { homedir as homedir6 } from "node:os";
24867
+ import { homedir as homedir5 } from "node:os";
24847
24868
  import { join as join19, parse as parsePath, resolve as resolve7, sep as sep2 } from "node:path";
24848
24869
  var DEFAULT_API2 = "https://api.pitboss.dev";
24849
24870
  var MAX_POOL_SIZE = 32;
@@ -25149,7 +25170,7 @@ function parseSpec(text, specDir, opts = {}) {
25149
25170
  worktrees.set(a.worktree, a.name);
25150
25171
  }
25151
25172
  if (body.janitorEnabled !== void 0 && typeof body.janitorEnabled !== "boolean") throw new Error("janitorEnabled must be true or false");
25152
- const janitor = body.janitorRoots === void 0 ? void 0 : janitorRootsOf(body.janitorRoots, specDir, agents, pools, opts.homeDir ?? homedir6());
25173
+ const janitor = body.janitorRoots === void 0 ? void 0 : janitorRootsOf(body.janitorRoots, specDir, agents, pools, opts.homeDir ?? homedir5());
25153
25174
  return {
25154
25175
  api: api.replace(/\/+$/, ""),
25155
25176
  agents,
@@ -25161,7 +25182,7 @@ function parseSpec(text, specDir, opts = {}) {
25161
25182
  }
25162
25183
 
25163
25184
  // src/node/store.ts
25164
- import { existsSync as existsSync12, mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as readFileSync15, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
25185
+ import { existsSync as existsSync12, mkdirSync as mkdirSync10, readdirSync as readdirSync4, readFileSync as readFileSync15, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
25165
25186
  import { dirname as dirname10, join as join20 } from "node:path";
25166
25187
  import { randomBytes as randomBytes7 } from "node:crypto";
25167
25188
  var nodeDir = () => join20(configDir(), "node");
@@ -25201,7 +25222,7 @@ var removeCreds = (name) => {
25201
25222
  var listStoredAgentNames = () => {
25202
25223
  const dir = join20(nodeDir(), "agents");
25203
25224
  if (!existsSync12(dir)) return [];
25204
- return readdirSync3(dir).filter((n) => n.endsWith(".json")).map((n) => n.slice(0, -".json".length)).sort();
25225
+ return readdirSync4(dir).filter((n) => n.endsWith(".json")).map((n) => n.slice(0, -".json".length)).sort();
25205
25226
  };
25206
25227
  var readState = () => readJson2(statePath2());
25207
25228
  function readRetirePending() {
@@ -25735,7 +25756,7 @@ async function onboardCommand(url, opts) {
25735
25756
  rl?.close();
25736
25757
  }
25737
25758
  const plan2 = planOnboard(url, {
25738
- home: homedir7(),
25759
+ home: homedir6(),
25739
25760
  parent: opts.dir,
25740
25761
  architect: roles.architect,
25741
25762
  writer: roles.writer,
@@ -25855,10 +25876,10 @@ async function fetchPoolSize(creds, name) {
25855
25876
  }
25856
25877
 
25857
25878
  // src/node/owner-pool.ts
25858
- import { chmodSync as chmodSync2, existsSync as existsSync15, lstatSync as lstatSync4, mkdirSync as mkdirSync13, readdirSync as readdirSync4, readFileSync as readFileSync18, realpathSync as realpathSync7, rmSync as rmSync7 } from "node:fs";
25879
+ import { chmodSync as chmodSync2, existsSync as existsSync15, lstatSync as lstatSync4, mkdirSync as mkdirSync13, readdirSync as readdirSync5, readFileSync as readFileSync18, realpathSync as realpathSync7, rmSync as rmSync7 } from "node:fs";
25859
25880
  import { basename as basename4, dirname as dirname12, join as join24, resolve as resolve9 } from "node:path";
25860
25881
  import { execFileSync as execFileSync12, spawnSync as spawnSync2 } from "node:child_process";
25861
- import { homedir as homedir8 } from "node:os";
25882
+ import { homedir as homedir7 } from "node:os";
25862
25883
 
25863
25884
  // src/node/runas.ts
25864
25885
  import { execFileSync as execFileSync11 } from "node:child_process";
@@ -26049,7 +26070,7 @@ var GIT_ENV_PREFIX = Object.entries(SLOT_GIT_ENV).map(([k, v]) => `${k}=${v}`).j
26049
26070
  var SEAT_RESET_SCRIPT = `chmod -R u+rwX -- "$1" 2>/dev/null; find "$1" -mindepth 1 -delete && ${GIT_ENV_PREFIX} git ${SLOT_GIT_INIT_ARGS.join(" ")} "$1"`;
26050
26071
  var realSlotResetDeps = () => ({
26051
26072
  lstat: (path3) => lstatSync4(path3),
26052
- readdir: (path3) => readdirSync4(path3),
26073
+ readdir: (path3) => readdirSync5(path3),
26053
26074
  makeWritable: (path3) => {
26054
26075
  chmodSync2(path3, 448);
26055
26076
  },
@@ -26127,7 +26148,7 @@ function probe(cmd, args, env2, timeout) {
26127
26148
  }
26128
26149
  function realAmbientCredentialProbes(env2 = process.env, timeout = 1e4) {
26129
26150
  const seat = workerEnv("claude", env2);
26130
- const home = seat.HOME ?? homedir8();
26151
+ const home = seat.HOME ?? homedir7();
26131
26152
  const configHome = seat.XDG_CONFIG_HOME || join24(home, ".config");
26132
26153
  return {
26133
26154
  ghAuthLoggedIn() {
@@ -27589,7 +27610,7 @@ function httpLoginApi(creds) {
27589
27610
  }
27590
27611
 
27591
27612
  // src/node/enroll.ts
27592
- import { hostname, arch, platform, homedir as homedir9 } from "node:os";
27613
+ import { hostname, arch, platform, homedir as homedir8 } from "node:os";
27593
27614
  import { chmodSync as chmodSync5, mkdirSync as mkdirSync18, realpathSync as realpathSync8, rmSync as rmSync11, statSync as statSync3, writeFileSync as writeFileSync17 } from "node:fs";
27594
27615
  import { join as join31, parse, resolve as resolve11 } from "node:path";
27595
27616
  var EnrollError = class extends Error {
@@ -27633,9 +27654,9 @@ function prepareRoot(input, seats = false) {
27633
27654
  const real3 = realpathSync8(wanted);
27634
27655
  const home = (() => {
27635
27656
  try {
27636
- return realpathSync8(homedir9());
27657
+ return realpathSync8(homedir8());
27637
27658
  } catch {
27638
- return homedir9();
27659
+ return homedir8();
27639
27660
  }
27640
27661
  })();
27641
27662
  if (real3 === parse(real3).root || real3 === home) {
@@ -28577,7 +28598,7 @@ async function provisionSeatClones(entries, deps) {
28577
28598
 
28578
28599
  // src/node/owner-pool-bases.ts
28579
28600
  import { execFile as execFile8 } from "node:child_process";
28580
- import { chmodSync as chmodSync7, existsSync as existsSync22, lstatSync as lstatSync6, mkdirSync as mkdirSync21, readdirSync as readdirSync5, rmSync as rmSync12 } from "node:fs";
28601
+ import { chmodSync as chmodSync7, existsSync as existsSync22, lstatSync as lstatSync6, mkdirSync as mkdirSync21, readdirSync as readdirSync6, rmSync as rmSync12 } from "node:fs";
28581
28602
  import { dirname as dirname19, join as join34 } from "node:path";
28582
28603
  import { promisify as promisify3 } from "node:util";
28583
28604
  var exec3 = promisify3(execFile8);
@@ -28755,7 +28776,7 @@ function realOwnerPoolBasesDeps(root, env2 = process.env, tokenHosts = [], log =
28755
28776
  lockdown,
28756
28777
  list() {
28757
28778
  try {
28758
- return readdirSync5(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
28779
+ return readdirSync6(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
28759
28780
  } catch {
28760
28781
  return [];
28761
28782
  }
@@ -29898,7 +29919,7 @@ function setEnabled(path3, enabled) {
29898
29919
  }
29899
29920
 
29900
29921
  // src/node/janitor/size.ts
29901
- import { lstatSync as lstatSync7, readdirSync as readdirSync6 } from "node:fs";
29922
+ import { lstatSync as lstatSync7, readdirSync as readdirSync7 } from "node:fs";
29902
29923
  import { join as join39 } from "node:path";
29903
29924
  var SIZE_WALK_LIMIT = 5e5;
29904
29925
  function diskUsage(path3, limit = SIZE_WALK_LIMIT) {
@@ -29918,7 +29939,7 @@ function diskUsage(path3, limit = SIZE_WALK_LIMIT) {
29918
29939
  if (st.isDirectory()) {
29919
29940
  let names2;
29920
29941
  try {
29921
- names2 = readdirSync6(p);
29942
+ names2 = readdirSync7(p);
29922
29943
  } catch {
29923
29944
  continue;
29924
29945
  }
@@ -30182,7 +30203,7 @@ function createDockerClient(run4 = runDocker2) {
30182
30203
  import { resolve as resolve14, sep as sep5 } from "node:path";
30183
30204
 
30184
30205
  // src/node/janitor/scratch.ts
30185
- import { lstatSync as lstatSync8, readdirSync as readdirSync7 } from "node:fs";
30206
+ import { lstatSync as lstatSync8, readdirSync as readdirSync8 } from "node:fs";
30186
30207
  import { basename as basename5, isAbsolute as isAbsolute3, join as join40, relative as relative3, resolve as resolve13, sep as sep4 } from "node:path";
30187
30208
  var SCRATCH_WALK_LIMIT = 2e4;
30188
30209
  var GO_BUILD_DIR = "go-build";
@@ -30205,7 +30226,7 @@ function newestMtime(path3, limit = SCRATCH_WALK_LIMIT, skipVendored = false) {
30205
30226
  if (st.isDirectory() && !(skipVendored && p !== path3 && (basename5(p) === ".git" || basename5(p) === REBUILDABLE_DIR))) {
30206
30227
  let children;
30207
30228
  try {
30208
- children = readdirSync7(p);
30229
+ children = readdirSync8(p);
30209
30230
  } catch {
30210
30231
  return { ok: false, reason: "unreadable" };
30211
30232
  }
@@ -30221,7 +30242,7 @@ var within = (root, path3) => {
30221
30242
  };
30222
30243
  var names = (dir) => {
30223
30244
  try {
30224
- return readdirSync7(dir);
30245
+ return readdirSync8(dir);
30225
30246
  } catch {
30226
30247
  return [];
30227
30248
  }
@@ -30355,7 +30376,7 @@ function isBusy(path3, agents, now = Date.now(), walkLimit) {
30355
30376
 
30356
30377
  // src/node/janitor/worktrees.ts
30357
30378
  import { execFile as execFile10 } from "node:child_process";
30358
- import { existsSync as existsSync24, readdirSync as readdirSync8, realpathSync as realpathSync11, statSync as statSync6 } from "node:fs";
30379
+ import { existsSync as existsSync24, readdirSync as readdirSync9, realpathSync as realpathSync11, statSync as statSync6 } from "node:fs";
30359
30380
  import { dirname as dirname22, isAbsolute as isAbsolute4, join as join41, relative as relative4, sep as sep6 } from "node:path";
30360
30381
  import { promisify as promisify4 } from "node:util";
30361
30382
  var execFileP = promisify4(execFile10);
@@ -30410,7 +30431,7 @@ function defaultAgeOf(now) {
30410
30431
  function baseClones(root) {
30411
30432
  let repos;
30412
30433
  try {
30413
- repos = readdirSync8(root);
30434
+ repos = readdirSync9(root);
30414
30435
  } catch {
30415
30436
  return [];
30416
30437
  }
@@ -30948,6 +30969,7 @@ import { existsSync as existsSync26, rmSync as rmSync13 } from "node:fs";
30948
30969
  import { readFileSync as readFileSync25, statSync as statSync9 } from "node:fs";
30949
30970
  var ACTIVITY_REPORT_MS = 15e3;
30950
30971
  var REVIEW_HEARTBEAT_MS = 6e4;
30972
+ var ACTIVITY_REFRESH_MS = 5 * 6e4;
30951
30973
  function sessionFileActive(path3) {
30952
30974
  try {
30953
30975
  return statSync9(path3).size > 0;
@@ -31023,6 +31045,10 @@ function needsReport(next, sent) {
31023
31045
  if (!sent || sent.state !== next.state) return true;
31024
31046
  return next.model !== void 0 && next.model !== sent.model;
31025
31047
  }
31048
+ function reportDue(next, sent, sentAt, now) {
31049
+ if (needsReport(next, sent)) return true;
31050
+ return sentAt === void 0 || now - sentAt >= ACTIVITY_REFRESH_MS;
31051
+ }
31026
31052
 
31027
31053
  // src/node/desired-seats.ts
31028
31054
  var seatWorking = (name) => isRunAsSeat(name) ? sessionFileActive(activityPath(name)) : existsSync26(activityPath(name));
@@ -31239,6 +31265,7 @@ async function reportActivity(creds, body) {
31239
31265
  function startActivityLoop(agents, sup, ownerPool = false) {
31240
31266
  let busy = false;
31241
31267
  const sent = /* @__PURE__ */ new Map();
31268
+ const sentAt = /* @__PURE__ */ new Map();
31242
31269
  const beatAt = /* @__PURE__ */ new Map();
31243
31270
  const sessions = new SessionEndTracker();
31244
31271
  const quota = new QuotaWindows();
@@ -31299,9 +31326,10 @@ function startActivityLoop(agents, sup, ownerPool = false) {
31299
31326
  });
31300
31327
  await heartbeatReviews(creds, name, live, reviewIds.get(creds.agentId) ?? []);
31301
31328
  const body = activityBody(state, readLaunchedModel(activityPath(name)));
31302
- if (!needsReport(body, sent.get(name))) continue;
31329
+ if (!reportDue(body, sent.get(name), sentAt.get(name), Date.now())) continue;
31303
31330
  await reportActivity(creds, body);
31304
31331
  sent.set(name, body);
31332
+ sentAt.set(name, Date.now());
31305
31333
  }
31306
31334
  } catch (err) {
31307
31335
  console.log(`${(/* @__PURE__ */ new Date()).toISOString()} activity: ${err instanceof Error ? err.message : String(err)}`);
@@ -31960,7 +31988,7 @@ function nodeStatusCommand(opts) {
31960
31988
 
31961
31989
  // src/commands/node-service.ts
31962
31990
  import { accessSync as accessSync2, chmodSync as chmodSync8, constants as constants2, existsSync as existsSync28, mkdirSync as mkdirSync26, readFileSync as readFileSync28, realpathSync as realpathSync15, statSync as statSync10, unlinkSync as unlinkSync5, writeFileSync as writeFileSync21 } from "node:fs";
31963
- import { homedir as homedir10, userInfo as userInfo2 } from "node:os";
31991
+ import { homedir as homedir9, userInfo as userInfo2 } from "node:os";
31964
31992
  import { dirname as dirname25, join as join45, resolve as resolve17 } from "node:path";
31965
31993
 
31966
31994
  // src/node/service/identity.ts
@@ -32198,7 +32226,7 @@ var DEFAULT_PATH = "/usr/bin:/bin:/usr/local/bin";
32198
32226
  function defaultServiceDeps() {
32199
32227
  return {
32200
32228
  platform: process.platform,
32201
- home: homedir10(),
32229
+ home: homedir9(),
32202
32230
  configDir: configDir(),
32203
32231
  uid: process.getuid?.() ?? 0,
32204
32232
  username: userInfo2().username,
@@ -32472,7 +32500,7 @@ function nodeServiceUninstallCommand() {
32472
32500
  // src/node/janitor/target.ts
32473
32501
  import { readFileSync as readFileSync29 } from "node:fs";
32474
32502
  import { dirname as dirname26, isAbsolute as isAbsolute7 } from "node:path";
32475
- import { homedir as homedir11 } from "node:os";
32503
+ import { homedir as homedir10 } from "node:os";
32476
32504
  function resolveJanitorTarget(d) {
32477
32505
  let state = null;
32478
32506
  try {
@@ -32484,7 +32512,7 @@ function resolveJanitorTarget(d) {
32484
32512
  if (specPath !== "" && isAbsolute7(specPath) && !specPath.endsWith("(desired state)")) {
32485
32513
  let spec;
32486
32514
  try {
32487
- spec = parseSpec(readFileSync29(specPath, "utf-8"), dirname26(specPath), { homeDir: d.homeDir ?? homedir11() });
32515
+ spec = parseSpec(readFileSync29(specPath, "utf-8"), dirname26(specPath), { homeDir: d.homeDir ?? homedir10() });
32488
32516
  } catch (e) {
32489
32517
  return { ok: false, message: `this node runs from ${specPath}, which cannot be used: ${e.message}. Nothing was cleaned.` };
32490
32518
  }
@@ -33219,7 +33247,8 @@ var requiredCheckExistsCheck = {
33219
33247
  // src/doctor/checks/risk-config.ts
33220
33248
  var MAX_BYTES = 64 * 1024;
33221
33249
  var MAX_GLOB = 200;
33222
- var FIX = "fix or delete .pitboss/risk.json (an invalid file makes every order tier 2)";
33250
+ var FIX = "fix or delete .shipster/risk.json (an invalid file makes every order tier 2)";
33251
+ var RISK_FILES = [".shipster/risk.json", ".pitboss/risk.json"];
33223
33252
  var TOP_KEYS = /* @__PURE__ */ new Set(["version", "extends", "rules", "ignore"]);
33224
33253
  var RULE_KEYS = /* @__PURE__ */ new Set(["id", "paths", "tier"]);
33225
33254
  var isObject2 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
@@ -33268,9 +33297,17 @@ var riskConfigCheck = {
33268
33297
  name: "Risk config",
33269
33298
  async run(env2) {
33270
33299
  const base2 = { id: "risk-config", name: "Risk config" };
33271
- const text = env2.readFile(`${env2.cwd}/.pitboss/risk.json`);
33300
+ let file = RISK_FILES[0];
33301
+ let text = null;
33302
+ for (const candidate of RISK_FILES) {
33303
+ text = env2.readFile(`${env2.cwd}/${candidate}`);
33304
+ if (text !== null) {
33305
+ file = candidate;
33306
+ break;
33307
+ }
33308
+ }
33272
33309
  if (text === null) {
33273
- return { ...base2, status: "ok", reason: "no .pitboss/risk.json: the default risky-path list is in use", fix: "" };
33310
+ return { ...base2, status: "ok", reason: "no .shipster/risk.json: the default risky-path list is in use", fix: "" };
33274
33311
  }
33275
33312
  const fail2 = (reason) => ({ ...base2, status: "fail", reason, fix: FIX });
33276
33313
  if (Buffer.byteLength(text, "utf8") > MAX_BYTES) return fail2("risk.json is larger than 64 KB");
@@ -33282,7 +33319,7 @@ var riskConfigCheck = {
33282
33319
  }
33283
33320
  const error = riskConfigError(parsed);
33284
33321
  if (error) return fail2(error);
33285
- return { ...base2, status: "ok", reason: "committed .pitboss/risk.json", fix: "" };
33322
+ return { ...base2, status: "ok", reason: `committed ${file}`, fix: "" };
33286
33323
  }
33287
33324
  };
33288
33325
 
@@ -535,7 +535,7 @@ var GIT_TIMEOUT_MS = 5e3;
535
535
  var LESSONS_MAX_BUFFER = 64 * 1024;
536
536
  var TREE_MAX_BUFFER = 32 * 1024 * 1024;
537
537
  var MAX_TREE_ENTRIES = 2e5;
538
- var LESSONS_PATH = ".pitboss/lessons.md";
538
+ var LESSONS_PATHS = [".shipster/lessons.md", ".pitboss/lessons.md"];
539
539
  var BRANCH_RE = /^[A-Za-z0-9._/-]{1,100}$/;
540
540
  var SHA_RE = /^[0-9a-f]{40}$/;
541
541
  var BLOB_MODES = /* @__PURE__ */ new Set(["100644", "100755"]);
@@ -587,25 +587,31 @@ function entryFor(repoPath, sha) {
587
587
  }
588
588
  return entry;
589
589
  }
590
- async function readLessons(repoPath, exec, resolved) {
591
- const ref = resolved.sha;
590
+ async function blobAt(exec, repoPath, ref, path) {
592
591
  let listing;
593
592
  try {
594
- listing = await git(exec, repoPath, ["ls-tree", "-z", ref, "--", LESSONS_PATH]);
593
+ listing = await git(exec, repoPath, ["ls-tree", "-z", ref, "--", path]);
595
594
  } catch {
596
595
  return null;
597
596
  }
598
597
  const row = listing.split("\0").find((r) => r !== "");
599
- const match = row?.match(/^(\d{6}) (\w+) ([0-9a-f]{40})\t(.+)$/);
600
- if (!match || match[4] !== LESSONS_PATH || match[2] !== "blob" || !BLOB_MODES.has(match[1])) return null;
601
- let text;
598
+ if (!row) return void 0;
599
+ const match = row.match(/^(\d{6}) (\w+) ([0-9a-f]{40})\t(.+)$/);
600
+ if (!match || match[4] !== path || match[2] !== "blob" || !BLOB_MODES.has(match[1])) return null;
602
601
  try {
603
- text = await git(exec, repoPath, ["cat-file", "blob", match[3]]);
602
+ return await git(exec, repoPath, ["cat-file", "blob", match[3]]);
604
603
  } catch {
605
604
  return null;
606
605
  }
607
- if (text.includes("\0")) return null;
608
- return { text, branch: resolved.branch, sha: resolved.sha };
606
+ }
607
+ async function readLessons(repoPath, exec, resolved) {
608
+ for (const path of LESSONS_PATHS) {
609
+ const text = await blobAt(exec, repoPath, resolved.sha, path);
610
+ if (text === void 0) continue;
611
+ if (text === null || text.includes("\0")) return null;
612
+ return { text, branch: resolved.branch, sha: resolved.sha };
613
+ }
614
+ return null;
609
615
  }
610
616
  async function loadLessons(repoPath, exec) {
611
617
  const resolved = await resolveDefaultBranch(repoPath, exec);
package/dist/mcp.js CHANGED
@@ -12909,7 +12909,7 @@ function buildUpdateOrderTool(client) {
12909
12909
  function buildCheckOrderRiskTool(client) {
12910
12910
  return {
12911
12911
  name: "check_order_risk",
12912
- description: "Derive an order's risk tier from the repo paths its plan will touch, using the repo's own .pitboss/risk.json (or the default rules). Returns { tier, riskyPaths, reason, acceptanceSource, acceptance, applied }: build the gate tasks that `acceptance` lists. An order filed with explicit acceptance is unaffected. The server raises the tier later if the diff touches a risky path. For the repo orchestrator and the order's planner.",
12912
+ description: "Derive an order's risk tier from the repo paths its plan will touch, using the repo's own .shipster/risk.json (or the default rules). Returns { tier, riskyPaths, reason, acceptanceSource, acceptance, applied }: build the gate tasks that `acceptance` lists. An order filed with explicit acceptance is unaffected. The server raises the tier later if the diff touches a risky path. For the repo orchestrator and the order's planner.",
12913
12913
  inputSchema: external_exports.object({
12914
12914
  orderId: external_exports.string().describe("The order id (ord_\u2026)."),
12915
12915
  paths: external_exports.array(external_exports.string().min(1)).min(1).max(500).describe("Repo-relative paths the plan will touch (1 to 500).")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pitboss/cli",
3
- "version": "0.4.13",
3
+ "version": "0.4.14",
4
4
  "private": false,
5
5
  "description": "Connect your coding agents to a pitboss instance",
6
6
  "keywords": [