@drisp/cli 0.6.9 → 0.6.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/README.md CHANGED
@@ -215,6 +215,7 @@ Connect a machine from **Settings → Runners** in the web console. It shows a o
215
215
  drisp runner connect K7QF-M2PX --hub https://hub.example.com # join the Team and start the Runner as a background service
216
216
  drisp runner connect --hub https://hub.example.com # or print a code to approve in the web console
217
217
  drisp runner status # the saved identity, without its credential, and the service's state
218
+ drisp runner restart # refresh the service definition and restart it, e.g. after npm install -g @drisp/cli@latest
218
219
  drisp runner disconnect [<team>] # leave a Team: stop its Runs there and delete that Team's credential
219
220
  drisp runner recover <run-id> confirmed-stopped # record a failed outcome after an uncertain crash
220
221
  ```
@@ -225,7 +226,7 @@ A machine is one Runner per Team. Connect writes that Team's Runner identity and
225
226
 
226
227
  Any member of the Team can connect their own machine. It joins as a **Personal** Runner named after its hostname, which runs only its owner's Runs; a Team admin approving a printed code may make it a **Team** Runner instead.
227
228
 
228
- Connect then installs and starts a user-level service, so the Runner keeps running when the terminal closes and starts again at login: a LaunchAgent `com.drisp.runner.<installationId>` on macOS (log in `~/Library/Logs/drisp/runner-<installationId>.log`), a systemd user unit `drisp-runner-<installationId>.service` on Linux (log in `journalctl --user -u drisp-runner-<installationId>`). `drisp runner status` prints the service's name. The service runs this drisp installation with the saved identity and the `PATH` you connected from, so it finds the same harnesses; there is no unit file to write. Each installation (a `DRISP_RUNNER_CONFIG` identity file is a separate one) gets its own service, so connecting one never stops another. On a Linux server, `loginctl enable-linger` keeps it running while you are logged out. Running Connect again where the identity file already exists is refused before the code is spent, and leaves the service as it is. So if the service cannot be installed or started, Connect exits with an error but keeps the identity: run `drisp runner` to run the Runner in the foreground. On macOS, a LaunchAgent that was installed but would not start still starts at your next login.
229
+ Connect then installs and starts a user-level service, so the Runner keeps running when the terminal closes and starts again at login: a LaunchAgent `com.drisp.runner.<installationId>` on macOS (log in `~/Library/Logs/drisp/runner-<installationId>.log`), a systemd user unit `drisp-runner-<installationId>.service` on Linux (log in `journalctl --user -u drisp-runner-<installationId>`). `drisp runner status` prints the service's name. `drisp runner restart` rewrites the service definition for the CLI installed now (a new Node version or global prefix) and restarts it (on Linux it also turns start-at-login back on, with `systemctl --user enable`); it never installs a service, and like any Runner restart it fails a Run in progress ([ADR-0021](docs/adr/0021-runner-boot-closes-orphaned-runs.md)), so run it when no Run is executing. The service runs this drisp installation with the saved identity and the `PATH` you connected from, so it finds the same harnesses; there is no unit file to write. Each installation (a `DRISP_RUNNER_CONFIG` identity file is a separate one) gets its own service, so connecting one never stops another. On a Linux server, `loginctl enable-linger` keeps it running while you are logged out. Running Connect again where the identity file already exists is refused before the code is spent, and leaves the service as it is. So if the service cannot be installed or started, Connect exits with an error but keeps the identity: run `drisp runner` to run the Runner in the foreground. On macOS, a LaunchAgent that was installed but would not start still starts at your next login.
229
230
 
230
231
  In a container or CI, or on a platform without launchd or systemd (where Connect says so and does this anyway), keep the Runner in the foreground instead:
231
232
 
@@ -12692,6 +12692,12 @@ import { existsSync as existsSync3, realpathSync } from "fs";
12692
12692
  import { mkdir, readFile, unlink, writeFile } from "fs/promises";
12693
12693
  import { homedir as homedir3 } from "os";
12694
12694
  import { dirname as dirname3, join as join5 } from "path";
12695
+ var ServiceNotEnabledError = class extends Error {
12696
+ constructor(cause) {
12697
+ super(`The service is running now but is not enabled at login: ${cause}`);
12698
+ this.name = "ServiceNotEnabledError";
12699
+ }
12700
+ };
12695
12701
  var runCommand = (command, args) => new Promise((resolve7, reject) => {
12696
12702
  execFile(command, args, { encoding: "utf8" }, (error, stdout, stderr) => {
12697
12703
  if (error && typeof error.code !== "number") reject(error);
@@ -12764,6 +12770,10 @@ function launchdServiceManager({ home, uid, run, installationId }) {
12764
12770
  else await check(run, "launchctl", ["bootstrap", `gui/${uid}`, plist]);
12765
12771
  },
12766
12772
  stop: unload,
12773
+ async restart() {
12774
+ if (await loaded()) await check(run, "launchctl", ["kickstart", "-k", target]);
12775
+ else await check(run, "launchctl", ["bootstrap", `gui/${uid}`, plist]);
12776
+ },
12767
12777
  async remove() {
12768
12778
  await removeFile(plist);
12769
12779
  await unload();
@@ -12826,6 +12836,12 @@ function systemdServiceManager({ home, run, installationId }) {
12826
12836
  async stop() {
12827
12837
  if (await active()) await systemctl("stop", unitName);
12828
12838
  },
12839
+ async restart() {
12840
+ await systemctl("restart", unitName);
12841
+ await systemctl("enable", unitName).catch((error) => {
12842
+ throw new ServiceNotEnabledError(error instanceof Error ? error.message : String(error));
12843
+ });
12844
+ },
12829
12845
  async remove() {
12830
12846
  if (!existsSync3(path23)) return;
12831
12847
  await systemctl("disable", "--now", unitName);
@@ -14852,7 +14868,7 @@ async function restoreCheckpoint(store, input) {
14852
14868
 
14853
14869
  // ../../modules/runtime/src/software-version.ts
14854
14870
  import "fs";
14855
- var runnerSoftwareVersion = true ? "0.6.9" : JSON.parse(readFileSync2(new URL("../../../apps/cli/package.json", import.meta.url), "utf8")).version;
14871
+ var runnerSoftwareVersion = true ? "0.6.10" : JSON.parse(readFileSync2(new URL("../../../apps/cli/package.json", import.meta.url), "utf8")).version;
14856
14872
 
14857
14873
  // ../../modules/runtime/src/connection.ts
14858
14874
  var RunnerDisconnectedError = class extends Error {
@@ -21851,6 +21867,7 @@ export {
21851
21867
  expandHome,
21852
21868
  forgetRunner,
21853
21869
  runConfiguredRunner,
21870
+ ServiceNotEnabledError,
21854
21871
  runnerServiceUnit,
21855
21872
  platformRunnerServices,
21856
21873
  runnerConfigDirectory,
@@ -21863,4 +21880,4 @@ export {
21863
21880
  runMachineRunners,
21864
21881
  writeIdentityOnce
21865
21882
  };
21866
- //# sourceMappingURL=chunk-2JL4QT55.js.map
21883
+ //# sourceMappingURL=chunk-BTHLAJV7.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runMachineRunners
3
- } from "./chunk-2JL4QT55.js";
3
+ } from "./chunk-BTHLAJV7.js";
4
4
 
5
5
  // src/app/entry/runnerDaemon.ts
6
6
  if (process.argv.includes("--help")) {
@@ -13,4 +13,4 @@ if (process.argv.includes("--help")) {
13
13
  process.exitCode = 1;
14
14
  });
15
15
  }
16
- //# sourceMappingURL=chunk-2DLFGWJV.js.map
16
+ //# sourceMappingURL=chunk-LRMKGH2R.js.map
package/dist/cli.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  IndexedTimeline,
8
8
  PORTABLE_PROVIDER_ENV_VARS,
9
9
  RUN_EXIT_CODE,
10
+ ServiceNotEnabledError,
10
11
  attachRuntimeEventLoop,
11
12
  behindMain,
12
13
  bootstrapRuntimeConfig,
@@ -136,7 +137,7 @@ import {
136
137
  visualPositionToOffset,
137
138
  wrapText,
138
139
  writeIdentityOnce
139
- } from "./chunk-2JL4QT55.js";
140
+ } from "./chunk-BTHLAJV7.js";
140
141
  import {
141
142
  generateId as generateId2
142
143
  } from "./chunk-PQIB66SG.js";
@@ -5961,6 +5962,14 @@ function eventLabel(event) {
5961
5962
  return event.data.task_subject || "Task Completed";
5962
5963
  case "config.change":
5963
5964
  return "Config Change";
5965
+ case "instructions.loaded":
5966
+ return "Instructions Loaded";
5967
+ case "worktree.create":
5968
+ return "Worktree Created";
5969
+ case "worktree.remove":
5970
+ return "Worktree Removed";
5971
+ case "artifacts.manifest":
5972
+ return "Artifacts Manifest";
5964
5973
  default:
5965
5974
  return "Event";
5966
5975
  }
@@ -8456,8 +8465,8 @@ function renderHeaderLines(model, width, hasColor, theme) {
8456
8465
  const harnessText = `${style("Harness: ", palette.label)}${style(model.harness, palette.value)}`;
8457
8466
  const effortSuffix = model.effort_level ? style(` with ${model.effort_level} effort`, palette.label) : "";
8458
8467
  const modelText = `${style("Model: ", palette.label)}${style(formatModelName(model.model_name), palette.value)}${effortSuffix}`;
8459
- const tokenLabel = model.token_label ?? "Tokens";
8460
- const runLabel = model.run_label ?? "Runs";
8468
+ const tokenLabel = model.token_label;
8469
+ const runLabel = model.run_label;
8461
8470
  const leftTokens = [
8462
8471
  { text: athena, priority: 100 },
8463
8472
  { text: divider, priority: 5 },
@@ -12606,11 +12615,10 @@ function parseArgs(args, context) {
12606
12615
  } else if (arg === "--global") {
12607
12616
  global = true;
12608
12617
  } else if (arg === "--env") {
12609
- const value = args[i + 1];
12610
- if (value === void 0) {
12618
+ if (i + 1 >= args.length) {
12611
12619
  return { error: `mcp ${context}: --env requires a KEY=VALUE argument` };
12612
12620
  }
12613
- env2.push(value);
12621
+ env2.push(args[i + 1]);
12614
12622
  i++;
12615
12623
  } else if (arg.startsWith("--")) {
12616
12624
  return { error: `Unknown flag for mcp ${context}: ${arg}` };
@@ -13268,7 +13276,7 @@ async function disconnectRunner({
13268
13276
  }
13269
13277
 
13270
13278
  // src/app/entry/runnerCommandV2.ts
13271
- var usage = `Usage: drisp runner [connect [<code>] --hub <url> [--foreground] [--replace] | disconnect [<team>] | status | recover | help]
13279
+ var usage = `Usage: drisp runner [connect [<code>] --hub <url> [--foreground] [--replace] | disconnect [<team>] | status | restart | recover | help]
13272
13280
 
13273
13281
  Connect this machine from Settings \u2192 Runners in the web console, which shows the
13274
13282
  command to paste here:
@@ -13284,8 +13292,11 @@ that runs this machine's Runner for every Team it serves, at login. Connecting a
13284
13292
  the same Team reports the Runner the machine already is and changes nothing. When this
13285
13293
  machine can no longer serve that Runner (its credential is gone or has lapsed), Connect
13286
13294
  says so without using the code, and --replace connects a new Runner in its place.
13287
- drisp runner status lists the Teams and the service's state. --foreground skips the
13288
- service and runs the Runner in this terminal, for containers and CI; drisp runner runs
13295
+ drisp runner status lists the Teams and the service's state. drisp runner restart
13296
+ rewrites the service definition for the CLI installed now and restarts the service
13297
+ (on Linux it also turns start-at-login back on), so run it after
13298
+ npm install -g @drisp/cli@latest; it never installs one, and it fails any Run in
13299
+ progress, so restart when no Run is executing. --foreground skips the service and runs the Runner in this terminal, for containers and CI; drisp runner runs
13289
13300
  every Team's Runner there again later. DRISP_HUB_URL may stand in for --hub, and
13290
13301
  DRISP_RUNNER_CONFIG selects one identity file of a separate installation instead, which
13291
13302
  gets its own service.
@@ -13312,6 +13323,7 @@ The code works once and expires in ${minutes} minutes. Waiting for approval\u202
13312
13323
  );
13313
13324
  }
13314
13325
  var serviceStarted = (service) => `The Runner runs as a background service (${service.kind} ${service.name}) and starts again at login.`;
13326
+ var notConnected = "This machine is not connected to a Team. Settings \u2192 Runners shows the command to connect it.";
13315
13327
  var servicesFor = (options) => options.services === void 0 ? platformRunnerServices() : options.services;
13316
13328
  async function serviceInstallation(config) {
13317
13329
  const single = overriddenIdentityPath();
@@ -13320,25 +13332,35 @@ async function serviceInstallation(config) {
13320
13332
  ...single ? { configPath: single } : {}
13321
13333
  };
13322
13334
  }
13335
+ async function installAndRestart(service, configPath, onInstalled = () => {
13336
+ }) {
13337
+ await service.install(runnerServiceUnit(configPath));
13338
+ onInstalled();
13339
+ await service.restart();
13340
+ }
13323
13341
  async function ensureService(services, config, identityPath) {
13324
13342
  let service;
13325
- let installed = false;
13343
+ const progress = { installed: false };
13326
13344
  try {
13327
13345
  const { installationId, configPath } = await serviceInstallation(config);
13328
13346
  service = services(installationId);
13329
- await service.install(runnerServiceUnit(configPath));
13330
- installed = true;
13331
- if ((await service.status()).running) await service.stop();
13332
- await service.start();
13347
+ await installAndRestart(service, configPath, () => {
13348
+ progress.installed = true;
13349
+ });
13333
13350
  return service;
13334
13351
  } catch (error) {
13352
+ if (error instanceof ServiceNotEnabledError && service)
13353
+ throw new Error(
13354
+ `Connected, and the Runner runs as a background service (${service.kind} ${service.name}). ${error.message}
13355
+ Run drisp runner restart to enable it again.`
13356
+ );
13335
13357
  throw new Error(
13336
13358
  [
13337
13359
  `Connected, but the background service did not start: ${error instanceof Error ? error.message : String(error)}`,
13338
13360
  `The identity is saved to ${identityPath}: run drisp runner to run the Runner in the foreground.`,
13339
13361
  // launchd loads an installed LaunchAgent at the next login and RunAtLoad starts it. A systemd unit
13340
- // is enabled only by the start that just failed, so it has no such fallback.
13341
- ...installed && service?.kind === "launchd" ? [
13362
+ // is enabled only by the restart that just failed, so it has no such fallback.
13363
+ ...progress.installed && service?.kind === "launchd" ? [
13342
13364
  `The LaunchAgent ${service.name} is installed, so launchd starts the Runner at your next login.`
13343
13365
  ] : []
13344
13366
  ].join("\n")
@@ -13346,6 +13368,10 @@ async function ensureService(services, config, identityPath) {
13346
13368
  }
13347
13369
  }
13348
13370
  async function runRunnerCommandV2(input, options = {}) {
13371
+ if (input.flags.help || input.subcommand === "help") {
13372
+ process.stdout.write(usage);
13373
+ return 0;
13374
+ }
13349
13375
  try {
13350
13376
  if (input.flags.detach)
13351
13377
  throw new Error(
@@ -13353,7 +13379,8 @@ async function runRunnerCommandV2(input, options = {}) {
13353
13379
  );
13354
13380
  switch (input.subcommand) {
13355
13381
  case "connect": {
13356
- const [code, extra] = input.subcommandArgs;
13382
+ const code = input.subcommandArgs.at(0);
13383
+ const extra = input.subcommandArgs.at(1);
13357
13384
  if (extra) throw new Error(`Unexpected argument ${extra}.`);
13358
13385
  const hub = input.flags.hub ?? process.env["DRISP_HUB_URL"];
13359
13386
  if (!hub)
@@ -13475,10 +13502,7 @@ async function runRunnerCommandV2(input, options = {}) {
13475
13502
  }
13476
13503
  case "status": {
13477
13504
  const identities = await runnerIdentities();
13478
- if (!identities.length)
13479
- throw new Error(
13480
- "This machine is not connected to a Team. Settings \u2192 Runners shows the command to connect it."
13481
- );
13505
+ if (!identities.length) throw new Error(notConnected);
13482
13506
  const services = servicesFor(options);
13483
13507
  const service = services ? services(
13484
13508
  (await serviceInstallation(identities[0].config)).installationId
@@ -13507,15 +13531,24 @@ async function runRunnerCommandV2(input, options = {}) {
13507
13531
  );
13508
13532
  return 0;
13509
13533
  }
13534
+ case "restart": {
13535
+ const [extra] = input.subcommandArgs;
13536
+ if (extra) throw new Error(`Unexpected argument ${extra}.`);
13537
+ const { service, configPath } = await installedService(
13538
+ servicesFor(options)
13539
+ );
13540
+ await installAndRestart(service, configPath);
13541
+ process.stdout.write(
13542
+ `Restarted the background service ${service.kind} ${service.name}.
13543
+ `
13544
+ );
13545
+ return 0;
13546
+ }
13510
13547
  case "":
13511
13548
  await runMachineRunners(options.signal, {
13512
13549
  services: servicesFor(options)
13513
13550
  });
13514
13551
  return 0;
13515
- case "help":
13516
- case "--help":
13517
- process.stdout.write(usage);
13518
- return 0;
13519
13552
  default:
13520
13553
  throw new Error(
13521
13554
  `Unsupported v2 runner command: ${input.subcommand}.
