@join-pantheon/cli 0.33.0-rc.1 → 0.33.0-rc.2

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
@@ -914,7 +914,8 @@ ${B("control")}
914
914
  (auto-detects claude / codex / cursor / copilot / kiro on this machine)
915
915
  pantheon spend woken runs on this machine, and what pantheon cannot see
916
916
  pantheon leave remove what pantheon put on this machine
917
- pantheon uninstall leave, then remove Pantheon itself: its own Node, the pantheon command, the PATH lines
917
+ pantheon uninstall leave, then remove Pantheon itself: its own Node, the pantheon command, the PATH lines,
918
+ and all it keeps in ~/.pantheon (files of yours there stay)
918
919
  pantheon panic emergency stop: ends the run in flight and the worker, and switches off wake rights in every team you are in
919
920
  pantheon doctor [--share] check this machine end to end; --share prints it without names or paths, to paste to us
920
921
  pantheon network [--proxy <url> | --direct | --clear] how this machine reaches the relay; save a proxy for every Pantheon process here
@@ -1038,7 +1039,7 @@ async function teamStanding(all, m) {
1038
1039
  return { others: null, founder: false };
1039
1040
  }
1040
1041
  finally {
1041
- c.close();
1042
+ c.dispose();
1042
1043
  }
1043
1044
  }
