sisyphi 1.1.30 → 1.1.32

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.
@@ -96,6 +96,9 @@ runcmd:
96
96
  # 6. Sisyphus install (root → /usr/bin/sisyphusd symlink).
97
97
  - npm i -g sisyphi@${sisyphus_version}
98
98
 
99
+ # 6b. Claude Code CLI (sisyphus drives it for agent sessions).
100
+ - npm i -g @anthropic-ai/claude-code
101
+
99
102
  # 7. Daemon as systemd user service.
100
103
  - sudo -u sisyphus XDG_RUNTIME_DIR=/run/user/$(id -u sisyphus) systemctl --user daemon-reload
101
104
  - sudo -u sisyphus XDG_RUNTIME_DIR=/run/user/$(id -u sisyphus) systemctl --user enable --now sisyphusd
package/dist/cli.js CHANGED
@@ -2320,6 +2320,11 @@ function getTmuxSessionInfo() {
2320
2320
  function shellQuote(s) {
2321
2321
  return `'${s.replace(/'/g, "'\\''")}'`;
2322
2322
  }
2323
+ function shellQuoteHomePath(path) {
2324
+ if (path === "~") return "~";
2325
+ if (path.startsWith("~/")) return `~/${shellQuote(path.slice(2))}`;
2326
+ return shellQuote(path);
2327
+ }
2323
2328
  function validateRepoName(repo) {
2324
2329
  return !repo.includes("/") && !repo.includes("\\") && !repo.includes("..");
2325
2330
  }
@@ -10296,7 +10301,7 @@ function ensureGroveInstalled(provider) {
10296
10301
  }
10297
10302
  }