@@ -13530,6 +13563,25 @@ ${usage}`
13530
13563
  return 1;
13531
13564
  }
13532
13565
  }
13566
+ async function installedService(services) {
13567
+ const identities = await runnerIdentities();
13568
+ if (!identities.length) throw new Error(notConnected);
13569
+ const whose = overriddenIdentityPath() ? "the Runner installation DRISP_RUNNER_CONFIG selects" : "this machine's Runner";
13570
+ const foreground = "drisp runner runs it in the foreground meanwhile.";
13571
+ if (!services)
13572
+ throw new Error(
13573
+ `No background service is installed for ${whose}: there is no launchd or systemd --user here. ${foreground}`
13574
+ );
13575
+ const { installationId, configPath } = await serviceInstallation(
13576
+ identities[0].config
13577
+ );
13578
+ const service = services(installationId);
13579
+ if (!(await service.status()).installed)
13580
+ throw new Error(
13581
+ `No background service is installed for ${whose} (${service.kind} ${service.name}). drisp runner connect installs one when it connects to a Team (Settings \u2192 Runners shows the command); restart never installs one. ${foreground}`
13582
+ );
13583
+ return { service, ...configPath ? { configPath } : {} };
13584
+ }
13533
13585
  async function recoveryIdentity(runId) {
13534
13586
  const identities = await runnerIdentities();
13535
13587
  if (!identities.length)
@@ -15603,7 +15655,7 @@ var cli = meow(
15603
15655
  skill <sub> Manage personal skills (install, remove, list)
15604
15656
  marketplace <sub> Manage marketplace sources (add, refresh, remove, list)
15605
15657
  runner [sub] Run the runner that connects this machine to a Team and executes its Runs
15606
- (no subcommand: foreground; connect [code] --hub <url> [--replace], disconnect [team], status, recover, help)
15658
+ (no subcommand: foreground; connect [code] --hub <url> [--replace], disconnect [team], status, restart, recover, help)
15607
15659
  build plan --input <path> Plan a Build inside an Orchestrator Run (prints one JSON object)
15608
15660
  build tick --input <path> Run one step of a started Build (prints the next action; [--rebase-failed <ID>]...)
15609
15661
  build checks The merge gate's verdict on HEAD's GitHub runs (in a child's worktree)
@@ -15637,7 +15689,7 @@ var cli = meow(
15637
15689
  --dry-run Print resolved bootstrap (workflow, isolation, plugins, harness) and exit (run mode)
15638
15690
  --project Scope workflow command to project config (workflow use)
15639
15691
  --global Scope workflow command to global config (workflow use, default)
15640
- --help Show command help
15692
+ --help, -h Show command help (runner shows its own)
15641
15693
  --version Show CLI version
15642
15694
 
15643
15695
  Note: All isolation modes use --setting-sources "" to completely isolate
@@ -15672,6 +15724,12 @@ var cli = meow(
15672
15724
  importMeta: import.meta,
15673
15725
  allowUnknownFlags: false,
15674
15726
  flags: {
15727
+ // Declared so -h works too; meow alone handles only a bare --help (DRI-193).
15728
+ help: {
15729
+ type: "boolean",
15730
+ shortFlag: "h",
15731
+ default: false
15732
+ },
15675
15733
  projectDir: {
15676
15734
  type: "string",
15677
15735
  default: process.cwd()
@@ -15788,6 +15846,10 @@ Available commands: ${[...KNOWN_COMMANDS].join(", ")}`
15788
15846
  await exitWith(1);