1044
1045
  function slipDistance(a, b) {
@@ -1080,7 +1081,7 @@ async function main() {
1080
1081
  await installNetwork();
1081
1082
  }
1082
1083
  catch { }
1083
- if (!QUIET.has(cmd)) {
1084
+ if (!QUIET.has(cmd) && cmd !== "uninstall") {
1084
1085
  try {
1085
1086
  console.error(D(updateBanner(VERSION)));
1086
1087
  }
@@ -2507,7 +2508,8 @@ async function main() {
2507
2508
  if (uninstalling && !argv.includes("--yes")) {
2508
2509
  const teams = plan.teams.length && !keepIdentity ? `leaves ${plan.teams.map((t) => `"${t.name}"`).join(", ")} (this machine's key goes), ` : "";
2509
2510
  const what = `this removes Pantheon from this machine: it ${teams}uninstalls its services, hooks and agent entries` +
2510
- (install?.present ? `, and deletes Pantheon's own Node in ${install.runtime}, the pantheon command and the PATH lines the installer added.` : ".");
2511
+ (install?.present ? `, and deletes Pantheon's own Node in ${install.runtime}, the pantheon command and the PATH lines the installer added` : "") +
2512
+ `. Everything Pantheon keeps in ${CONFIG_DIR} goes${keepIdentity ? " (but your identity, --keep-identity)" : ""}; files of your own there stay.`;
2511
2513
  if (!process.stdin.isTTY)
2512
2514
  die(`${what}\n If you mean it: pantheon uninstall --yes`);
2513
2515
  const rl = createInterface({ input: process.stdin, output: process.stderr });
@@ -2557,52 +2559,56 @@ async function main() {
2557
2559
  left.push(...u.left);
2558
2560
  }
2559
2561
  const { unlinkSync, existsSync: exists, rmSync, readdirSync } = await import("node:fs");
2560
- if (all && exists(CONFIG_PATH)) {
2561
- if (keepIdentity) {
2562
- left.push(`your identity and ${plan.teams.length} team membership${plan.teams.length === 1 ? "" : "s"}, ${CONFIG_PATH} (--keep-identity)`);
2563
- }
2564
- else {
2562
+ const spare = [];
2563
+ const hasConfig = !!all && exists(CONFIG_PATH);
2564
+ if (hasConfig && keepIdentity) {
2565
+ left.push(`your identity and ${plan.teams.length} team membership${plan.teams.length === 1 ? "" : "s"}, ${CONFIG_PATH} (--keep-identity)`);
2566
+ }
2567
+ else if (!keepIdentity && (hasConfig || uninstalling)) {
2568
+ if (hasConfig) {
2565
2569
  unlinkSync(CONFIG_PATH);
2566
2570
  removed.push(`${CONFIG_PATH} — your key and ${plan.teams.length ? `the token${plan.teams.length === 1 ? "" : "s"} for ${plan.teams.map((t) => `"${t.name}"`).join(", ")}` : "account"}; rejoining means a new invite`);
2567
- const runHomes = join(CONFIG_PATH, "..", "run-homes");
2568
- const { restorePendingQuarantines, pendingQuarantines } = await import("./agents.js");
2569
- const put = restorePendingQuarantines(runHomes);
2570
- if (put.length)
2571
- removed.push(`nothing of your repos' — what interrupted runs had held aside: ${put.join("; ")}`);
2572
- const still = pendingQuarantines(runHomes);
2573
- const keptAside = (dir) => { try {
2574
- return readdirSync(join(dir, "quarantine-kept")).length > 0;
2575
- }
2576
- catch {
2577
- return false;
2578
- } };
2579
- let homes = [];
2571
+ }
2572
+ const runHomes = join(CONFIG_PATH, "..", "run-homes");
2573
+ const { restorePendingQuarantines, pendingQuarantines } = await import("./agents.js");
2574
+ const put = restorePendingQuarantines(runHomes);
2575
+ if (put.length)
2576
+ removed.push(`nothing of your repos' — what interrupted runs had held aside: ${put.join("; ")}`);
2577
+ const still = pendingQuarantines(runHomes);
2578
+ const keptAside = (dir) => { try {
2579
+ return readdirSync(join(dir, "quarantine-kept")).length > 0;
2580
+ }
2581
+ catch {
2582
+ return false;
2583
+ } };
2584
+ let homes = [];
2585
+ try {
2586
+ homes = readdirSync(runHomes);
2587
+ }
2588
+ catch { }
2589
+ const keep = new Set([...still.map((x) => x.runHome), ...homes.map((h) => join(runHomes, h)).filter(keptAside)]);
2590
+ for (const h of homes) {
2591
+ const dir = join(runHomes, h);
2592
+ if (keep.has(dir))
2593
+ continue;
2580
2594
  try {
2581
- homes = readdirSync(runHomes);
2595
+ rmSync(dir, { recursive: true, force: true });
2582
2596
  }
2583
2597
  catch { }
2584
- const keep = new Set([...still.map((x) => x.runHome), ...homes.map((h) => join(runHomes, h)).filter(keptAside)]);
2585
- for (const h of homes) {
2586
- const dir = join(runHomes, h);
2587
- if (keep.has(dir))
2588
- continue;
2589
- try {
2590
- rmSync(dir, { recursive: true, force: true });
2591
- }
2592
- catch { }
2593
- }
2594
- if (!keep.size) {
2595
- try {
2596
- rmSync(runHomes, { recursive: true, force: true });
2597
- }
2598
- catch { }
2598
+ }
2599
+ if (!keep.size) {
2600
+ try {
2601
+ rmSync(runHomes, { recursive: true, force: true });
2599
2602
  }
2600
- for (const x of still)
2601
- left.push(`${x.runHome} — it still holds ${x.paths.join(", ")} from ${x.worktree}, which could not be put back safely; compare and move them back by hand, then delete the folder`);
2602
- for (const dir of keep)
2603
- if (keptAside(dir) && !still.some((x) => x.runHome === dir))
2604
- left.push(`${join(dir, "quarantine-kept")} — agent config an interrupted run held, set aside because the repo had moved on; check it, then delete the folder`);
2603
+ catch { }
2605
2604
  }
2605
+ else
2606
+ spare.push(runHomes);
2607
+ for (const x of still)
2608
+ left.push(`${x.runHome} — it still holds ${x.paths.join(", ")} from ${x.worktree}, which could not be put back safely; compare and move them back by hand, then delete the folder`);
2609
+ for (const dir of keep)
2610
+ if (keptAside(dir) && !still.some((x) => x.runHome === dir))
2611
+ left.push(`${join(dir, "quarantine-kept")} — agent config an interrupted run held, set aside because the repo had moved on; check it, then delete the folder`);
2606
2612
  }
2607
2613
  {
2608
2614
  const { removePantheonWorktrees, removeHomeLeftovers } = await import("./machine.js");
@@ -2626,6 +2632,10 @@ async function main() {
2626
2632
  }
2627
2633
  if (!runningManaged)
2628
2634
  left.push(`this pantheon itself (${process.argv[1] ?? "the one you ran"}), which npm installed — remove it with: ${NPM_UNINSTALL}`);
2635
+ const { sweepPantheonHome } = await import("./machine.js");
2636
+ const swept = sweepPantheonHome(CONFIG_DIR, { keepIdentity, spare });
2637
+ removed.push(...swept.removed);
2638
+ left.push(...swept.left);
2629
2639
  }
2630
2640
  console.error(`\n${B("Removed")}`);
2631
2641
  for (const r of removed)
package/dist/client.js CHANGED
@@ -21,6 +21,7 @@ export class PantheonClient {
21
21
  seen = new Map();
22
22
  backoff = 500;
23
23
  closed = false;
24
+ disposed = false;
24
25
  everConnected = false;
25
26
  localOverride = null;
26
27
  usingLoopback = false;
@@ -170,6 +171,11 @@ export class PantheonClient {
170
171
  }
171
172
  attempt(address) {
172
173
  return new Promise((resolve, reject) => {
174
+ if (this.disposed) {
175
+ this.closed = true;
176
+ reject(new Error("this client was disposed"));
177
+ return;
178
+ }
173
179
  let settled = false;
174
180
  let heard = false;
175
181
  const fail = reject;
@@ -195,6 +201,8 @@ export class PantheonClient {
195
201
  this.watchdog.unref?.();
196
202
  ws.on("open", () => { });
197
203
  ws.on("message", (raw) => {
204
+ if (this.disposed)
205
+ return;
198
206
  this.lastInbound = Date.now();
199
207
  let msg;
200
208
  try {
@@ -438,6 +446,14 @@ export class PantheonClient {
438
446
  this.waiters = [];
439
447
  this.ws?.close(4000, "handover");
440
448
  }
449
+ dispose() {
450
+ this.disposed = true;
451
+ this.close();
452
+ if (this.watchdog) {
453
+ clearInterval(this.watchdog);
454
+ this.watchdog = null;
455
+ }
456
+ }
441
457
  close() {
442
458
  this.closed = true;
443
459
  for (const w of this.waiters) {
package/dist/machine.js CHANGED
@@ -705,6 +705,142 @@ export function removeHomeLeftovers(home, keep, opts = {}) {
705
705
  }
706
706
  return { removed, left };
707
707
  }
708
+ export const PANTHEON_HOME_ENTRIES = [
709
+ { name: "config.json", what: "your key and team tokens", identity: true },
710
+ { name: "config.json.bak", what: "the previous config.json", identity: true },
711
+ { name: "keys.json", what: "the teammates' keys this machine pinned", identity: true },
712
+ { name: "nonces.json", what: "the signed requests this machine has seen", identity: true },
713
+ { name: "continued.json", what: "what this machine already handled", identity: true },
714
+ { name: "cursors.json", what: "where each agent session last read", identity: true },
715
+ { name: "worker-cursor.json", what: "where the worker last read", identity: true },
716
+ { name: "profile.json", what: "your profile", identity: true },
717
+ { name: "worker-policy.json", what: "the worker's wake policy", identity: true },
718
+ { name: "spend.json", what: "the spend ledger", identity: true },
719
+ { name: "personas", what: "the worker's personas", dir: true, identity: true },
720
+ { name: "worker-state.json", what: "the worker's last state" },
721
+ { name: "worker-run.json", what: "the worker's record of a run in flight" },
722
+ { name: "run-slot.json", what: "the worker's run slot" },
723
+ { name: "worker.pid", what: "the worker's pid file" },
724
+ { name: /^notifier-state(-.+)?\.json$/, sample: "notifier-state-team%2Fone.json", what: "the alerts' state" },
725
+ { name: "update-check.json", what: "the update check's cache" },
726
+ { name: "uri-key", what: "the key pantheon:// links are signed with" },
727
+ { name: "board.json", what: "the board's state" },
728
+ { name: "hook-intent.json", what: "the hook intent" },
729
+ { name: "hook-guard.json", what: "the hook guard" },
730
+ { name: /^(worker|relay|notifier|menubar)\.log(\.1)?$/, sample: "worker.log", what: "service logs an older version wrote here" },
731
+ { name: /^\.write-check\..+$/, sample: ".write-check.1234.5678", what: "a leftover write probe" },
732
+ { name: "bin", what: "the menu bar's and alerts' files", dir: true },
733
+ { name: "logs", what: "the service logs", dir: true },
734
+ { name: "host", what: "the Windows host's queue, state and markers", dir: true },
735
+ { name: "mcp", what: "the agent windows' server state", dir: true },
736
+ { name: "run-homes", what: "the woken runs' homes", dir: true },
737
+ { name: "worktrees", what: "the worker's worktrees", dir: true },
738
+ { name: "no-hooks", what: "the empty hooks folder woken runs' git uses", dir: true },
739
+ { name: "lfs-hooks", what: "the LFS-only hooks folder woken runs' git uses", dir: true },
740
+ { name: "runtime", what: "Pantheon's own Node", dir: true, kept: "managed" },
741
+ { name: "data", what: "the relay's ledger", dir: true, kept: "it is your team's history and may be its only copy; delete it yourself once no relay runs from it" },
742
+ { name: /^(\.DS_Store|Thumbs\.db|desktop\.ini)$/i, sample: ".DS_Store", what: "the file browser's folder cache" },
743
+ ];
744
+ const LOCK_OR_TMP = /^(.+?)(\.lock|(\.[0-9a-f]+)+\.tmp)$/i;
745
+ export function homeEntryFor(name) {
746
+ const direct = (n) => PANTHEON_HOME_ENTRIES.find((e) => typeof e.name === "string" ? e.name === n : e.name.test(n)) ?? null;
747
+ const e = direct(name);
748
+ if (e)
749
+ return e;
750
+ const m = LOCK_OR_TMP.exec(name);
751
+ const base = m ? direct(m[1]) : null;
752
+ return base && !base.dir ? base : null;
753
+ }
754
+ const pause = (ms) => { try {
755
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
756
+ }
757
+ catch { } };
758
+ const realSweepFs = {
759
+ list: (d) => readdirSync(d),
760
+ exists: (p) => existsSync(p),
761
+ remove: (p) => rmSync(p, { recursive: true, force: true }),
762
+ removeDir: (d) => rmdirSync(d),
763
+ };
764
+ export function sweepPantheonHome(home, o = {}) {
765
+ const fs = o.fs ?? realSweepFs;
766
+ const tries = o.tries ?? 5, waitMs = o.waitMs ?? 200;
767
+ const os = o.os ?? platform();
768
+ const removed = [], left = [];
769
+ if (!fs.exists(home))
770
+ return { removed, left, gone: true };
771
+ const spare = new Set((o.spare ?? []).map((p) => resolve(p)));
772
+ const attempt = (p, rm) => {
773
+ let why = "";
774
+ for (let i = 0; i < tries; i++) {
775
+ try {
776
+ rm(p);
777
+ }
778
+ catch (e) {
779
+ why = String(e.code ?? e.message.split("\n")[0]);
780
+ }
781
+ if (!fs.exists(p))
782
+ return null;
783
+ if (i < tries - 1)
784
+ pause(waitMs * (i + 1));
785
+ }
786
+ return why || "still there";
787
+ };
788
+ const lockedHint = os === "win32" ? "; a Pantheon process (an agent window, the menu bar) may still have it open — close it, then delete it" : "; delete it yourself";
789
+ const gone = [], foreign = [], keptForIdentity = [];
790
+ let names = [];
791
+ try {
792
+ names = fs.list(home);
793
+ }
794
+ catch (e) {
795
+ return { removed, left: [`${home} — could not be read (${e.message.split("\n")[0]}), so nothing in it was removed`], gone: false };
796
+ }
797
+ for (const name of names.sort()) {
798
+ const p = join(home, name);
799
+ const e = homeEntryFor(name);
800
+ if (!e) {
801
+ foreign.push(name);
802
+ continue;
803
+ }
804
+ if (spare.has(resolve(p)))
805
+ continue;
806
+ if (e.kept === "managed")
807
+ continue;
808
+ if (e.kept) {
809
+ left.push(`${e.what}, ${p} — kept: ${e.kept}`);
810
+ continue;
811
+ }
812
+ if (o.keepIdentity && e.identity) {
813
+ keptForIdentity.push(name);
814
+ continue;
815
+ }
816
+ const why = attempt(p, fs.remove);
817
+ if (why === null)
818
+ gone.push(name);
819
+ else
820
+ left.push(`${e.what}, ${p} — could not remove (${why})${lockedHint}`);
821
+ }
822
+ if (gone.length)
823
+ removed.push(`Pantheon's own files in ${home}: ${gone.join(", ")}`);
824
+ if (keptForIdentity.length)
825
+ left.push(`what goes with your identity in ${home}: ${keptForIdentity.join(", ")} (--keep-identity)`);
826
+ let rest = [];
827
+ try {
828
+ rest = fs.list(home);
829
+ }
830
+ catch { }
831
+ if (!rest.length) {
832
+ const why = attempt(home, fs.removeDir);
833
+ if (why === null) {
834
+ removed.push(`${home} itself, now empty`);
835
+ return { removed, left, gone: true };
836
+ }
837
+ left.push(`${home} — empty, but could not remove it (${why})${lockedHint}`);
838
+ return { removed, left, gone: false };
839
+ }
840
+ if (foreign.length)
841
+ left.push(`${home}, for what is not Pantheon's: ${foreign.join(", ")} — Pantheon never writes ${foreign.length === 1 ? "it" : "these"}, so ${foreign.length === 1 ? "it was" : "they were"} not touched`);
842
+ return { removed, left, gone: false };
843
+ }
708
844
  export const accountStillExists = (email) => `your account${email ? ` ${email}` : ""} still exists — this machine is signed out. Sign back in with: pantheon login${email ? ` --email ${email}` : ""} (pantheon signup would fail: the email is taken). To delete the account itself: pantheon account delete, before leaving`;
709
845
  const LOG_KINDS = ["worker", "relay", "notifier", "menubar"];
710
846
  export function uninstallMachine(opts, io) {
package/dist/uninstall.js CHANGED
@@ -5,7 +5,7 @@ import { posix, win32 } from "node:path";
5
5
  import { expectedLauncher } from "./managed.js";
6
6
  export const BEGIN_MARK = "# >>> pantheon >>>";
7
7
  export const END_MARK = "# <<< pantheon <<<";
8
- export const PROFILES = [".profile", ".bash_profile", ".bashrc", ".zshrc", ".zprofile"];
8
+ export const PROFILES = [".profile", ".bash_profile", ".bash_login", ".bashrc", ".zshrc", ".zprofile"];
9
9
  export const FISH_CONF = ".config/fish/conf.d/pantheon.fish";
10
10
  export function withoutPathBlock(text) {
11
11
  const lines = text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
package/dist/win-host.js CHANGED
@@ -633,10 +633,12 @@ export function realHostIo(o = {}) {
633
633
  exit: (code) => process.exit(code),
634
634
  };
635
635
  }
636
- export function takeHostLock(home = CONFIG_DIR, pid = process.pid) {
636
+ export const HOST_LOCK_STARTUP_GRACE_MS = 2 * 60_000;
637
+ export function takeHostLock(home = CONFIG_DIR, pid = process.pid, now = Date.now, alive = pidAlive) {
637
638
  const f = hostFiles(home);
638
639
  mkdirSync(f.dir, { recursive: true });
639
- for (let i = 0; i < 2; i++) {
640
+ let lastHolder = -1;
641
+ for (let i = 0; i < 4; i++) {
640
642
  try {
641
643
  const fd = openSync(f.lock, "wx");
642
644
  writeSync(fd, String(pid));
@@ -646,13 +648,35 @@ export function takeHostLock(home = CONFIG_DIR, pid = process.pid) {
646
648
  catch (e) {
647
649
  if (e.code !== "EEXIST")
648
650
  throw e;
649
- const held = Number(readFileSafe(f.lock));
650
- if (Number.isInteger(held) && held > 0 && held !== pid && pidAlive(held) && hostAlive(readHostState(home)))
651
+ }
652
+ const held = Number(readFileSafe(f.lock));
653
+ let age = 0;
654
+ try {
655
+ age = now() - statSync(f.lock).mtimeMs;
656
+ }
657
+ catch {
658
+ continue;
659
+ }
660
+ if (Number.isInteger(held) && held > 0) {
661
+ lastHolder = held;
662
+ if (held === pid)
663
+ return null;
664
+ if (alive(held) && (hostAlive(readHostState(home)) || age < HOST_LOCK_STARTUP_GRACE_MS))
651
665
  return held;
652
- rmSync(f.lock, { force: true });
653
666
  }
667
+ else if (age < 10_000) {
668
+ return lastHolder;
669
+ }
670
+ const gone = `${f.lock}.stale-${pid}-${i}`;
671
+ try {
672
+ renameSync(f.lock, gone);
673
+ }
674
+ catch {
675
+ continue;
676
+ }
677
+ rmSync(gone, { force: true });
654
678
  }
655
- return null;
679
+ return lastHolder;
656
680
  }
657
681
  const readFileSafe = (p) => { try {
658
682
  return readFileSync(p, "utf8").trim();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "format": 1,
3
- "built_at": "2026-10-04T17:35:53.208Z",
3
+ "built_at": "2026-10-05T04:55:37.913Z",
4
4
  "swiftc": "Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)",
5
5
  "helpers": {
6
6
  "pantheon-tray": {
@@ -622,7 +622,10 @@ function Install-Pantheon {
622
622
  # Start-Process -NoNewWindow, so pantheon gets this console itself: a real
623
623
  # terminal for the sign-in questions, not a pipe PowerShell reads from.
624
624
  $State.step = 'starting pantheon'
625
- $line = ConvertTo-ArgLine (@($entry) + $Arguments)
625
+ # With the same --use-system-ca as npm and pantheon.cmd: this first run is the
626
+ # one that signs in, and behind a TLS-inspecting proxy the relay's
627
+ # certificate chains only to the company root in the Windows store.
628
+ $line = ConvertTo-ArgLine (@($ca) + @($entry) + $Arguments)
626
629
  $noConsole = $false
627
630
  try { $noConsole = [Console]::IsInputRedirected } catch { $noConsole = $false }
628
631
  if (-not $noConsole) {
@@ -508,6 +508,17 @@ add_block() {
508
508
  note "the pantheon block in $f has a marker line without its pair, so $f was left as it is; put $BIN_DIR at the front of PATH there yourself"
509
509
  return 0
510
510
  fi
511
+ # One of each, but the end before the begin (edited by hand): the rewrite
512
+ # below would skip from the begin marker to the end of the file and drop
513
+ # everything after it, so the file is not touched either.
514
+ if [ "${begins:-0}" -eq 1 ]; then
515
+ bline=$(grep -nxF "$BEGIN_MARK" "$f" | head -n 1 | cut -d: -f1)
516
+ eline=$(grep -nxF "$END_MARK" "$f" | head -n 1 | cut -d: -f1)
517
+ if [ "${bline:-0}" -gt "${eline:-0}" ]; then
518
+ note "the pantheon block in $f has its end marker before its begin marker, so $f was left as it is; put $BIN_DIR at the front of PATH there yourself"
519
+ return 0
520
+ fi
521
+ fi
511
522
  if [ "${begins:-0}" -eq 1 ]; then
512
523
  awk -v b="$BEGIN_MARK" -v e="$END_MARK" '$0 == b { keep = 1 } keep { print } $0 == e { keep = 0 }' "$f" >"$TMP_DIR/old"
513
524
  same "$TMP_DIR/old" "$TMP_DIR/block" && return 0
@@ -531,10 +542,13 @@ add_block() {
531
542
  }
532
543
 
533
544
  login_shell=$(basename "${SHELL:-sh}")
534
- # ~/.profile: read by sh and dash logins, by bash when it has no .bash_profile,
545
+ # ~/.profile: read by sh and dash logins, by bash when it has no .bash_profile or .bash_login,
535
546
  # and by the `sh -lc` Pantheon itself uses to find programs.
536
547
  add_block "$HOME/.profile"
537
548
  [ -f "$HOME/.bash_profile" ] && add_block "$HOME/.bash_profile"
549
+ # bash logins read the first of .bash_profile, .bash_login and .profile: with
550
+ # no .bash_profile, an existing .bash_login is the one read, not .profile.
551
+ [ -f "$HOME/.bash_login" ] && add_block "$HOME/.bash_login"
538
552
  { [ -f "$HOME/.bashrc" ] || [ "$login_shell" = bash ]; } && add_block "$HOME/.bashrc"
539
553
  { [ -f "$HOME/.zshrc" ] || [ "$login_shell" = zsh ]; } && add_block "$HOME/.zshrc"
540
554
  [ -f "$HOME/.zprofile" ] && add_block "$HOME/.zprofile"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@join-pantheon/cli",
3
- "version": "0.33.0-rc.1",
3
+ "version": "0.33.0-rc.2",
4
4
  "description": "Let your coding agent collaborate directly with your teammates' agents — ask, agree an interface, and deliver, without a human relaying messages.",
5
5
  "type": "module",
6
6
  "bin": {