10298
10303
  function ensureGroveRegistered(provider, repo, instancePath) {
10299
- const cmd = `grove register --update --name ${shellQuote(repo)} ${shellQuote(instancePath)}`;
10304
+ const cmd = `grove register --update --name ${shellQuote(repo)} ${shellQuoteHomePath(instancePath)}`;
10300
10305
  const result = runOnBox(provider, cmd);
10301
10306
  if (result.exitCode !== 0) {
10302
10307
  throw new Error(`Failed to register grove project ${repo}: ${result.stderr || result.stdout}`);
@@ -10319,13 +10324,8 @@ function captureGit(args2) {
10319
10324
  }
10320
10325
  function inferRepoName() {
10321
10326
  const { stdout, ok } = captureGit(["rev-parse", "--show-toplevel"]);
10322
- if (!ok) {
10323
- throw new Error("Not inside a git repository. Run from a repo or pass --name.");
10324
- }
10325
- if (!stdout) {
10326
- throw new Error("git rev-parse returned empty toplevel.");
10327
- }
10328
- return basename6(stdout);
10327
+ if (ok && stdout) return basename6(stdout);
10328
+ return basename6(process.cwd());
10329
10329
  }
10330
10330
  function getOriginUrl() {
10331
10331
  const { stdout, ok } = captureGit(["remote", "get-url", "origin"]);
@@ -10334,10 +10334,8 @@ function getOriginUrl() {
10334
10334
  }
10335
10335
  function getRepoToplevel() {
10336
10336
  const { stdout, ok } = captureGit(["rev-parse", "--show-toplevel"]);
10337
- if (!ok) {
10338
- throw new Error("Not inside a git repository.");
10339
- }
10340
- return stdout;
10337
+ if (ok && stdout) return stdout;
10338
+ return process.cwd();
10341
10339
  }
10342
10340
  var DEFAULT_EXCLUDES = [
10343
10341
  ".sisyphus/",
@@ -10389,7 +10387,7 @@ function packageManagerInstallCmd(pm) {
10389
10387
  init_paths();
10390
10388
  function readSidecar(provider, repo) {
10391
10389
  const path = boxCloudSidecarPath(repo);
10392
- const result = runOnBox(provider, `cat ${shellQuote(path)} 2>/dev/null`);
10390
+ const result = runOnBox(provider, `cat ${shellQuoteHomePath(path)} 2>/dev/null`);
10393
10391
  if (result.exitCode !== 0 || !result.stdout.trim()) return null;
10394
10392
  try {
10395
10393
  const parsed = JSON.parse(result.stdout);
@@ -10403,8 +10401,8 @@ function writeSidecar(provider, repo, data) {
10403
10401
  const path = boxCloudSidecarPath(repo);
10404
10402
  const json = JSON.stringify(data, null, 2);
10405
10403
  const cmd = [
10406
- `mkdir -p ${shellQuote(dir)}`,
10407
- `cat > ${shellQuote(path)} <<'SISYPHUS_CLOUD_SIDECAR_EOF'`,
10404
+ `mkdir -p ${shellQuoteHomePath(dir)}`,
10405
+ `cat > ${shellQuoteHomePath(path)} <<'SISYPHUS_CLOUD_SIDECAR_EOF'`,
10408
10406
  json,
10409
10407
  "SISYPHUS_CLOUD_SIDECAR_EOF"
10410
10408
  ].join("\n");
@@ -10431,7 +10429,9 @@ Pass --name <slug> to disambiguate, or --fresh to overwrite.`
10431
10429
  }
10432
10430
  if (opts.fresh) {
10433
10431
  if (!localOrigin) {
10434
- throw new Error("--fresh requires an `origin` remote on the local repo.");
10432
+ throw new Error(
10433
+ "--fresh requires an `origin` remote on the local repo. Not available when running from a non-git parent dir."
10434
+ );
10435
10435
  }
10436
10436
  if (!opts.yes) {
10437
10437
  console.log(`This will wipe ~/projects/${repo} on the box and re-clone from ${localOrigin}.`);
@@ -10443,14 +10443,14 @@ Pass --name <slug> to disambiguate, or --fresh to overwrite.`
10443
10443
  }
10444
10444
  console.log(`\u2192 wiping ${remoteDir} and cloning ${localOrigin} on box...`);
10445
10445
  const cloneCmd = [
10446
- `rm -rf ${shellQuote(remoteDir)}`,
10447
- `mkdir -p ${shellQuote("~/projects")}`,
10448
- `git clone ${shellQuote(localOrigin)} ${shellQuote(remoteDir)}`
10446
+ `rm -rf ${shellQuoteHomePath(remoteDir)}`,
10447
+ `mkdir -p ${shellQuoteHomePath("~/projects")}`,
10448
+ `git clone ${shellQuote(localOrigin)} ${shellQuoteHomePath(remoteDir)}`
10449
10449
  ].join(" && ");
10450
10450
  const code = await runOnBoxStreaming(provider, cloneCmd);
10451
10451
  if (code !== 0) throw new Error(`fresh clone failed (exit ${code})`);
10452
10452
  } else {
10453
- const mkdir = runOnBox(provider, `mkdir -p ${shellQuote(remoteDir)}`);
10453
+ const mkdir = runOnBox(provider, `mkdir -p ${shellQuoteHomePath(remoteDir)}`);
10454
10454
  if (mkdir.exitCode !== 0) {
10455
10455
  throw new Error(`Failed to mkdir on box: ${mkdir.stderr}`);
10456
10456
  }
@@ -10488,7 +10488,7 @@ async function cloudInstall(provider, repo) {
10488
10488
  return;
10489
10489
  }
10490
10490
  console.log(`\u2192 ${pm} install in ${remoteDir} on box...`);
10491
- const remoteCmd = `cd ${shellQuote(remoteDir)} && ${cmd}`;
10491
+ const remoteCmd = `cd ${shellQuoteHomePath(remoteDir)} && ${cmd}`;
10492
10492
  const code = await runOnBoxStreaming(provider, remoteCmd);
10493
10493
  if (code !== 0) throw new Error(`${pm} install failed (exit ${code})`);
10494
10494
  const existing = readSidecar(provider, repo);
@@ -10504,7 +10504,7 @@ async function cloudInstall(provider, repo) {
10504
10504
  }
10505
10505
  async function cloudSession(provider, repo) {
10506
10506
  const remoteDir = boxRepoPath(repo);
10507
- const cmd = `sis admin home-init ${shellQuote(repo)} ${shellQuote(remoteDir)}`;
10507
+ const cmd = `sis admin home-init ${shellQuote(repo)} ${shellQuoteHomePath(remoteDir)}`;
10508
10508
  console.log(`\u2192 initializing tmux home session "${repo}" on box...`);
10509
10509
  const result = runOnBox(provider, cmd);
10510
10510
  if (result.exitCode !== 0) {
@@ -10528,6 +10528,19 @@ Use a fresh terminal, or run from outside tmux:
10528
10528
  });
10529
10529
  child.on("exit", (code) => process.exit(code === null ? 1 : code));
10530
10530
  }
10531
+ function cloudClaudeLogin(provider) {
10532
+ const target = effectiveSshTarget(provider);
10533
+ const remote = [
10534
+ "command -v claude >/dev/null 2>&1",
10535
+ "|| sudo npm i -g @anthropic-ai/claude-code",
10536
+ "&& claude auth login"
10537
+ ].join(" ");
10538
+ const child = spawn4("ssh", ["-t", target, remote], {
10539
+ stdio: "inherit",
10540
+ env: EXEC_ENV
10541
+ });
10542
+ child.on("exit", (code) => process.exit(code === null ? 1 : code));
10543
+ }
10531
10544
  async function cloudStart(provider, repo, opts) {
10532
10545
  await cloudSync(provider, repo, { fresh: opts.fresh, yes: opts.yes });
10533
10546
  await cloudInstall(provider, repo);
@@ -10610,6 +10623,10 @@ function registerCloud(program2) {
10610
10623
  const { provider, repo } = resolve11(raw);
10611
10624
  await cloudStart(provider, repo, { fresh: raw.fresh === true, yes: raw.yes === true });
10612
10625
  });
10626
+ cloud.command("claude-login").description("Run `claude auth login` on the box (device-code flow; paste the URL into your local browser).").option("--provider <name>", "Cloud provider.").action((raw) => {
10627
+ const provider = pickProvider(raw.provider);
10628
+ cloudClaudeLogin(provider);
10629
+ });
10613
10630
  cloud.command("status").description("Print box-side status for this repo (planted, session running, last sync/install).").option("--name <repo>", "Override the repo name.").option("--provider <name>", "Cloud provider.").action((raw) => {
10614
10631
  const { provider, repo } = resolve11(raw);
10615
10632
  cloudStatus(provider, repo);