15789
15847
  return;
15790
15848
  }
15849
+ if (cli.flags.help && command !== "runner" && command !== "dashboard") {
15850
+ cli.showHelp(0);
15851
+ return;
15852
+ }
15791
15853
  if (command === "exec") {
15792
15854
  console.error(
15793
15855
  "drisp exec is deprecated and is removed in 0.7.0; use drisp run instead."
@@ -15898,7 +15960,8 @@ Available commands: ${[...KNOWN_COMMANDS].join(", ")}`
15898
15960
  ...cli.flags.detach ? { detach: true } : {},
15899
15961
  ...typeof cli.flags.hub === "string" ? { hub: cli.flags.hub } : {},
15900
15962
  ...cli.flags.foreground ? { foreground: true } : {},
15901
- ...cli.flags.replace ? { replace: true } : {}
15963
+ ...cli.flags.replace ? { replace: true } : {},
15964
+ ...cli.flags.help ? { help: true } : {}
15902
15965
  }
15903
15966
  })
15904
15967
  );
@@ -1,5 +1,5 @@
1
- import "./chunk-2DLFGWJV.js";
2
- import "./chunk-2JL4QT55.js";
1
+ import "./chunk-LRMKGH2R.js";
2
+ import "./chunk-BTHLAJV7.js";
3
3
  import "./chunk-PQIB66SG.js";
4
4
  import "./chunk-YUVMVYUF.js";
5
5
  import "./chunk-G3PMV62Z.js";
package/dist/runner.js CHANGED
@@ -1,5 +1,5 @@
1
- import "./chunk-2DLFGWJV.js";
2
- import "./chunk-2JL4QT55.js";
1
+ import "./chunk-LRMKGH2R.js";
2
+ import "./chunk-BTHLAJV7.js";
3
3
  import "./chunk-PQIB66SG.js";
4
4
  import "./chunk-YUVMVYUF.js";
5
5
  import "./chunk-G3PMV62Z.js";
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "hooks",
18
18
  "dashboard"
19
19
  ],
20
- "version": "0.6.9",
20
+ "version": "0.6.10",
21
21
  "license": "MIT",
22
22
  "bin": {
23
23
  "athena": "dist/cli.js",