@usepowerplant/cli 0.4.13 → 0.4.15

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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="66f773d5-e0b2-5538-a184-3ee15c3a469a")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bdd42bb0-e20a-5100-a257-b6dbb21d0f74")}catch(e){}}();
4
4
  const __cliNodeMajor = Number(process.versions.node.split('.')[0]);
5
5
  if (__cliNodeMajor < 20) {
6
6
  console.error(`powerplant needs Node 20 or newer — this is Node ${process.versions.node}.`);
@@ -6879,19 +6879,19 @@ var require_module_details_from_path = __commonJS({
6879
6879
  basedir += segments[i] + sep2;
6880
6880
  }
6881
6881
  }
6882
- var path32 = "";
6882
+ var path34 = "";
6883
6883
  var lastSegmentIndex = segments.length - 1;
6884
6884
  for (var i2 = index + offset; i2 <= lastSegmentIndex; i2++) {
6885
6885
  if (i2 === lastSegmentIndex) {
6886
- path32 += segments[i2];
6886
+ path34 += segments[i2];
6887
6887
  } else {
6888
- path32 += segments[i2] + sep2;
6888
+ path34 += segments[i2] + sep2;
6889
6889
  }
6890
6890
  }
6891
6891
  return {
6892
6892
  name,
6893
6893
  basedir,
6894
- path: path32
6894
+ path: path34
6895
6895
  };
6896
6896
  };
6897
6897
  }
@@ -6901,7 +6901,7 @@ var require_module_details_from_path = __commonJS({
6901
6901
  var require_require_in_the_middle = __commonJS({
6902
6902
  "../../node_modules/.pnpm/require-in-the-middle@8.0.1/node_modules/require-in-the-middle/index.js"(exports, module2) {
6903
6903
  "use strict";
6904
- var path32 = __require("path");
6904
+ var path34 = __require("path");
6905
6905
  var Module = __require("module");
6906
6906
  var debug2 = require_src3()("require-in-the-middle");
6907
6907
  var moduleDetailsFromPath = require_module_details_from_path();
@@ -7046,7 +7046,7 @@ var require_require_in_the_middle = __commonJS({
7046
7046
  }
7047
7047
  moduleName = filename;
7048
7048
  } else if (hasWhitelist === true && modules.includes(filename)) {
7049
- const parsedPath = path32.parse(filename);
7049
+ const parsedPath = path34.parse(filename);
7050
7050
  moduleName = parsedPath.name;
7051
7051
  basedir = parsedPath.dir;
7052
7052
  } else {
@@ -7084,7 +7084,7 @@ var require_require_in_the_middle = __commonJS({
7084
7084
  }
7085
7085
  if (res !== filename) {
7086
7086
  if (internals === true) {
7087
- moduleName = moduleName + path32.sep + path32.relative(basedir, filename);
7087
+ moduleName = moduleName + path34.sep + path34.relative(basedir, filename);
7088
7088
  debug2("preparing to process require of internal file: %s", moduleName);
7089
7089
  } else {
7090
7090
  debug2("ignoring require of non-main module file: %s", res);
@@ -7120,8 +7120,8 @@ var require_require_in_the_middle = __commonJS({
7120
7120
  }
7121
7121
  };
7122
7122
  function resolveModuleName(stat) {
7123
- const normalizedPath = path32.sep !== "/" ? stat.path.split(path32.sep).join("/") : stat.path;
7124
- return path32.posix.join(stat.name, normalizedPath).replace(normalize3, "");
7123
+ const normalizedPath = path34.sep !== "/" ? stat.path.split(path34.sep).join("/") : stat.path;
7124
+ return path34.posix.join(stat.name, normalizedPath).replace(normalize3, "");
7125
7125
  }
7126
7126
  }
7127
7127
  });
@@ -7206,7 +7206,7 @@ var require_RequireInTheMiddleSingleton = __commonJS({
7206
7206
  Object.defineProperty(exports, "__esModule", { value: true });
7207
7207
  exports.RequireInTheMiddleSingleton = void 0;
7208
7208
  var require_in_the_middle_1 = require_require_in_the_middle();
7209
- var path32 = __require("path");
7209
+ var path34 = __require("path");
7210
7210
  var ModuleNameTrie_1 = require_ModuleNameTrie();
7211
7211
  var isMocha = [
7212
7212
  "afterEach",
@@ -7270,7 +7270,7 @@ var require_RequireInTheMiddleSingleton = __commonJS({
7270
7270
  };
7271
7271
  exports.RequireInTheMiddleSingleton = RequireInTheMiddleSingleton;
7272
7272
  function normalizePathSeparators(moduleNameOrPath) {
7273
- return path32.sep !== ModuleNameTrie_1.ModuleNameSeparator ? moduleNameOrPath.split(path32.sep).join(ModuleNameTrie_1.ModuleNameSeparator) : moduleNameOrPath;
7273
+ return path34.sep !== ModuleNameTrie_1.ModuleNameSeparator ? moduleNameOrPath.split(path34.sep).join(ModuleNameTrie_1.ModuleNameSeparator) : moduleNameOrPath;
7274
7274
  }
7275
7275
  }
7276
7276
  });
@@ -7480,7 +7480,7 @@ var require_register = __commonJS({
7480
7480
  // ../../node_modules/.pnpm/import-in-the-middle@3.5.1/node_modules/import-in-the-middle/index.js
7481
7481
  var require_import_in_the_middle = __commonJS({
7482
7482
  "../../node_modules/.pnpm/import-in-the-middle@3.5.1/node_modules/import-in-the-middle/index.js"(exports, module2) {
7483
- var path32 = __require("path");
7483
+ var path34 = __require("path");
7484
7484
  var moduleDetailsFromPath = require_module_details_from_path();
7485
7485
  var { fileURLToPath: fileURLToPath3 } = __require("url");
7486
7486
  var { MessageChannel } = __require("worker_threads");
@@ -7599,7 +7599,7 @@ var require_import_in_the_middle = __commonJS({
7599
7599
  } else if (baseDir.endsWith(specifiers.get(loadUrl)) || isTurbopackSpecifier(specifiers.get(loadUrl), baseDir)) {
7600
7600
  callHookFn(hookFn, namespace, name, baseDir);
7601
7601
  } else if (internals) {
7602
- const internalPath = name + path32.sep + path32.relative(baseDir, filePath);
7602
+ const internalPath = name + path34.sep + path34.relative(baseDir, filePath);
7603
7603
  callHookFn(hookFn, namespace, internalPath, baseDir);
7604
7604
  }
7605
7605
  } else if (matchArg === specifier) {
@@ -7674,7 +7674,7 @@ var require_instrumentation2 = __commonJS({
7674
7674
  "use strict";
7675
7675
  Object.defineProperty(exports, "__esModule", { value: true });
7676
7676
  exports.InstrumentationBase = void 0;
7677
- var path32 = __require("path");
7677
+ var path34 = __require("path");
7678
7678
  var util_1 = __require("util");
7679
7679
  var semver_1 = require_semver();
7680
7680
  var shimmer_1 = require_shimmer();
@@ -7775,7 +7775,7 @@ var require_instrumentation2 = __commonJS({
7775
7775
  }
7776
7776
  _extractPackageVersion(baseDir) {
7777
7777
  try {
7778
- const json2 = (0, fs_1.readFileSync)(path32.join(baseDir, "package.json"), {
7778
+ const json2 = (0, fs_1.readFileSync)(path34.join(baseDir, "package.json"), {
7779
7779
  encoding: "utf8"
7780
7780
  });
7781
7781
  const version2 = JSON.parse(json2).version;
@@ -7817,7 +7817,7 @@ var require_instrumentation2 = __commonJS({
7817
7817
  return exports2;
7818
7818
  }
7819
7819
  const files = module3.files ?? [];
7820
- const normalizedName = path32.normalize(name);
7820
+ const normalizedName = path34.normalize(name);
7821
7821
  const supportedFileInstrumentations = files.filter((f) => f.name === normalizedName && isSupported(f.supportedVersions, version2, module3.includePrerelease));
7822
7822
  return supportedFileInstrumentations.reduce((patchedExports, file2) => {
7823
7823
  file2.moduleExports = patchedExports;
@@ -7863,8 +7863,8 @@ var require_instrumentation2 = __commonJS({
7863
7863
  this._warnOnPreloadedModules();
7864
7864
  for (const module3 of this._modules) {
7865
7865
  const hookFn = (exports2, name, baseDir) => {
7866
- if (!baseDir && path32.isAbsolute(name)) {
7867
- const parsedPath = path32.parse(name);
7866
+ if (!baseDir && path34.isAbsolute(name)) {
7867
+ const parsedPath = path34.parse(name);
7868
7868
  name = parsedPath.name;
7869
7869
  baseDir = parsedPath.dir;
7870
7870
  }
@@ -7873,7 +7873,7 @@ var require_instrumentation2 = __commonJS({
7873
7873
  const onRequire = (exports2, name, baseDir) => {
7874
7874
  return this._onRequire(module3, exports2, name, baseDir);
7875
7875
  };
7876
- const hook = path32.isAbsolute(module3.name) ? new require_in_the_middle_1.Hook([module3.name], { internals: true }, onRequire) : this._requireInTheMiddleSingleton.register(module3.name, onRequire);
7876
+ const hook = path34.isAbsolute(module3.name) ? new require_in_the_middle_1.Hook([module3.name], { internals: true }, onRequire) : this._requireInTheMiddleSingleton.register(module3.name, onRequire);
7877
7877
  this._hooks.push(hook);
7878
7878
  const esmHook = new import_in_the_middle_1.Hook([module3.name], { internals: true }, hookFn);
7879
7879
  this._hooks.push(esmHook);
@@ -8481,9 +8481,9 @@ var require_getMachineId_linux = __commonJS({
8481
8481
  var api_1 = (init_esm(), __toCommonJS(esm_exports));
8482
8482
  async function getMachineId() {
8483
8483
  const paths = ["/etc/machine-id", "/var/lib/dbus/machine-id"];
8484
- for (const path32 of paths) {
8484
+ for (const path34 of paths) {
8485
8485
  try {
8486
- const result = await fs_1.promises.readFile(path32, { encoding: "utf8" });
8486
+ const result = await fs_1.promises.readFile(path34, { encoding: "utf8" });
8487
8487
  return result.trim();
8488
8488
  } catch (e) {
8489
8489
  api_1.diag.debug(`error reading machine id: ${e}`);
@@ -11843,14 +11843,14 @@ var require_util = __commonJS({
11843
11843
  }
11844
11844
  const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80;
11845
11845
  let origin = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`;
11846
- let path32 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
11846
+ let path34 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
11847
11847
  if (origin[origin.length - 1] === "/") {
11848
11848
  origin = origin.slice(0, origin.length - 1);
11849
11849
  }
11850
- if (path32 && path32[0] !== "/") {
11851
- path32 = `/${path32}`;
11850
+ if (path34 && path34[0] !== "/") {
11851
+ path34 = `/${path34}`;
11852
11852
  }
11853
- return new URL(`${origin}${path32}`);
11853
+ return new URL(`${origin}${path34}`);
11854
11854
  }
11855
11855
  if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) {
11856
11856
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -12671,9 +12671,9 @@ var require_diagnostics = __commonJS({
12671
12671
  "undici:client:sendHeaders",
12672
12672
  (evt) => {
12673
12673
  const {
12674
- request: { method, path: path32, origin }
12674
+ request: { method, path: path34, origin }
12675
12675
  } = evt;
12676
- debugLog3("sending request to %s %s%s", method, origin, path32);
12676
+ debugLog3("sending request to %s %s%s", method, origin, path34);
12677
12677
  }
12678
12678
  );
12679
12679
  }
@@ -12691,14 +12691,14 @@ var require_diagnostics = __commonJS({
12691
12691
  "undici:request:headers",
12692
12692
  (evt) => {
12693
12693
  const {
12694
- request: { method, path: path32, origin },
12694
+ request: { method, path: path34, origin },
12695
12695
  response: { statusCode }
12696
12696
  } = evt;
12697
12697
  debugLog3(
12698
12698
  "received response to %s %s%s - HTTP %d",
12699
12699
  method,
12700
12700
  origin,
12701
- path32,
12701
+ path34,
12702
12702
  statusCode
12703
12703
  );
12704
12704
  }
@@ -12707,23 +12707,23 @@ var require_diagnostics = __commonJS({
12707
12707
  "undici:request:trailers",
12708
12708
  (evt) => {
12709
12709
  const {
12710
- request: { method, path: path32, origin }
12710
+ request: { method, path: path34, origin }
12711
12711
  } = evt;
12712
- debugLog3("trailers received from %s %s%s", method, origin, path32);
12712
+ debugLog3("trailers received from %s %s%s", method, origin, path34);
12713
12713
  }
12714
12714
  );
12715
12715
  diagnosticsChannel9.subscribe(
12716
12716
  "undici:request:error",
12717
12717
  (evt) => {
12718
12718
  const {
12719
- request: { method, path: path32, origin },
12719
+ request: { method, path: path34, origin },
12720
12720
  error: error63
12721
12721
  } = evt;
12722
12722
  debugLog3(
12723
12723
  "request to %s %s%s errored - %s",
12724
12724
  method,
12725
12725
  origin,
12726
- path32,
12726
+ path34,
12727
12727
  error63.message
12728
12728
  );
12729
12729
  }
@@ -12838,7 +12838,7 @@ var require_request = __commonJS({
12838
12838
  var kHandler = /* @__PURE__ */ Symbol("handler");
12839
12839
  var Request2 = class {
12840
12840
  constructor(origin, {
12841
- path: path32,
12841
+ path: path34,
12842
12842
  method,
12843
12843
  body,
12844
12844
  headers,
@@ -12855,11 +12855,11 @@ var require_request = __commonJS({
12855
12855
  maxRedirections,
12856
12856
  typeOfService
12857
12857
  }, handler) {
12858
- if (typeof path32 !== "string") {
12858
+ if (typeof path34 !== "string") {
12859
12859
  throw new InvalidArgumentError("path must be a string");
12860
- } else if (path32[0] !== "/" && !(path32.startsWith("http://") || path32.startsWith("https://")) && method !== "CONNECT") {
12860
+ } else if (path34[0] !== "/" && !(path34.startsWith("http://") || path34.startsWith("https://")) && method !== "CONNECT") {
12861
12861
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
12862
- } else if (invalidPathRegex.test(path32)) {
12862
+ } else if (invalidPathRegex.test(path34)) {
12863
12863
  throw new InvalidArgumentError("invalid request path");
12864
12864
  }
12865
12865
  if (typeof method !== "string") {
@@ -12934,7 +12934,7 @@ var require_request = __commonJS({
12934
12934
  this.completed = false;
12935
12935
  this.aborted = false;
12936
12936
  this.upgrade = upgrade || null;
12937
- this.path = query ? serializePathWithQuery(path32, query) : path32;
12937
+ this.path = query ? serializePathWithQuery(path34, query) : path34;
12938
12938
  this.origin = origin;
12939
12939
  this.protocol = getProtocolFromUrlString(origin);
12940
12940
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -18116,7 +18116,7 @@ var require_client_h1 = __commonJS({
18116
18116
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
18117
18117
  }
18118
18118
  function writeH1(client, request2) {
18119
- const { method, path: path32, host, upgrade, blocking, reset } = request2;
18119
+ const { method, path: path34, host, upgrade, blocking, reset } = request2;
18120
18120
  let { body, headers, contentLength } = request2;
18121
18121
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
18122
18122
  if (util2.isFormDataLike(body)) {
@@ -18194,7 +18194,7 @@ var require_client_h1 = __commonJS({
18194
18194
  if (socket.setTypeOfService) {
18195
18195
  socket.setTypeOfService(request2.typeOfService);
18196
18196
  }
18197
- let header = `${method} ${path32} HTTP/1.1\r
18197
+ let header = `${method} ${path34} HTTP/1.1\r
18198
18198
  `;
18199
18199
  if (typeof host === "string") {
18200
18200
  header += `host: ${host}\r
@@ -18873,7 +18873,7 @@ var require_client_h2 = __commonJS({
18873
18873
  const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout];
18874
18874
  const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
18875
18875
  const session = client[kHTTP2Session];
18876
- const { method, path: path32, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
18876
+ const { method, path: path34, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
18877
18877
  let { body } = request2;
18878
18878
  if (upgrade != null && upgrade !== "websocket") {
18879
18879
  util2.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -18942,7 +18942,7 @@ var require_client_h2 = __commonJS({
18942
18942
  }
18943
18943
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
18944
18944
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
18945
- headers[HTTP2_HEADER_PATH] = path32;
18945
+ headers[HTTP2_HEADER_PATH] = path34;
18946
18946
  if (protocol === "ws:" || protocol === "wss:") {
18947
18947
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
18948
18948
  } else {
@@ -18984,7 +18984,7 @@ var require_client_h2 = __commonJS({
18984
18984
  stream.setTimeout(headersTimeout);
18985
18985
  return true;
18986
18986
  }
18987
- headers[HTTP2_HEADER_PATH] = path32;
18987
+ headers[HTTP2_HEADER_PATH] = path34;
18988
18988
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
18989
18989
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
18990
18990
  if (body && typeof body.read === "function") {
@@ -21336,10 +21336,10 @@ var require_proxy_agent = __commonJS({
21336
21336
  };
21337
21337
  const {
21338
21338
  origin,
21339
- path: path32 = "/",
21339
+ path: path34 = "/",
21340
21340
  headers = {}
21341
21341
  } = opts;
21342
- opts.path = origin + path32;
21342
+ opts.path = origin + path34;
21343
21343
  if (!("host" in headers) && !("Host" in headers)) {
21344
21344
  const { host } = new URL(origin);
21345
21345
  headers.host = host;
@@ -23448,20 +23448,20 @@ var require_mock_utils = __commonJS({
23448
23448
  }
23449
23449
  return normalizedQp;
23450
23450
  }
23451
- function safeUrl(path32) {
23452
- if (typeof path32 !== "string") {
23453
- return path32;
23451
+ function safeUrl(path34) {
23452
+ if (typeof path34 !== "string") {
23453
+ return path34;
23454
23454
  }
23455
- const pathSegments = path32.split("?", 3);
23455
+ const pathSegments = path34.split("?", 3);
23456
23456
  if (pathSegments.length !== 2) {
23457
- return path32;
23457
+ return path34;
23458
23458
  }
23459
23459
  const qp = new URLSearchParams(pathSegments.pop());
23460
23460
  qp.sort();
23461
23461
  return [...pathSegments, qp.toString()].join("?");
23462
23462
  }
23463
- function matchKey(mockDispatch2, { path: path32, method, body, headers }) {
23464
- const pathMatch = matchValue(mockDispatch2.path, path32);
23463
+ function matchKey(mockDispatch2, { path: path34, method, body, headers }) {
23464
+ const pathMatch = matchValue(mockDispatch2.path, path34);
23465
23465
  const methodMatch = matchValue(mockDispatch2.method, method);
23466
23466
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
23467
23467
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -23486,8 +23486,8 @@ var require_mock_utils = __commonJS({
23486
23486
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
23487
23487
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
23488
23488
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
23489
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path32, ignoreTrailingSlash }) => {
23490
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path32)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path32), resolvedPath);
23489
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path34, ignoreTrailingSlash }) => {
23490
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path34)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path34), resolvedPath);
23491
23491
  });
23492
23492
  if (matchedMockDispatches.length === 0) {
23493
23493
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -23526,19 +23526,19 @@ var require_mock_utils = __commonJS({
23526
23526
  mockDispatches.splice(index, 1);
23527
23527
  }
23528
23528
  }
23529
- function removeTrailingSlash(path32) {
23530
- while (path32.endsWith("/")) {
23531
- path32 = path32.slice(0, -1);
23529
+ function removeTrailingSlash(path34) {
23530
+ while (path34.endsWith("/")) {
23531
+ path34 = path34.slice(0, -1);
23532
23532
  }
23533
- if (path32.length === 0) {
23534
- path32 = "/";
23533
+ if (path34.length === 0) {
23534
+ path34 = "/";
23535
23535
  }
23536
- return path32;
23536
+ return path34;
23537
23537
  }
23538
23538
  function buildKey(opts) {
23539
- const { path: path32, method, body, headers, query } = opts;
23539
+ const { path: path34, method, body, headers, query } = opts;
23540
23540
  return {
23541
- path: path32,
23541
+ path: path34,
23542
23542
  method,
23543
23543
  body,
23544
23544
  headers,
@@ -24228,10 +24228,10 @@ var require_pending_interceptors_formatter = __commonJS({
24228
24228
  }
24229
24229
  format(pendingInterceptors) {
24230
24230
  const withPrettyHeaders = pendingInterceptors.map(
24231
- ({ method, path: path32, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
24231
+ ({ method, path: path34, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
24232
24232
  Method: method,
24233
24233
  Origin: origin,
24234
- Path: path32,
24234
+ Path: path34,
24235
24235
  "Status code": statusCode,
24236
24236
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
24237
24237
  Invocations: timesInvoked,
@@ -24313,9 +24313,9 @@ var require_mock_agent = __commonJS({
24313
24313
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
24314
24314
  const dispatchOpts = { ...opts };
24315
24315
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
24316
- const [path32, searchParams] = dispatchOpts.path.split("?");
24316
+ const [path34, searchParams] = dispatchOpts.path.split("?");
24317
24317
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
24318
- dispatchOpts.path = `${path32}?${normalizedSearchParams}`;
24318
+ dispatchOpts.path = `${path34}?${normalizedSearchParams}`;
24319
24319
  }
24320
24320
  return this[kAgent].dispatch(dispatchOpts, handler);
24321
24321
  }
@@ -24716,12 +24716,12 @@ var require_snapshot_recorder = __commonJS({
24716
24716
  * @return {Promise<void>} - Resolves when snapshots are loaded
24717
24717
  */
24718
24718
  async loadSnapshots(filePath) {
24719
- const path32 = filePath || this.#snapshotPath;
24720
- if (!path32) {
24719
+ const path34 = filePath || this.#snapshotPath;
24720
+ if (!path34) {
24721
24721
  throw new InvalidArgumentError("Snapshot path is required");
24722
24722
  }
24723
24723
  try {
24724
- const data = await readFile3(resolve2(path32), "utf8");
24724
+ const data = await readFile3(resolve2(path34), "utf8");
24725
24725
  const parsed = JSON.parse(data);
24726
24726
  if (Array.isArray(parsed)) {
24727
24727
  this.#snapshots.clear();
@@ -24735,7 +24735,7 @@ var require_snapshot_recorder = __commonJS({
24735
24735
  if (error63.code === "ENOENT") {
24736
24736
  this.#snapshots.clear();
24737
24737
  } else {
24738
- throw new UndiciError(`Failed to load snapshots from ${path32}`, { cause: error63 });
24738
+ throw new UndiciError(`Failed to load snapshots from ${path34}`, { cause: error63 });
24739
24739
  }
24740
24740
  }
24741
24741
  }
@@ -24746,11 +24746,11 @@ var require_snapshot_recorder = __commonJS({
24746
24746
  * @returns {Promise<void>} - Resolves when snapshots are saved
24747
24747
  */
24748
24748
  async saveSnapshots(filePath) {
24749
- const path32 = filePath || this.#snapshotPath;
24750
- if (!path32) {
24749
+ const path34 = filePath || this.#snapshotPath;
24750
+ if (!path34) {
24751
24751
  throw new InvalidArgumentError("Snapshot path is required");
24752
24752
  }
24753
- const resolvedPath = resolve2(path32);
24753
+ const resolvedPath = resolve2(path34);
24754
24754
  await mkdir(dirname2(resolvedPath), { recursive: true });
24755
24755
  const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
24756
24756
  hash: hash2,
@@ -25382,15 +25382,15 @@ var require_redirect_handler = __commonJS({
25382
25382
  return;
25383
25383
  }
25384
25384
  const { origin, pathname, search } = util2.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
25385
- const path32 = search ? `${pathname}${search}` : pathname;
25386
- const redirectUrlString = `${origin}${path32}`;
25385
+ const path34 = search ? `${pathname}${search}` : pathname;
25386
+ const redirectUrlString = `${origin}${path34}`;
25387
25387
  for (const historyUrl of this.history) {
25388
25388
  if (historyUrl.toString() === redirectUrlString) {
25389
25389
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
25390
25390
  }
25391
25391
  }
25392
25392
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
25393
- this.opts.path = path32;
25393
+ this.opts.path = path34;
25394
25394
  this.opts.origin = origin;
25395
25395
  this.opts.query = null;
25396
25396
  }
@@ -27150,10 +27150,10 @@ var require_cache_handler = __commonJS({
27150
27150
  }
27151
27151
  return locationUrl.pathname + locationUrl.search;
27152
27152
  }
27153
- function deleteCachedUri(store, cacheKey, path32) {
27153
+ function deleteCachedUri(store, cacheKey, path34) {
27154
27154
  deleteCachedValue(store, {
27155
27155
  ...cacheKey,
27156
- path: path32
27156
+ path: path34
27157
27157
  });
27158
27158
  for (let i = 0; i < util2.safeHTTPMethods.length; i++) {
27159
27159
  const method = util2.safeHTTPMethods[i];
@@ -27161,7 +27161,7 @@ var require_cache_handler = __commonJS({
27161
27161
  deleteCachedValue(store, {
27162
27162
  ...cacheKey,
27163
27163
  method,
27164
- path: path32
27164
+ path: path34
27165
27165
  });
27166
27166
  }
27167
27167
  }
@@ -27172,9 +27172,9 @@ var require_cache_handler = __commonJS({
27172
27172
  }
27173
27173
  const values = Array.isArray(headerValue) ? headerValue : [headerValue];
27174
27174
  for (let i = 0; i < values.length; i++) {
27175
- const path32 = getSameOriginPath(cacheKey, values[i]);
27176
- if (path32 !== void 0) {
27177
- deleteCachedUri(store, cacheKey, path32);
27175
+ const path34 = getSameOriginPath(cacheKey, values[i]);
27176
+ if (path34 !== void 0) {
27177
+ deleteCachedUri(store, cacheKey, path34);
27178
27178
  }
27179
27179
  }
27180
27180
  }
@@ -32174,11 +32174,11 @@ var require_fetch = __commonJS({
32174
32174
  function dispatch({ body }) {
32175
32175
  const url2 = requestCurrentURL(request2);
32176
32176
  const agent = fetchParams.controller.dispatcher;
32177
- const path32 = url2.pathname + url2.search;
32177
+ const path34 = url2.pathname + url2.search;
32178
32178
  const hasTrailingQuestionMark = url2.search.length === 0 && url2.href[url2.href.length - url2.hash.length - 1] === "?";
32179
32179
  return new Promise((resolve2, reject) => agent.dispatch(
32180
32180
  {
32181
- path: hasTrailingQuestionMark ? `${path32}?` : path32,
32181
+ path: hasTrailingQuestionMark ? `${path34}?` : path34,
32182
32182
  origin: url2.origin,
32183
32183
  method: request2.method,
32184
32184
  body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
@@ -33125,9 +33125,9 @@ var require_util4 = __commonJS({
33125
33125
  }
33126
33126
  }
33127
33127
  }
33128
- function validateCookiePath(path32) {
33129
- for (let i = 0; i < path32.length; ++i) {
33130
- const code = path32.charCodeAt(i);
33128
+ function validateCookiePath(path34) {
33129
+ for (let i = 0; i < path34.length; ++i) {
33130
+ const code = path34.charCodeAt(i);
33131
33131
  if (code < 32 || // exclude CTLs (0-31)
33132
33132
  code > 126 || // exclude DEL and non-ascii
33133
33133
  code === 59) {
@@ -36475,11 +36475,11 @@ var require_undici = __commonJS({
36475
36475
  if (typeof opts.path !== "string") {
36476
36476
  throw new InvalidArgumentError("invalid opts.path");
36477
36477
  }
36478
- let path32 = opts.path;
36478
+ let path34 = opts.path;
36479
36479
  if (!opts.path.startsWith("/")) {
36480
- path32 = `/${path32}`;
36480
+ path34 = `/${path34}`;
36481
36481
  }
36482
- url2 = new URL(util2.parseOrigin(url2).origin + path32);
36482
+ url2 = new URL(util2.parseOrigin(url2).origin + path34);
36483
36483
  } else {
36484
36484
  if (!opts) {
36485
36485
  opts = typeof url2 === "object" ? url2 : {};
@@ -36588,10 +36588,11 @@ ${captureLines}` : capture.stack;
36588
36588
  }
36589
36589
  });
36590
36590
 
36591
- // src/clientFailure.ts
36592
- import { constants } from "node:os";
36591
+ // src/hookPreferences.ts
36592
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync11, renameSync as renameSync5, writeFileSync as writeFileSync9 } from "node:fs";
36593
+ import path21 from "node:path";
36593
36594
 
36594
- // ../../apps/collector/src/credentials.ts
36595
+ // ../../apps/syncservice/src/credentials.ts
36595
36596
  import { chmodSync as chmodSync4, existsSync as existsSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync8, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "node:fs";
36596
36597
  import os12 from "node:os";
36597
36598
  import path14 from "node:path";
@@ -37412,10 +37413,10 @@ function mergeDefs(...defs) {
37412
37413
  function cloneDef(schema) {
37413
37414
  return mergeDefs(schema._zod.def);
37414
37415
  }
37415
- function getElementAtPath(obj, path32) {
37416
- if (!path32)
37416
+ function getElementAtPath(obj, path34) {
37417
+ if (!path34)
37417
37418
  return obj;
37418
- return path32.reduce((acc, key) => acc?.[key], obj);
37419
+ return path34.reduce((acc, key) => acc?.[key], obj);
37419
37420
  }
37420
37421
  function promiseAllObject(promisesObj) {
37421
37422
  const keys = Object.keys(promisesObj);
@@ -37755,11 +37756,11 @@ function explicitlyAborted(x, startIndex = 0) {
37755
37756
  }
37756
37757
  return false;
37757
37758
  }
37758
- function prefixIssues(path32, issues) {
37759
+ function prefixIssues(path34, issues) {
37759
37760
  return issues.map((iss) => {
37760
37761
  var _a4;
37761
37762
  (_a4 = iss).path ?? (_a4.path = []);
37762
- iss.path.unshift(path32);
37763
+ iss.path.unshift(path34);
37763
37764
  return iss;
37764
37765
  });
37765
37766
  }
@@ -38209,16 +38210,16 @@ function flattenError(error63, mapper = (issue2) => issue2.message) {
38209
38210
  }
38210
38211
  function formatError(error63, mapper = (issue2) => issue2.message) {
38211
38212
  const fieldErrors = { _errors: [] };
38212
- const processError = (error64, path32 = []) => {
38213
+ const processError = (error64, path34 = []) => {
38213
38214
  for (const issue2 of error64.issues) {
38214
38215
  if (issue2.code === "invalid_union" && issue2.errors.length) {
38215
- issue2.errors.map((issues) => processError({ issues }, [...path32, ...issue2.path]));
38216
+ issue2.errors.map((issues) => processError({ issues }, [...path34, ...issue2.path]));
38216
38217
  } else if (issue2.code === "invalid_key") {
38217
- processError({ issues: issue2.issues }, [...path32, ...issue2.path]);
38218
+ processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
38218
38219
  } else if (issue2.code === "invalid_element") {
38219
- processError({ issues: issue2.issues }, [...path32, ...issue2.path]);
38220
+ processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
38220
38221
  } else {
38221
- const fullpath = [...path32, ...issue2.path];
38222
+ const fullpath = [...path34, ...issue2.path];
38222
38223
  if (fullpath.length === 0) {
38223
38224
  fieldErrors._errors.push(mapper(issue2));
38224
38225
  } else {
@@ -38257,17 +38258,17 @@ function formatError(error63, mapper = (issue2) => issue2.message) {
38257
38258
  }
38258
38259
  function treeifyError(error63, mapper = (issue2) => issue2.message) {
38259
38260
  const result = { errors: [] };
38260
- const processError = (error64, path32 = []) => {
38261
+ const processError = (error64, path34 = []) => {
38261
38262
  var _a4;
38262
38263
  for (const issue2 of error64.issues) {
38263
38264
  if (issue2.code === "invalid_union" && issue2.errors.length) {
38264
- issue2.errors.map((issues) => processError({ issues }, [...path32, ...issue2.path]));
38265
+ issue2.errors.map((issues) => processError({ issues }, [...path34, ...issue2.path]));
38265
38266
  } else if (issue2.code === "invalid_key") {
38266
- processError({ issues: issue2.issues }, [...path32, ...issue2.path]);
38267
+ processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
38267
38268
  } else if (issue2.code === "invalid_element") {
38268
- processError({ issues: issue2.issues }, [...path32, ...issue2.path]);
38269
+ processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
38269
38270
  } else {
38270
- const fullpath = [...path32, ...issue2.path];
38271
+ const fullpath = [...path34, ...issue2.path];
38271
38272
  if (fullpath.length === 0) {
38272
38273
  result.errors.push(mapper(issue2));
38273
38274
  continue;
@@ -38306,8 +38307,8 @@ function treeifyError(error63, mapper = (issue2) => issue2.message) {
38306
38307
  }
38307
38308
  function toDotPath(_path) {
38308
38309
  const segs = [];
38309
- const path32 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
38310
- for (const seg of path32) {
38310
+ const path34 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
38311
+ for (const seg of path34) {
38311
38312
  if (typeof seg === "number")
38312
38313
  segs.push(`[${seg}]`);
38313
38314
  else if (typeof seg === "symbol")
@@ -55409,13 +55410,13 @@ function resolveRef(ref, ctx) {
55409
55410
  if (!ref.startsWith("#")) {
55410
55411
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
55411
55412
  }
55412
- const path32 = ref.slice(1).split("/").filter(Boolean);
55413
- if (path32.length === 0) {
55413
+ const path34 = ref.slice(1).split("/").filter(Boolean);
55414
+ if (path34.length === 0) {
55414
55415
  return ctx.rootSchema;
55415
55416
  }
55416
55417
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
55417
- if (path32[0] === defsKey) {
55418
- const key = path32[1] === void 0 ? void 0 : decodeJSONPointerSegment(path32[1]);
55418
+ if (path34[0] === defsKey) {
55419
+ const key = path34[1] === void 0 ? void 0 : decodeJSONPointerSegment(path34[1]);
55419
55420
  if (!key || !ctx.defs[key]) {
55420
55421
  throw new Error(`Reference not found: ${ref}`);
55421
55422
  }
@@ -56264,6 +56265,96 @@ function date4(params) {
56264
56265
  return _coercedDate(ZodDate, params);
56265
56266
  }
56266
56267
 
56268
+ // ../core/src/mcpWarning.ts
56269
+ var mcpClientSchema = external_exports.enum(["claude", "codex", "cursor"]);
56270
+ var mcpWarningSchema = external_exports.enum(["not-connected", "sign-in-needed", "different-url"]);
56271
+ var mcpWarningDismissalSchema = external_exports.object({
56272
+ client: mcpClientSchema,
56273
+ warning: mcpWarningSchema
56274
+ }).strict();
56275
+
56276
+ // ../core/src/harnesses.ts
56277
+ var HARNESSES = [
56278
+ "claude-local",
56279
+ "claude-cloud",
56280
+ "codex-local",
56281
+ "codex-cloud",
56282
+ "cursor-local",
56283
+ "cursor-cloud"
56284
+ ];
56285
+ var harnessSchema = external_exports.enum(HARNESSES);
56286
+ var SESSION_SOURCE_HARNESSES = {
56287
+ "claude-code": "claude-local",
56288
+ "claude-cloud": "claude-cloud",
56289
+ codex: "codex-local",
56290
+ cursor: "cursor-local",
56291
+ "cursor-cloud": "cursor-cloud"
56292
+ };
56293
+ function harnessFromLegacySessionSource(source) {
56294
+ if (source === "github-pr") return { kind: "not-harness", source };
56295
+ return { kind: "harness", harness: SESSION_SOURCE_HARNESSES[source] };
56296
+ }
56297
+ var LEGACY_SESSION_SOURCE_BY_HARNESS = {
56298
+ "claude-local": "claude-code",
56299
+ "claude-cloud": "claude-cloud",
56300
+ "codex-local": "codex",
56301
+ "codex-cloud": null,
56302
+ "cursor-local": "cursor",
56303
+ "cursor-cloud": "cursor-cloud"
56304
+ };
56305
+ function legacySessionSourceFromHarness(harness) {
56306
+ const source = LEGACY_SESSION_SOURCE_BY_HARNESS[harness];
56307
+ return source === null ? { kind: "unsupported", harness } : { kind: "supported", source };
56308
+ }
56309
+
56310
+ // ../core/src/sessionIngest.ts
56311
+ var LEGACY_SESSION_SOURCES = [
56312
+ "claude-code",
56313
+ "claude-cloud",
56314
+ "codex",
56315
+ "cursor",
56316
+ "cursor-cloud",
56317
+ "github-pr"
56318
+ ];
56319
+ var SESSION_SPEED_MODES = ["standard", "fast"];
56320
+ var SESSION_SPEED_OBSERVATIONS = [...SESSION_SPEED_MODES, "unknown"];
56321
+ function isLegacySessionSource(source) {
56322
+ return typeof source === "string" && LEGACY_SESSION_SOURCES.includes(source);
56323
+ }
56324
+ var SESSION_ACTIVE_WINDOW_MS = 30 * 60 * 1e3;
56325
+ var LEGACY_COLLECTOR_SESSION_SOURCES = ["claude-code", "codex", "cursor"];
56326
+ var LEGACY_PREVIEW_REGISTRABLE_SOURCES = [
56327
+ ...LEGACY_COLLECTOR_SESSION_SOURCES,
56328
+ "cursor-cloud"
56329
+ ];
56330
+ var COLLECTOR_SESSION_HARNESSES = [
56331
+ "claude-local",
56332
+ "codex-local",
56333
+ "cursor-local"
56334
+ ];
56335
+ var PREVIEW_REGISTRABLE_HARNESSES = [
56336
+ ...COLLECTOR_SESSION_HARNESSES,
56337
+ "cursor-cloud"
56338
+ ];
56339
+ var MAX_INGEST_BATCH = 500;
56340
+ var MAX_RAW_UPLOAD_BYTES = 256 * 1024 * 1024;
56341
+ var MAX_PREVIEW_URL_LENGTH = 2e3;
56342
+ var MAX_REGISTERED_PREVIEWS = 10;
56343
+ var MAX_PREVIEW_LABEL_LENGTH = 60;
56344
+ var MAX_BRANCH_FACTS = 50;
56345
+
56346
+ // ../core/src/menubarAnalytics.ts
56347
+ var MENUBAR_AGENT_CLICK = "menubar:agent_click";
56348
+ var MENUBAR_MCP_WARNING_REMOVE = "menubar:mcp_warning_remove";
56349
+ var menubarAgentClickSchema = external_exports.object({
56350
+ source: external_exports.enum([...LEGACY_SESSION_SOURCES, "unknown"]),
56351
+ destination: external_exports.enum(["focus", "resume", "desktop", "web"])
56352
+ }).strict();
56353
+ var menubarEventSchema = external_exports.discriminatedUnion("event", [
56354
+ menubarAgentClickSchema.extend({ event: external_exports.literal(MENUBAR_AGENT_CLICK) }),
56355
+ mcpWarningDismissalSchema.extend({ event: external_exports.literal(MENUBAR_MCP_WARNING_REMOVE) })
56356
+ ]);
56357
+
56267
56358
  // ../core/src/messageOrigin.ts
56268
56359
  var CLAUDE_CODE_NATIVE_ORIGINS = /* @__PURE__ */ new Set(["human", "agent", "harness", "tool"]);
56269
56360
  var CLAUDE_CODE_TASK_NOTIFICATION_ORIGIN = "task-notification";
@@ -56273,7 +56364,7 @@ function claudeCodeMessageOrigin(facts, text) {
56273
56364
  if (facts.nativeOrigin !== null && CLAUDE_CODE_NATIVE_ORIGINS.has(facts.nativeOrigin)) {
56274
56365
  origin = facts.nativeOrigin;
56275
56366
  }
56276
- if (facts.nativeOrigin === CLAUDE_CODE_TASK_NOTIFICATION_ORIGIN || facts.isMeta === true || facts.isCompactSummary === true || facts.model === "<synthetic>") {
56367
+ if (facts.nativeOrigin === CLAUDE_CODE_TASK_NOTIFICATION_ORIGIN || facts.commandMode === CLAUDE_CODE_TASK_NOTIFICATION_ORIGIN || facts.isMeta === true || facts.isCompactSummary === true || facts.model === "<synthetic>") {
56277
56368
  origin = "harness";
56278
56369
  }
56279
56370
  return origin === "human" && SYSTEM_REMINDER.test(text) ? "mixed" : origin;
@@ -56725,16 +56816,16 @@ function githubRepositoryOfRemote(url2) {
56725
56816
  const afterUser = url2.replace(REMOTE_SCHEME, "").replace(REMOTE_USER, "");
56726
56817
  const host = afterUser.startsWith("ssh.") ? afterUser.slice("ssh.".length) : afterUser;
56727
56818
  if (!host.startsWith("github.com")) return null;
56728
- let path32 = host.slice("github.com".length);
56729
- const port = hasScheme ? REMOTE_PORT.exec(path32) : null;
56730
- if (port !== null) path32 = path32.slice(port[0].length);
56731
- else if (path32.startsWith("/") || path32.startsWith(":")) path32 = path32.slice(1);
56819
+ let path34 = host.slice("github.com".length);
56820
+ const port = hasScheme ? REMOTE_PORT.exec(path34) : null;
56821
+ if (port !== null) path34 = path34.slice(port[0].length);
56822
+ else if (path34.startsWith("/") || path34.startsWith(":")) path34 = path34.slice(1);
56732
56823
  else return null;
56733
- if (path32.endsWith("/")) path32 = path32.slice(0, -1);
56734
- if (path32.endsWith(".git")) path32 = path32.slice(0, -".git".length);
56735
- const segments = path32.split("/");
56824
+ if (path34.endsWith("/")) path34 = path34.slice(0, -1);
56825
+ if (path34.endsWith(".git")) path34 = path34.slice(0, -".git".length);
56826
+ const segments = path34.split("/");
56736
56827
  if (segments.length !== 2 || !segments.every((segment) => REMOTE_PATH_SEGMENT.test(segment))) return null;
56737
- return path32;
56828
+ return path34;
56738
56829
  }
56739
56830
  var PUSH_DESTINATION = /\bTo\s+([^\s\\"]+)/g;
56740
56831
  function pushDestinationsInText(text) {
@@ -57394,7 +57485,8 @@ function originFacts(record2) {
57394
57485
  nativeOrigin: typeof origin?.kind === "string" ? origin.kind : null,
57395
57486
  isMeta: typeof record2.isMeta === "boolean" ? record2.isMeta : null,
57396
57487
  isCompactSummary: typeof record2.isCompactSummary === "boolean" ? record2.isCompactSummary : null,
57397
- model: typeof message2?.model === "string" ? message2.model : null
57488
+ model: typeof message2?.model === "string" ? message2.model : null,
57489
+ commandMode: null
57398
57490
  };
57399
57491
  }
57400
57492
  function recordTime(record2) {
@@ -57669,10 +57761,10 @@ function boundUnfamiliarPayload(record2) {
57669
57761
  }
57670
57762
  function excludeImageCarriers(record2) {
57671
57763
  const excludedKeys = [];
57672
- const withoutImages = (value, path32) => {
57764
+ const withoutImages = (value, path34) => {
57673
57765
  if (Array.isArray(value)) {
57674
57766
  return value.map((item, index) => {
57675
- const itemPath = `${path32}[${index}]`;
57767
+ const itemPath = `${path34}[${index}]`;
57676
57768
  if (typeof item === "string" && isImageCarrier(item)) {
57677
57769
  excludedKeys.push(itemPath);
57678
57770
  return null;
@@ -57683,7 +57775,7 @@ function excludeImageCarriers(record2) {
57683
57775
  if (!isRecord2(value)) return value;
57684
57776
  const kept = [];
57685
57777
  for (const [key, item] of Object.entries(value)) {
57686
- const keyPath = path32 === "" ? key : `${path32}.${key}`;
57778
+ const keyPath = path34 === "" ? key : `${path34}.${key}`;
57687
57779
  if (isImageBase64Payload(value, key) || typeof item === "string" && isImageCarrier(item)) {
57688
57780
  excludedKeys.push(keyPath);
57689
57781
  continue;
@@ -58404,8 +58496,8 @@ function primaryArg(args) {
58404
58496
  function readFilePath(name, primary) {
58405
58497
  if (!primary || !READ_TOOLS.has(name)) return null;
58406
58498
  if (ARTIFACT_PATH_RE.test(primary)) return null;
58407
- const path32 = primary.startsWith("/workspace/") ? primary.slice("/workspace/".length) : primary;
58408
- return path32.length > 0 ? path32 : null;
58499
+ const path34 = primary.startsWith("/workspace/") ? primary.slice("/workspace/".length) : primary;
58500
+ return path34.length > 0 ? path34 : null;
58409
58501
  }
58410
58502
  function asRecord3(value) {
58411
58503
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -58738,33 +58830,6 @@ function describeSyncSignals(member, now, noUpload = "no sessions uploaded yet")
58738
58830
  return `${line.charAt(0).toUpperCase()}${line.slice(1)}.`;
58739
58831
  }
58740
58832
 
58741
- // ../core/src/sessionIngest.ts
58742
- var SESSION_SOURCES = [
58743
- "claude-code",
58744
- "claude-cloud",
58745
- "codex",
58746
- "cursor",
58747
- "cursor-cloud",
58748
- "github-pr"
58749
- ];
58750
- var SESSION_SPEED_MODES = ["standard", "fast"];
58751
- var SESSION_SPEED_OBSERVATIONS = [...SESSION_SPEED_MODES, "unknown"];
58752
- function isSessionSource(source) {
58753
- return typeof source === "string" && SESSION_SOURCES.includes(source);
58754
- }
58755
- var SESSION_ACTIVE_WINDOW_MS = 30 * 60 * 1e3;
58756
- var COLLECTOR_SESSION_SOURCES = ["claude-code", "codex", "cursor"];
58757
- var PREVIEW_REGISTRABLE_SOURCES = [
58758
- ...COLLECTOR_SESSION_SOURCES,
58759
- "cursor-cloud"
58760
- ];
58761
- var MAX_INGEST_BATCH = 500;
58762
- var MAX_RAW_UPLOAD_BYTES = 256 * 1024 * 1024;
58763
- var MAX_PREVIEW_URL_LENGTH = 2e3;
58764
- var MAX_REGISTERED_PREVIEWS = 10;
58765
- var MAX_PREVIEW_LABEL_LENGTH = 60;
58766
- var MAX_BRANCH_FACTS = 50;
58767
-
58768
58833
  // ../core/src/version.ts
58769
58834
  function parseReleaseVersion(version2) {
58770
58835
  const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version2);
@@ -58837,6 +58902,19 @@ var recentSessionCursorSchema = external_exports.object({
58837
58902
  id: external_exports.uuid()
58838
58903
  });
58839
58904
 
58905
+ // ../core/src/codexClient.ts
58906
+ var codexClientSchema = external_exports.enum(["desktop", "tui", "unknown"]);
58907
+ var metadataSchema = external_exports.object({ originator: external_exports.unknown().optional(), source: external_exports.unknown().optional() });
58908
+ function classifyCodexClient(metadata) {
58909
+ const parsed = metadataSchema.safeParse(metadata);
58910
+ if (!parsed.success) return "unknown";
58911
+ const { originator, source } = parsed.data;
58912
+ if (source === "exec" || typeof source === "object" && source !== null) return "unknown";
58913
+ if (originator === "Codex Desktop") return "desktop";
58914
+ if (source === "cli") return "tui";
58915
+ return "unknown";
58916
+ }
58917
+
58840
58918
  // ../../node_modules/.pnpm/@sentry+core@10.74.0/node_modules/@sentry/core/build/esm/debug-build.js
58841
58919
  var DEBUG_BUILD = typeof __SENTRY_DEBUG__ === "undefined" || __SENTRY_DEBUG__;
58842
58920
 
@@ -59017,8 +59095,8 @@ function getFunctionName(fn) {
59017
59095
  return defaultFunctionName;
59018
59096
  }
59019
59097
  }
59020
- function normalizeStackTracePath(path32) {
59021
- let filename = path32?.startsWith("file://") ? path32.slice(7) : path32;
59098
+ function normalizeStackTracePath(path34) {
59099
+ let filename = path34?.startsWith("file://") ? path34.slice(7) : path34;
59022
59100
  if (filename?.match(/\/[A-Z]:/)) {
59023
59101
  filename = filename.slice(1);
59024
59102
  }
@@ -60828,8 +60906,8 @@ function isValidProtocol(protocol) {
60828
60906
  return protocol === "http" || protocol === "https";
60829
60907
  }
60830
60908
  function dsnToString(dsn, withPassword = false) {
60831
- const { host, path: path32, pass, port, projectId, protocol, publicKey } = dsn;
60832
- return `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ""}@${host}${port ? `:${port}` : ""}/${path32 ? `${path32}/` : path32}${projectId}`;
60909
+ const { host, path: path34, pass, port, projectId, protocol, publicKey } = dsn;
60910
+ return `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ""}@${host}${port ? `:${port}` : ""}/${path34 ? `${path34}/` : path34}${projectId}`;
60833
60911
  }
60834
60912
  function dsnFromString(str) {
60835
60913
  const match = DSN_REGEX.exec(str);
@@ -60840,11 +60918,11 @@ function dsnFromString(str) {
60840
60918
  return void 0;
60841
60919
  }
60842
60920
  const [protocol, publicKey, pass = "", host = "", port = "", lastPath = ""] = match.slice(1);
60843
- let path32 = "";
60921
+ let path34 = "";
60844
60922
  let projectId = lastPath;
60845
60923
  const split = projectId.split("/");
60846
60924
  if (split.length > 1) {
60847
- path32 = split.slice(0, -1).join("/");
60925
+ path34 = split.slice(0, -1).join("/");
60848
60926
  projectId = split.pop();
60849
60927
  }
60850
60928
  if (projectId) {
@@ -60853,7 +60931,7 @@ function dsnFromString(str) {
60853
60931
  projectId = projectMatch[0];
60854
60932
  }
60855
60933
  }
60856
- return dsnFromComponents({ host, pass, path: path32, projectId, port, protocol, publicKey });
60934
+ return dsnFromComponents({ host, pass, path: path34, projectId, port, protocol, publicKey });
60857
60935
  }
60858
60936
  function dsnFromComponents(components) {
60859
60937
  return {
@@ -65382,9 +65460,9 @@ function stripUrlQueryAndFragment(urlPath) {
65382
65460
  return urlPath.split(/[?#]/, 1)[0];
65383
65461
  }
65384
65462
  function getSanitizedUrlString(url2) {
65385
- const { protocol, host, path: path32 } = url2;
65463
+ const { protocol, host, path: path34 } = url2;
65386
65464
  const filteredHost = host?.replace(/^.*@/, "[filtered]:[filtered]@").replace(/(:80)$/, "").replace(/(:443)$/, "") || "";
65387
- return `${protocol ? `${protocol}://` : ""}${filteredHost}${path32}`;
65465
+ return `${protocol ? `${protocol}://` : ""}${filteredHost}${path34}`;
65388
65466
  }
65389
65467
  function stripDataUrlContent(url2, includeDataPrefix = true) {
65390
65468
  if (url2.startsWith("data:")) {
@@ -66329,8 +66407,8 @@ function splitPath(filename) {
66329
66407
  const parts = splitPathRe.exec(truncated);
66330
66408
  return parts ? parts.slice(1) : [];
66331
66409
  }
66332
- function dirname(path32) {
66333
- const result = splitPath(path32);
66410
+ function dirname(path34) {
66411
+ const result = splitPath(path34);
66334
66412
  const root = result[0] || "";
66335
66413
  let dir = result[1];
66336
66414
  if (!root && !dir) {
@@ -70173,15 +70251,15 @@ var getLayerMetadata = (route, layer, layerPath) => {
70173
70251
  };
70174
70252
  }
70175
70253
  };
70176
- var getRouterPath = (path32, layer) => {
70254
+ var getRouterPath = (path34, layer) => {
70177
70255
  const stackLayer = Array.isArray(layer.handle?.stack) ? layer.handle?.stack?.[0] : void 0;
70178
70256
  if (stackLayer?.route?.path) {
70179
- return `${path32}${stackLayer.route.path}`;
70257
+ return `${path34}${stackLayer.route.path}`;
70180
70258
  }
70181
70259
  if (stackLayer && Array.isArray(stackLayer?.handle?.stack)) {
70182
- return getRouterPath(path32, stackLayer);
70260
+ return getRouterPath(path34, stackLayer);
70183
70261
  }
70184
- return path32;
70262
+ return path34;
70185
70263
  };
70186
70264
  var isLayerIgnored = (name, type, config2) => {
70187
70265
  if (Array.isArray(config2?.ignoreLayersType) && config2?.ignoreLayersType?.includes(type)) {
@@ -70201,7 +70279,7 @@ function getActualMatchedRoute(req, constructedRoute) {
70201
70279
  if (layersStore.length === 0) {
70202
70280
  return void 0;
70203
70281
  }
70204
- if (layersStore.every((path32) => path32 === "/")) {
70282
+ if (layersStore.every((path34) => path34 === "/")) {
70205
70283
  return req.originalUrl === "/" ? "/" : void 0;
70206
70284
  }
70207
70285
  if (constructedRoute === "*") {
@@ -70217,11 +70295,11 @@ function getActualMatchedRoute(req, constructedRoute) {
70217
70295
  function getConstructedRoute(req) {
70218
70296
  const layersStore = getStoredLayers(req);
70219
70297
  let constructedRoute = "";
70220
- for (const path32 of layersStore) {
70221
- if (path32 === "/" || path32 === "/*") {
70298
+ for (const path34 of layersStore) {
70299
+ if (path34 === "/" || path34 === "/*") {
70222
70300
  continue;
70223
70301
  }
70224
- constructedRoute += !constructedRoute || constructedRoute.endsWith("/") ? path32 : `/${path32}`;
70302
+ constructedRoute += !constructedRoute || constructedRoute.endsWith("/") ? path34 : `/${path34}`;
70225
70303
  }
70226
70304
  return constructedRoute.replace(/\/{2,}/g, "/");
70227
70305
  }
@@ -70726,9 +70804,9 @@ function getRequestUrlObject(requestOptions) {
70726
70804
  const hostHeader = requestOptions.headers?.host && String(requestOptions.headers?.host);
70727
70805
  const hostname4 = hostHeader || requestOptions.hostname || requestOptions.host || "";
70728
70806
  const port = !requestOptions.port || requestOptions.port === 80 || requestOptions.port === 443 || /^(.*):(\d+)$/.test(hostname4) ? "" : `:${requestOptions.port}`;
70729
- const path32 = requestOptions.path ? requestOptions.path : "/";
70807
+ const path34 = requestOptions.path ? requestOptions.path : "/";
70730
70808
  const base = `${protocol}//${hostname4}${port}`;
70731
- return new URL(path32.startsWith("//") ? `${base}${path32}` : path32, base);
70809
+ return new URL(path34.startsWith("//") ? `${base}${path34}` : path34, base);
70732
70810
  }
70733
70811
  function getRequestUrlFromClientRequest(request2) {
70734
70812
  return String(getRequestUrl(getRequestOptions(request2)));
@@ -71401,11 +71479,11 @@ function shouldIgnoreSpansForIncomingRequest(request2, {
71401
71479
  return false;
71402
71480
  }
71403
71481
  function isStaticAssetRequest(urlPath) {
71404
- const path32 = stripUrlQueryAndFragment(urlPath);
71405
- if (path32.match(/\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {
71482
+ const path34 = stripUrlQueryAndFragment(urlPath);
71483
+ if (path34.match(/\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {
71406
71484
  return true;
71407
71485
  }
71408
- if (path32.match(/^\/(robots\.txt|sitemap\.xml|manifest\.json|browserconfig\.xml)$/)) {
71486
+ if (path34.match(/^\/(robots\.txt|sitemap\.xml|manifest\.json|browserconfig\.xml)$/)) {
71409
71487
  return true;
71410
71488
  }
71411
71489
  return false;
@@ -71646,11 +71724,11 @@ function isKnownPrefetchRequest2(req) {
71646
71724
  return req.headers["next-router-prefetch"] === "1";
71647
71725
  }
71648
71726
  function isStaticAssetRequest2(urlPath) {
71649
- const path32 = stripUrlQueryAndFragment(urlPath);
71650
- if (path32.match(/\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {
71727
+ const path34 = stripUrlQueryAndFragment(urlPath);
71728
+ if (path34.match(/\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {
71651
71729
  return true;
71652
71730
  }
71653
- if (path32.match(/^\/(robots\.txt|sitemap\.xml|manifest\.json|browserconfig\.xml)$/)) {
71731
+ if (path34.match(/^\/(robots\.txt|sitemap\.xml|manifest\.json|browserconfig\.xml)$/)) {
71654
71732
  return true;
71655
71733
  }
71656
71734
  return false;
@@ -72010,19 +72088,19 @@ function getBreadcrumbData(request2) {
72010
72088
  return {};
72011
72089
  }
72012
72090
  }
72013
- function getAbsoluteUrl2(origin, path32 = "/") {
72091
+ function getAbsoluteUrl2(origin, path34 = "/") {
72014
72092
  try {
72015
- const url2 = new URL(path32, origin);
72093
+ const url2 = new URL(path34, origin);
72016
72094
  return url2.toString();
72017
72095
  } catch {
72018
72096
  const url2 = `${origin}`;
72019
- if (url2.endsWith("/") && path32.startsWith("/")) {
72020
- return `${url2}${path32.slice(1)}`;
72097
+ if (url2.endsWith("/") && path34.startsWith("/")) {
72098
+ return `${url2}${path34.slice(1)}`;
72021
72099
  }
72022
- if (!url2.endsWith("/") && !path32.startsWith("/")) {
72023
- return `${url2}/${path32}`;
72100
+ if (!url2.endsWith("/") && !path34.startsWith("/")) {
72101
+ return `${url2}/${path34}`;
72024
72102
  }
72025
- return `${url2}${path32}`;
72103
+ return `${url2}${path34}`;
72026
72104
  }
72027
72105
  }
72028
72106
 
@@ -72267,15 +72345,15 @@ function getRequestMethod(original) {
72267
72345
  }
72268
72346
  return "_OTHER";
72269
72347
  }
72270
- function getAbsoluteUrl3(origin, path32 = "/") {
72348
+ function getAbsoluteUrl3(origin, path34 = "/") {
72271
72349
  const url2 = `${origin}`;
72272
- if (url2.endsWith("/") && path32.startsWith("/")) {
72273
- return `${url2}${path32.slice(1)}`;
72350
+ if (url2.endsWith("/") && path34.startsWith("/")) {
72351
+ return `${url2}${path34.slice(1)}`;
72274
72352
  }
72275
- if (!url2.endsWith("/") && !path32.startsWith("/")) {
72276
- return `${url2}/${path32}`;
72353
+ if (!url2.endsWith("/") && !path34.startsWith("/")) {
72354
+ return `${url2}/${path34}`;
72277
72355
  }
72278
- return `${url2}${path32}`;
72356
+ return `${url2}${path34}`;
72279
72357
  }
72280
72358
 
72281
72359
  // ../../node_modules/.pnpm/@sentry+node-core@10.74.0_@opentelemetry+api@1.9.1_@opentelemetry+core@2.11.0_@opentele_b542b1cf9336850aabd631474d797bed/node_modules/@sentry/node-core/build/esm/integrations/node-fetch/index.js
@@ -74768,12 +74846,12 @@ function emplace(map2, key, contents) {
74768
74846
  }
74769
74847
  return value;
74770
74848
  }
74771
- function shouldSkipContextLinesForFile(path32) {
74772
- if (path32.startsWith("node:")) return true;
74773
- if (path32.endsWith(".min.js")) return true;
74774
- if (path32.endsWith(".min.cjs")) return true;
74775
- if (path32.endsWith(".min.mjs")) return true;
74776
- if (path32.startsWith("data:")) return true;
74849
+ function shouldSkipContextLinesForFile(path34) {
74850
+ if (path34.startsWith("node:")) return true;
74851
+ if (path34.endsWith(".min.js")) return true;
74852
+ if (path34.endsWith(".min.cjs")) return true;
74853
+ if (path34.endsWith(".min.mjs")) return true;
74854
+ if (path34.startsWith("data:")) return true;
74777
74855
  return false;
74778
74856
  }
74779
74857
  function shouldSkipContextLinesForFrame(frame) {
@@ -74821,9 +74899,9 @@ function makeLineReaderRanges(lines, linecontext) {
74821
74899
  }
74822
74900
  return out;
74823
74901
  }
74824
- function getContextLinesFromFile(path32, ranges, output2) {
74902
+ function getContextLinesFromFile(path34, ranges, output2) {
74825
74903
  return new Promise((resolve2, _reject) => {
74826
- const stream = createReadStream(path32);
74904
+ const stream = createReadStream(path34);
74827
74905
  const lineReaded = createInterface({
74828
74906
  input: stream
74829
74907
  });
@@ -74841,8 +74919,8 @@ function getContextLinesFromFile(path32, ranges, output2) {
74841
74919
  let rangeStart = range[0];
74842
74920
  let rangeEnd = range[1];
74843
74921
  function onStreamError(e) {
74844
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path32, 1);
74845
- DEBUG_BUILD2 && debug.error(`Failed to read file: ${path32}. Error: ${e}`);
74922
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path34, 1);
74923
+ DEBUG_BUILD2 && debug.error(`Failed to read file: ${path34}. Error: ${e}`);
74846
74924
  lineReaded.close();
74847
74925
  lineReaded.removeAllListeners();
74848
74926
  destroyStreamAndResolve();
@@ -76281,8 +76359,8 @@ function getSpotlightConfig(optionsSpotlight) {
76281
76359
 
76282
76360
  // ../../node_modules/.pnpm/@sentry+node-core@10.74.0_@opentelemetry+api@1.9.1_@opentelemetry+core@2.11.0_@opentele_b542b1cf9336850aabd631474d797bed/node_modules/@sentry/node-core/build/esm/utils/module.js
76283
76361
  import { posix, sep } from "node:path";
76284
- function normalizeWindowsPath(path32) {
76285
- return path32.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
76362
+ function normalizeWindowsPath(path34) {
76363
+ return path34.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
76286
76364
  }
76287
76365
  function createGetModuleFromFilename(basePath = process.argv[1] ? dirname(process.argv[1]) : process.cwd(), isWindows = sep === "\\") {
76288
76366
  const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
@@ -79167,22 +79245,22 @@ function addSpanSource(span, loc, start, end) {
79167
79245
  span.setAttribute(AttributeNames2.SOURCE, source);
79168
79246
  }
79169
79247
  }
79170
- function createFieldIfNotExists(contextValue, info, path32) {
79171
- let field = getField(contextValue, path32);
79248
+ function createFieldIfNotExists(contextValue, info, path34) {
79249
+ let field = getField(contextValue, path34);
79172
79250
  if (field) {
79173
79251
  return { field, spanAdded: false };
79174
79252
  }
79175
- const parentSpan = getParentFieldSpan(contextValue, path32);
79253
+ const parentSpan = getParentFieldSpan(contextValue, path34);
79176
79254
  field = {
79177
- span: createResolverSpan(contextValue, info, path32, parentSpan)
79255
+ span: createResolverSpan(contextValue, info, path34, parentSpan)
79178
79256
  };
79179
- addField(contextValue, path32, field);
79257
+ addField(contextValue, path34, field);
79180
79258
  return { field, spanAdded: true };
79181
79259
  }
79182
- function createResolverSpan(contextValue, info, path32, parentSpan) {
79260
+ function createResolverSpan(contextValue, info, path34, parentSpan) {
79183
79261
  const attributes = {
79184
79262
  [AttributeNames2.FIELD_NAME]: info.fieldName,
79185
- [AttributeNames2.FIELD_PATH]: path32.join("."),
79263
+ [AttributeNames2.FIELD_PATH]: path34.join("."),
79186
79264
  [AttributeNames2.FIELD_TYPE]: info.returnType.toString(),
79187
79265
  [AttributeNames2.PARENT_NAME]: info.parentType.name
79188
79266
  };
@@ -79214,15 +79292,15 @@ function getOperation(document2, operationName) {
79214
79292
  return document2.definitions.find((definition) => OPERATION_VALUES.indexOf(definition?.operation) !== -1);
79215
79293
  }
79216
79294
  }
79217
- function addField(contextValue, path32, field) {
79218
- return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[path32.join(".")] = field;
79295
+ function addField(contextValue, path34, field) {
79296
+ return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[path34.join(".")] = field;
79219
79297
  }
79220
- function getField(contextValue, path32) {
79221
- return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[path32.join(".")];
79298
+ function getField(contextValue, path34) {
79299
+ return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[path34.join(".")];
79222
79300
  }
79223
- function getParentFieldSpan(contextValue, path32) {
79224
- for (let i = path32.length - 1; i > 0; i--) {
79225
- const field = getField(contextValue, path32.slice(0, i));
79301
+ function getParentFieldSpan(contextValue, path34) {
79302
+ for (let i = path34.length - 1; i > 0; i--) {
79303
+ const field = getField(contextValue, path34.slice(0, i));
79226
79304
  if (field) {
79227
79305
  return field.span;
79228
79306
  }
@@ -79232,9 +79310,9 @@ function getParentFieldSpan(contextValue, path32) {
79232
79310
  function getRootSpan2(contextValue) {
79233
79311
  return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].span;
79234
79312
  }
79235
- function pathToArray(path32) {
79313
+ function pathToArray(path34) {
79236
79314
  const flattened = [];
79237
- let curr = path32;
79315
+ let curr = path34;
79238
79316
  while (curr) {
79239
79317
  flattened.push(String(curr.key));
79240
79318
  curr = curr.prev;
@@ -79375,8 +79453,8 @@ function wrapFieldResolver(getConfig3, fieldResolver, isDefaultResolver = false)
79375
79453
  if (!contextValue[OTEL_GRAPHQL_DATA_SYMBOL]) {
79376
79454
  return fieldResolver.call(this, source, args, contextValue, info);
79377
79455
  }
79378
- const path32 = pathToArray(info?.path);
79379
- const { field, spanAdded } = createFieldIfNotExists(contextValue, info, path32);
79456
+ const path34 = pathToArray(info?.path);
79457
+ const { field, spanAdded } = createFieldIfNotExists(contextValue, info, path34);
79380
79458
  const span = field.span;
79381
79459
  const shouldEndSpan = spanAdded;
79382
79460
  return withActiveSpan(span, () => {
@@ -82359,10 +82437,10 @@ var PostgresJsInstrumentation = class extends import_instrumentation24.Instrumen
82359
82437
  },
82360
82438
  (exports) => exports
82361
82439
  );
82362
- ["src", "cf/src", "cjs/src"].forEach((path32) => {
82440
+ ["src", "cf/src", "cjs/src"].forEach((path34) => {
82363
82441
  module2.files.push(
82364
82442
  new InstrumentationNodeModuleFile(
82365
- `postgres/${path32}/query.js`,
82443
+ `postgres/${path34}/query.js`,
82366
82444
  SUPPORTED_VERSIONS4,
82367
82445
  this._patchQueryPrototype.bind(this),
82368
82446
  this._unpatchQueryPrototype.bind(this)
@@ -82993,13 +83071,13 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
82993
83071
  return function(original) {
82994
83072
  return function wrappedHandler(...args) {
82995
83073
  if (typeof args[0] === "string") {
82996
- const path32 = args[0];
83074
+ const path34 = args[0];
82997
83075
  if (args.length === 1) {
82998
- return original.apply(this, [path32]);
83076
+ return original.apply(this, [path34]);
82999
83077
  }
83000
83078
  const handlers2 = args.slice(1);
83001
83079
  return original.apply(this, [
83002
- path32,
83080
+ path34,
83003
83081
  ...handlers2.map((handler) => instrumentation._wrapHandler(handler))
83004
83082
  ]);
83005
83083
  }
@@ -83033,13 +83111,13 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
83033
83111
  return function(original) {
83034
83112
  return function wrappedHandler(...args) {
83035
83113
  if (typeof args[0] === "string") {
83036
- const path32 = args[0];
83114
+ const path34 = args[0];
83037
83115
  if (args.length === 1) {
83038
- return original.apply(this, [path32]);
83116
+ return original.apply(this, [path34]);
83039
83117
  }
83040
83118
  const handlers2 = args.slice(1);
83041
83119
  return original.apply(this, [
83042
- path32,
83120
+ path34,
83043
83121
  ...handlers2.map((handler) => instrumentation._wrapHandler(handler))
83044
83122
  ]);
83045
83123
  }
@@ -83059,8 +83137,8 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
83059
83137
  if (!instrumentation.isEnabled()) {
83060
83138
  return handler.apply(this, [c, next]);
83061
83139
  }
83062
- const path32 = c.req.path;
83063
- const span = instrumentation.tracer.startSpan(path32);
83140
+ const path34 = c.req.path;
83141
+ const span = instrumentation.tracer.startSpan(path34);
83064
83142
  return context.with(trace.setSpan(context.active(), span), () => {
83065
83143
  return instrumentation._safeExecute(
83066
83144
  () => {
@@ -83070,7 +83148,7 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
83070
83148
  const type = instrumentation._determineHandlerType(result2);
83071
83149
  span.setAttributes({
83072
83150
  [AttributeNames5.HONO_TYPE]: type,
83073
- [AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ? path32 : handler.name || "anonymous"
83151
+ [AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ? path34 : handler.name || "anonymous"
83074
83152
  });
83075
83153
  instrumentation.getConfig().responseHook?.(span);
83076
83154
  return result2;
@@ -83079,7 +83157,7 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
83079
83157
  const type = instrumentation._determineHandlerType(result);
83080
83158
  span.setAttributes({
83081
83159
  [AttributeNames5.HONO_TYPE]: type,
83082
- [AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ? path32 : handler.name || "anonymous"
83160
+ [AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ? path34 : handler.name || "anonymous"
83083
83161
  });
83084
83162
  instrumentation.getConfig().responseHook?.(span);
83085
83163
  return result;
@@ -83283,11 +83361,11 @@ var KoaInstrumentation = class extends import_instrumentation29.InstrumentationB
83283
83361
  const router = dispatchLayer.router;
83284
83362
  const routesStack = router?.stack ?? [];
83285
83363
  for (const pathLayer of routesStack) {
83286
- const path32 = pathLayer.path;
83364
+ const path34 = pathLayer.path;
83287
83365
  const pathStack = pathLayer.stack;
83288
83366
  for (let j = 0; j < pathStack.length; j++) {
83289
83367
  const routedMiddleware = pathStack[j];
83290
- pathStack[j] = this._patchLayer(routedMiddleware, true, path32);
83368
+ pathStack[j] = this._patchLayer(routedMiddleware, true, path34);
83291
83369
  }
83292
83370
  }
83293
83371
  return dispatchLayer;
@@ -85534,7 +85612,7 @@ function _init2(options = {}, getDefaultIntegrationsImpl) {
85534
85612
  return client;
85535
85613
  }
85536
85614
 
85537
- // ../../apps/collector/src/reporting.ts
85615
+ // ../../apps/syncservice/src/reporting.ts
85538
85616
  function initCollectorReporting(appEnv, release2) {
85539
85617
  const dsn = process.env.SENTRY_DSN;
85540
85618
  if (!dsn) return;
@@ -85604,7 +85682,7 @@ async function flushReporting() {
85604
85682
  await flush(2e3).catch(() => void 0);
85605
85683
  }
85606
85684
 
85607
- // ../../apps/collector/src/macosCredentialStore.ts
85685
+ // ../../apps/syncservice/src/macosCredentialStore.ts
85608
85686
  import { execFileSync as execFileSync3 } from "node:child_process";
85609
85687
  import { createCipheriv, createDecipheriv, randomBytes, randomUUID as randomUUID2 } from "node:crypto";
85610
85688
  import {
@@ -85619,7 +85697,7 @@ import {
85619
85697
  import os11 from "node:os";
85620
85698
  import path13 from "node:path";
85621
85699
 
85622
- // ../../apps/collector/src/readIfExists.ts
85700
+ // ../../apps/syncservice/src/readIfExists.ts
85623
85701
  import { readFileSync as readFileSync2 } from "node:fs";
85624
85702
  function readIfExists(file2) {
85625
85703
  try {
@@ -85630,7 +85708,7 @@ function readIfExists(file2) {
85630
85708
  }
85631
85709
  }
85632
85710
 
85633
- // ../../apps/collector/src/childExitCodes.ts
85711
+ // ../../apps/syncservice/src/childExitCodes.ts
85634
85712
  var SECURITY_EXITS = {
85635
85713
  36: "user interaction is not allowed, Keychain needs a desktop session",
85636
85714
  44: "item not found",
@@ -85657,7 +85735,7 @@ function describeLaunchctlExit(status) {
85657
85735
  return `launchctl exited ${status}${meaning ? ` (${meaning})` : ""}`;
85658
85736
  }
85659
85737
 
85660
- // ../../apps/collector/src/service.ts
85738
+ // ../../apps/syncservice/src/service.ts
85661
85739
  import { execFileSync } from "node:child_process";
85662
85740
  import { chmodSync, existsSync, mkdirSync, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync } from "node:fs";
85663
85741
  import os3 from "node:os";
@@ -85874,16 +85952,38 @@ function xmlEscape(value) {
85874
85952
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
85875
85953
  }
85876
85954
 
85877
- // ../../apps/collector/src/status.ts
85955
+ // ../../apps/syncservice/src/status.ts
85878
85956
  import { mkdirSync as mkdirSync7, readFileSync as readFileSync7, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
85879
85957
  import os10 from "node:os";
85880
85958
  import path12 from "node:path";
85881
85959
 
85882
- // ../../apps/collector/src/hookHealth.ts
85960
+ // ../../apps/syncservice/src/hookHealth.ts
85883
85961
  import { existsSync as existsSync6, lstatSync as lstatSync4 } from "node:fs";
85884
85962
  import path11 from "node:path";
85885
85963
 
85886
- // ../../apps/collector/src/codexTranscriptDiscovery.ts
85964
+ // ../../apps/syncservice/src/codexHookGuidance.ts
85965
+ var CODEX_ACTIVITY_WINDOW_MS = 7 * 24 * 60 * 6e4;
85966
+ function codexHookInstructions(client) {
85967
+ switch (client) {
85968
+ case "desktop":
85969
+ return "Open Settings \u2192 Hooks in Codex to trust Powerplant. This makes sync more efficient.";
85970
+ case "tui":
85971
+ return "Run /hooks in Codex to trust Powerplant. This makes sync more efficient.";
85972
+ case "unknown":
85973
+ return "Open Settings \u2192 Hooks in the Codex app, or run /hooks in the Codex TUI, to trust Powerplant.";
85974
+ }
85975
+ }
85976
+ function hookWarning(health, nowMs) {
85977
+ const silence = health.silence;
85978
+ if (health.harness !== "codex" || silence?.kind !== "not-firing") return silence;
85979
+ const activity = health.codexActivity;
85980
+ if (activity === void 0) return void 0;
85981
+ const age = nowMs - Date.parse(activity.at);
85982
+ if (!Number.isFinite(age) || age < 0 || age > CODEX_ACTIVITY_WINDOW_MS) return void 0;
85983
+ return { ...silence, fix: codexHookInstructions(activity.client) };
85984
+ }
85985
+
85986
+ // ../../apps/syncservice/src/codexTranscriptDiscovery.ts
85887
85987
  import { createHash } from "node:crypto";
85888
85988
  import { closeSync, lstatSync, openSync, readSync, readdirSync, realpathSync } from "node:fs";
85889
85989
  import path2 from "node:path";
@@ -85944,13 +86044,13 @@ function readCodexTranscriptDiscoveryRecords(home, roots) {
85944
86044
  return result;
85945
86045
  }
85946
86046
 
85947
- // ../../apps/collector/src/diagnostics.ts
86047
+ // ../../apps/syncservice/src/diagnostics.ts
85948
86048
  import { createHmac } from "node:crypto";
85949
86049
 
85950
- // ../../apps/collector/src/http.ts
86050
+ // ../../apps/syncservice/src/http.ts
85951
86051
  var import_undici = __toESM(require_undici(), 1);
85952
86052
  var CLI_VERSION_HEADER = "x-powerplant-cli-version";
85953
- var cliVersion = true ? "0.4.13" : "0.0.0-checkout";
86053
+ var cliVersion = true ? "0.4.15" : "0.0.0-checkout";
85954
86054
  function cliVersionHeaders() {
85955
86055
  return { [CLI_VERSION_HEADER]: cliVersion, "user-agent": `powerplant-cli/${cliVersion}` };
85956
86056
  }
@@ -86022,7 +86122,7 @@ function isPoisonedHttp2Session(error63) {
86022
86122
  return false;
86023
86123
  }
86024
86124
 
86025
- // ../../apps/collector/src/diagnostics.ts
86125
+ // ../../apps/syncservice/src/diagnostics.ts
86026
86126
  function observeFileDiagnostic(observer, file2) {
86027
86127
  try {
86028
86128
  observer?.(file2);
@@ -86074,8 +86174,8 @@ function createStructureDiagnostics() {
86074
86174
  observe: (source) => (observation) => {
86075
86175
  try {
86076
86176
  const formatVersion = admitted("formatVersion", observation.formatVersion ?? null);
86077
- const path32 = observation.path.replace(/[^A-Za-z0-9_.$:/=[\]-]/g, "_").slice(0, 160) || "other";
86078
- const key = [source, path32, observation.reason, observation.valueType, formatVersion].join("\0");
86177
+ const path34 = observation.path.replace(/[^A-Za-z0-9_.$:/=[\]-]/g, "_").slice(0, 160) || "other";
86178
+ const key = [source, path34, observation.reason, observation.valueType, formatVersion].join("\0");
86079
86179
  const count3 = observation.count ?? 1;
86080
86180
  const existing = groups.get(key);
86081
86181
  if (existing) {
@@ -86085,7 +86185,7 @@ function createStructureDiagnostics() {
86085
86185
  if (samples.length >= MAX_STRUCTURE_DIAGNOSTICS) return;
86086
86186
  const sample = {
86087
86187
  source,
86088
- path: path32,
86188
+ path: path34,
86089
86189
  reason: observation.reason,
86090
86190
  valueType: observation.valueType,
86091
86191
  formatVersion,
@@ -86257,13 +86357,13 @@ function bindDiagnosticEnrollment(diagnostic, token) {
86257
86357
  passEnrollments.set(diagnostic, token);
86258
86358
  }
86259
86359
 
86260
- // ../../apps/collector/src/codexSessions.ts
86360
+ // ../../apps/syncservice/src/codexSessions.ts
86261
86361
  import { closeSync as closeSync3, mkdirSync as mkdirSync2, openSync as openSync3, renameSync, rmSync as rmSync2, utimesSync, writeSync } from "node:fs";
86262
86362
  import os6 from "node:os";
86263
86363
  import path5 from "node:path";
86264
86364
  import { setImmediate as yieldToEventLoop } from "node:timers/promises";
86265
86365
 
86266
- // ../../apps/collector/src/gitOwner.ts
86366
+ // ../../apps/syncservice/src/gitOwner.ts
86267
86367
  import { execFileSync as execFileSync2 } from "node:child_process";
86268
86368
  import { readFileSync as readFileSync4, statSync } from "node:fs";
86269
86369
  import os4 from "node:os";
@@ -86463,7 +86563,7 @@ function isPermissionError(cause) {
86463
86563
  return typeof cause === "object" && cause !== null && "code" in cause && (cause.code === "EPERM" || cause.code === "EACCES");
86464
86564
  }
86465
86565
 
86466
- // ../../apps/collector/src/scan.ts
86566
+ // ../../apps/syncservice/src/scan.ts
86467
86567
  import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync2, readSync as readSync2, statSync as statSync2 } from "node:fs";
86468
86568
  import { StringDecoder } from "node:string_decoder";
86469
86569
  var SESSION_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -86548,7 +86648,7 @@ function describeReadError(error63) {
86548
86648
  return error63 instanceof Error ? error63.message : String(error63);
86549
86649
  }
86550
86650
 
86551
- // ../../apps/collector/src/scope.ts
86651
+ // ../../apps/syncservice/src/scope.ts
86552
86652
  import os5 from "node:os";
86553
86653
  import path4 from "node:path";
86554
86654
  var captureEverythingUnresolved = {
@@ -86637,15 +86737,6 @@ function withWorkspaceRouting(policy, repoPart) {
86637
86737
  const severalWorkspaces = (policy.workspaceClaims?.length ?? 0) > 1;
86638
86738
  return severalWorkspaces && claiming.length > 0 ? `${repoPart}, routing each repo to the workspace that syncs it (${listSome(claiming.map((workspace) => workspace.name))})` : repoPart;
86639
86739
  }
86640
- function describeEnrollmentCapture(policy) {
86641
- if (policy.mode === "org-repos") {
86642
- const boundary = orgRepoBoundary(policy);
86643
- if (boundary.kind === "repo-list") {
86644
- return `Set allowlist from this org: ${withWorkspaceRouting(policy, listSome(boundary.repos))}`;
86645
- }
86646
- }
86647
- return `Syncing: ${describeCapturePolicy(policy)}`;
86648
- }
86649
86740
  function describeStoredCapture(credentials) {
86650
86741
  if (credentials.captureMode === "scope") {
86651
86742
  return describeCapturePolicy({
@@ -86697,12 +86788,14 @@ function isPathWithinScopes(resolved, scopePaths) {
86697
86788
  );
86698
86789
  }
86699
86790
 
86700
- // ../../apps/collector/src/codexSessions.ts
86791
+ // ../../apps/syncservice/src/codexSessions.ts
86701
86792
  function parseCodexRollout(text, sharedUsage) {
86702
86793
  let meta3 = null;
86703
86794
  let initialEvent;
86704
86795
  let records = 0;
86705
86796
  let model;
86797
+ let codexClient = "unknown";
86798
+ let noninteractive;
86706
86799
  const timestamps = [];
86707
86800
  const usage = sharedUsage ?? createCodexUsageReader();
86708
86801
  for (const line of parseJsonl(text)) {
@@ -86715,6 +86808,8 @@ function parseCodexRollout(text, sharedUsage) {
86715
86808
  const record2 = payload;
86716
86809
  if (line.type === "session_meta") {
86717
86810
  meta3 ??= record2;
86811
+ codexClient = classifyCodexClient(record2);
86812
+ noninteractive = record2.source === "exec" ? true : void 0;
86718
86813
  } else if (line.type === "turn_context" && typeof record2.model === "string") {
86719
86814
  model = record2.model;
86720
86815
  }
@@ -86725,6 +86820,8 @@ function parseCodexRollout(text, sharedUsage) {
86725
86820
  const sessionId = meta3?.id ?? meta3?.session_id;
86726
86821
  const facts = meta3 === null ? {} : harnessSessionFacts("codex", { ...meta3, initialEvent });
86727
86822
  return {
86823
+ codexClient,
86824
+ ...noninteractive && { noninteractive },
86728
86825
  kind: facts.subagent ? "subagent" : "session",
86729
86826
  ...facts.standaloneReview && { standaloneReview: true },
86730
86827
  ...typeof sessionId === "string" && sessionId !== "" && { sessionId },
@@ -86762,6 +86859,8 @@ function foldRolloutPages(pages, usage) {
86762
86859
  const repoFullName = first("repoFullName");
86763
86860
  return {
86764
86861
  kind: pages[0].kind,
86862
+ codexClient: pages.at(-1).codexClient,
86863
+ ...pages.at(-1).noninteractive && { noninteractive: true },
86765
86864
  ...pages[0].standaloneReview && { standaloneReview: true },
86766
86865
  ...sessionId !== void 0 && { sessionId },
86767
86866
  ...startedAt !== void 0 && { startedAt },
@@ -86828,11 +86927,12 @@ var MergedTranscriptWriter = class {
86828
86927
  function rolloutLocation(rolloutPath) {
86829
86928
  const record2 = readFirstRecord(rolloutPath, (candidate) => candidate.type === "session_meta");
86830
86929
  const meta3 = record2?.payload;
86831
- if (!meta3 || typeof meta3 !== "object" || Array.isArray(meta3)) return { kind: "session", totals: null, fastTotals: null };
86930
+ if (!meta3 || typeof meta3 !== "object" || Array.isArray(meta3)) return { kind: "session", codexClient: "unknown", totals: null, fastTotals: null };
86832
86931
  const { cwd, id, session_id: fallbackId } = meta3;
86833
86932
  const sessionId = id ?? fallbackId;
86834
86933
  const startedAt = record2?.timestamp;
86835
86934
  return {
86935
+ codexClient: classifyCodexClient(meta3),
86836
86936
  kind: isSidecarThread(meta3) ? "subagent" : "session",
86837
86937
  ...typeof sessionId === "string" && { sessionId },
86838
86938
  ...typeof startedAt === "string" && { startedAt },
@@ -86891,7 +86991,7 @@ async function collectCodexSessions(options = {}) {
86891
86991
  let skippedTooLarge = 0;
86892
86992
  let mergedThreads = 0;
86893
86993
  let largestMergedBytes = 0;
86894
- const externalIdOf = (rolloutPath) => path5.basename(rolloutPath, ".jsonl");
86994
+ const harnessSessionIdOf = (rolloutPath) => path5.basename(rolloutPath, ".jsonl");
86895
86995
  const files = /* @__PURE__ */ new Map();
86896
86996
  const observe = async (paths, archived, discoverySessionId) => {
86897
86997
  for (const rolloutPath of paths) {
@@ -86932,7 +87032,7 @@ async function collectCodexSessions(options = {}) {
86932
87032
  }
86933
87033
  for (const [threadId2, observed] of byThread) {
86934
87034
  const stored = dedupeStoreCopies(observed);
86935
- let externalId = externalIdOf((stored.find((file2) => !file2.identity.page) ?? stored[0]).rolloutPath);
87035
+ let harnessSessionId = harnessSessionIdOf((stored.find((file2) => !file2.identity.page) ?? stored[0]).rolloutPath);
86936
87036
  try {
86937
87037
  const mergedTranscriptPath = stored.length > 1 ? path5.join(mergedTranscriptsDir, `${threadId2}.jsonl`) : void 0;
86938
87038
  const changedMs = Math.max(...stored.map((file2) => file2.changedMs));
@@ -86949,7 +87049,7 @@ async function collectCodexSessions(options = {}) {
86949
87049
  if (named.length === 0) continue;
86950
87050
  const threadFiles = named.length > 1 ? orderPages(named) : named;
86951
87051
  const base = threadFiles[0];
86952
- externalId = externalIdOf(base.rolloutPath);
87052
+ harnessSessionId = harnessSessionIdOf(base.rolloutPath);
86953
87053
  const mtimeMs = Math.max(...threadFiles.map((file2) => file2.mtimeMs));
86954
87054
  const sizeBytes = threadFiles.reduce((sum2, file2) => sum2 + file2.sizeBytes, 0);
86955
87055
  if (sizeBytes > maxBytes) {
@@ -86972,7 +87072,7 @@ async function collectCodexSessions(options = {}) {
86972
87072
  continue;
86973
87073
  }
86974
87074
  const thread = {
86975
- externalId,
87075
+ harnessSessionId,
86976
87076
  files: threadFiles,
86977
87077
  ...threadFiles.length > 1 && mergedTranscriptPath !== void 0 && { mergedTranscriptPath },
86978
87078
  mtimeMs,
@@ -86984,8 +87084,8 @@ async function collectCodexSessions(options = {}) {
86984
87084
  transcriptPath: base.rolloutPath,
86985
87085
  ...location.cwd && { cwd: location.cwd },
86986
87086
  item: {
86987
- source: "codex",
86988
- externalId,
87087
+ harness: "codex-local",
87088
+ harnessSessionId,
86989
87089
  status: now - mtimeMs < ACTIVE_GRACE_MS ? "active" : "inactive",
86990
87090
  archived: thread.archived,
86991
87091
  capturedVia: decision.via
@@ -86995,7 +87095,7 @@ async function collectCodexSessions(options = {}) {
86995
87095
  }
86996
87096
  candidates.push({ thread, ...location.cwd && { cwd: location.cwd }, decision });
86997
87097
  } catch (error63) {
86998
- unreadable.push(`${externalId}: ${describeReadError(error63)}`);
87098
+ unreadable.push(`${harnessSessionId}: ${describeReadError(error63)}`);
86999
87099
  observeFileDiagnostic(options.onFileDiagnostic, {
87000
87100
  path: stored[0].rolloutPath,
87001
87101
  reason: "unreadable",
@@ -87059,11 +87159,13 @@ async function collectCodexSessions(options = {}) {
87059
87159
  const title = summary.sessionId ? threadNames.get(summary.sessionId) : void 0;
87060
87160
  items.push({
87061
87161
  mtimeMs: thread.mtimeMs,
87162
+ codexClient: summary.codexClient,
87163
+ ...summary.noninteractive && { codexNoninteractive: true },
87062
87164
  transcriptPath: transcriptUploadSourcePath,
87063
87165
  ...cwd && { cwd },
87064
87166
  item: {
87065
- source: "codex",
87066
- externalId: thread.externalId,
87167
+ harness: "codex-local",
87168
+ harnessSessionId: thread.harnessSessionId,
87067
87169
  status: now - thread.mtimeMs < ACTIVE_GRACE_MS ? "active" : "inactive",
87068
87170
  archived: thread.archived,
87069
87171
  ...summary.standaloneReview && { automation: true },
@@ -87092,7 +87194,7 @@ async function collectCodexSessions(options = {}) {
87092
87194
  });
87093
87195
  } catch (error63) {
87094
87196
  writer?.abandon();
87095
- unreadable.push(`${thread.externalId}: ${describeReadError(error63)}`);
87197
+ unreadable.push(`${thread.harnessSessionId}: ${describeReadError(error63)}`);
87096
87198
  observeFileDiagnostic(options.onFileDiagnostic, {
87097
87199
  path: thread.files[0].rolloutPath,
87098
87200
  reason: "unreadable",
@@ -87140,7 +87242,7 @@ function codexThreadCwd(threadId2, sessionsDir = path5.join(os6.homedir(), ".cod
87140
87242
  return void 0;
87141
87243
  }
87142
87244
 
87143
- // ../../apps/collector/src/cursorTranscriptFile.ts
87245
+ // ../../apps/syncservice/src/cursorTranscriptFile.ts
87144
87246
  import { createHash as createHash3 } from "node:crypto";
87145
87247
  import {
87146
87248
  chmodSync as chmodSync3,
@@ -87158,7 +87260,7 @@ import {
87158
87260
  import os8 from "node:os";
87159
87261
  import path7 from "node:path";
87160
87262
 
87161
- // ../../apps/collector/src/captureOmissions.ts
87263
+ // ../../apps/syncservice/src/captureOmissions.ts
87162
87264
  var REPORTED_REASONS = /* @__PURE__ */ new Set([
87163
87265
  "unsupported",
87164
87266
  "malformed",
@@ -87170,21 +87272,21 @@ function createOmissionRecorder() {
87170
87272
  const count3 = (reason, by = 1) => {
87171
87273
  if (by > 0) counts[reason] = (counts[reason] ?? 0) + by;
87172
87274
  };
87173
- const shape = (reason, path32, valueType, formatVersion, by = 1) => {
87275
+ const shape = (reason, path34, valueType, formatVersion, by = 1) => {
87174
87276
  if (!REPORTED_REASONS.has(reason)) return;
87175
- const key = `${path32}\0${reason}\0${valueType}\0${formatVersion ?? ""}`;
87277
+ const key = `${path34}\0${reason}\0${valueType}\0${formatVersion ?? ""}`;
87176
87278
  const group = groups.get(key);
87177
87279
  if (group) group.count += by;
87178
87280
  else if (groups.size < MAX_STRUCTURE_DIAGNOSTICS) {
87179
- groups.set(key, { path: path32, reason, valueType, count: by, ...formatVersion !== void 0 && { formatVersion } });
87281
+ groups.set(key, { path: path34, reason, valueType, count: by, ...formatVersion !== void 0 && { formatVersion } });
87180
87282
  }
87181
87283
  };
87182
87284
  return {
87183
87285
  count: count3,
87184
87286
  shape,
87185
- note(reason, path32, valueType, formatVersion) {
87287
+ note(reason, path34, valueType, formatVersion) {
87186
87288
  count3(reason);
87187
- shape(reason, path32, valueType, formatVersion);
87289
+ shape(reason, path34, valueType, formatVersion);
87188
87290
  },
87189
87291
  absorb(other) {
87190
87292
  for (const [reason, by] of Object.entries(other.omissions())) {
@@ -87209,7 +87311,7 @@ function unhandledObservations(shapes, externalId) {
87209
87311
  return shapes.map(({ formatVersion, ...shape }) => ({ ...shape, formatVersion: formatVersion ?? null, externalId }));
87210
87312
  }
87211
87313
 
87212
- // ../../apps/collector/src/cursorLocal.ts
87314
+ // ../../apps/syncservice/src/cursorLocal.ts
87213
87315
  import { createHash as createHash2 } from "node:crypto";
87214
87316
  import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as mkdirSync3, utimesSync as utimesSync2, writeFileSync as writeFileSync2 } from "node:fs";
87215
87317
  import os7 from "node:os";
@@ -87424,8 +87526,8 @@ var MODEL_INFO_FIELDS_INTERPRETED = /* @__PURE__ */ new Set(["modelName"]);
87424
87526
  function collectUnfamiliar(record2, interpreted, excluded, prefix, into, recorder, formatVersion) {
87425
87527
  for (const [key, value] of Object.entries(record2)) {
87426
87528
  if (interpreted.has(key) || excluded.has(key)) continue;
87427
- const path32 = prefix === "" ? key : `${prefix}.${key}`;
87428
- into.set(path32, value);
87529
+ const path34 = prefix === "" ? key : `${prefix}.${key}`;
87530
+ into.set(path34, value);
87429
87531
  recorder.shape("unsupported", `bubble.${prefix === "" ? "" : `${prefix}.`}${nativeTypeLabel(key) ?? "other"}`, jsonValueType(value), formatVersion);
87430
87532
  }
87431
87533
  }
@@ -87511,8 +87613,8 @@ function bubbleLines(bubble, at, recorder) {
87511
87613
  const formatVersion = typeof bubble._v === "number" || typeof bubble._v === "string" ? String(bubble._v) : void 0;
87512
87614
  if (bubble.type !== 1 && bubble.type !== 2) {
87513
87615
  const nativeType = nativeTypeLabel(String(bubble.type));
87514
- const path32 = `bubble.type=${nativeType ?? "other"}`;
87515
- recorder.note("unsupported", path32, jsonValueType(bubble.type), formatVersion);
87616
+ const path34 = `bubble.type=${nativeType ?? "other"}`;
87617
+ recorder.note("unsupported", path34, jsonValueType(bubble.type), formatVersion);
87516
87618
  const retained = Object.fromEntries(Object.entries(bubble).filter(([key]) => !BUBBLE_FIELDS_EXCLUDED.has(key)));
87517
87619
  const bounded = boundUnfamiliarPayload(retained);
87518
87620
  if (bounded.payload === void 0) recorder.count("truncated");
@@ -87729,8 +87831,8 @@ function collectFromStore(db, userDir, options, result, knownIds) {
87729
87831
  transcriptPath: path6.join(userDir, "globalStorage", "state.vscdb"),
87730
87832
  ...cwd && { cwd },
87731
87833
  item: {
87732
- source: "cursor",
87733
- externalId: raw.composerId,
87834
+ harness: "cursor-local",
87835
+ harnessSessionId: raw.composerId,
87734
87836
  status: now - lastUpdatedAt < ACTIVE_GRACE_MS ? "active" : "inactive",
87735
87837
  capturedVia: decision.via
87736
87838
  }
@@ -87808,8 +87910,8 @@ function collectFromStore(db, userDir, options, result, knownIds) {
87808
87910
  transcriptPath: transcriptUploadSourcePath,
87809
87911
  ...cwd && { cwd },
87810
87912
  item: {
87811
- source: "cursor",
87812
- externalId: raw.composerId,
87913
+ harness: "cursor-local",
87914
+ harnessSessionId: raw.composerId,
87813
87915
  status: now - lastUpdatedAt < ACTIVE_GRACE_MS ? "active" : "inactive",
87814
87916
  // The header's own archive evidence, both ways; omitted (nothing
87815
87917
  // claimed) when the column establishes neither.
@@ -87836,7 +87938,7 @@ function collectFromStore(db, userDir, options, result, knownIds) {
87836
87938
  }
87837
87939
  }
87838
87940
 
87839
- // ../../apps/collector/src/cursorTranscriptFile.ts
87941
+ // ../../apps/syncservice/src/cursorTranscriptFile.ts
87840
87942
  var textBlock = external_exports.object({ type: external_exports.literal("text"), text: external_exports.string() });
87841
87943
  var toolUseBlock = external_exports.object({
87842
87944
  type: external_exports.literal("tool_use"),
@@ -87863,12 +87965,12 @@ var CONTENT_LINE_TYPES2 = /* @__PURE__ */ new Set([
87863
87965
  function parseCursorTranscriptFile(text) {
87864
87966
  const lines = [];
87865
87967
  const recorder = createOmissionRecorder();
87866
- const retainUnsupported = (record2, at, path32, discriminator) => {
87968
+ const retainUnsupported = (record2, at, path34, discriminator) => {
87867
87969
  const nativeType = nativeTypeLabel(discriminator);
87868
87970
  const bounded = boundUnfamiliarPayload(record2);
87869
87971
  lines.push({ type: "unsupported", ...nativeType !== void 0 && { nativeType }, ...at, ...bounded });
87870
- recorder.note("unsupported", `${path32}=${nativeType ?? "other"}`, jsonValueType(discriminator));
87871
- if (bounded.payload === void 0) recorder.note("truncated", `${path32}=${nativeType ?? "other"}`, "object");
87972
+ recorder.note("unsupported", `${path34}=${nativeType ?? "other"}`, jsonValueType(discriminator));
87973
+ if (bounded.payload === void 0) recorder.note("truncated", `${path34}=${nativeType ?? "other"}`, "object");
87872
87974
  };
87873
87975
  text.split("\n").forEach((row, recordIndex) => {
87874
87976
  if (!row.trim()) return;
@@ -87890,8 +87992,8 @@ function parseCursorTranscriptFile(text) {
87890
87992
  }
87891
87993
  const record2 = message.safeParse(value);
87892
87994
  if (!record2.success) {
87893
- const [path32, discriminator] = typeof value.type === "string" ? ["record.type", value.type] : typeof value.role === "string" ? ["message.role", value.role] : ["record", void 0];
87894
- retainUnsupported(value, { recordIndex }, path32, discriminator);
87995
+ const [path34, discriminator] = typeof value.type === "string" ? ["record.type", value.type] : typeof value.role === "string" ? ["message.role", value.role] : ["record", void 0];
87996
+ retainUnsupported(value, { recordIndex }, path34, discriminator);
87895
87997
  return;
87896
87998
  }
87897
87999
  const role = record2.data.role;
@@ -88053,8 +88155,8 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
88053
88155
  continue;
88054
88156
  }
88055
88157
  const common = {
88056
- source: "cursor",
88057
- externalId: record2.sessionId,
88158
+ harness: "cursor-local",
88159
+ harnessSessionId: record2.sessionId,
88058
88160
  status: (options.now ?? Date.now()) - stat.mtimeMs < ACTIVE_GRACE_MS ? "active" : "inactive",
88059
88161
  ...decision.repoFullName && { repoFullName: decision.repoFullName },
88060
88162
  capturedVia: decision.via
@@ -88144,7 +88246,7 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
88144
88246
  }
88145
88247
  }
88146
88248
 
88147
- // ../../apps/collector/src/hookInstall.ts
88249
+ // ../../apps/syncservice/src/hookInstall.ts
88148
88250
  import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
88149
88251
  import os9 from "node:os";
88150
88252
  import path8 from "node:path";
@@ -88266,7 +88368,7 @@ function installCollectorHooks(homeDir = os9.homedir()) {
88266
88368
  };
88267
88369
  }
88268
88370
 
88269
- // ../../apps/collector/src/lifecycleJournal.ts
88371
+ // ../../apps/syncservice/src/lifecycleJournal.ts
88270
88372
  import path9 from "node:path";
88271
88373
  var LIFECYCLE_JOURNAL_FILENAME = "session-lifecycle.jsonl";
88272
88374
  function lifecycleJournalPath(home) {
@@ -88298,7 +88400,7 @@ function observedSessionEnd(entry, mtimeMs) {
88298
88400
  return entry.at;
88299
88401
  }
88300
88402
 
88301
- // ../../apps/collector/src/harnessHooks.ts
88403
+ // ../../apps/syncservice/src/harnessHooks.ts
88302
88404
  import {
88303
88405
  existsSync as existsSync5,
88304
88406
  lstatSync as lstatSync3,
@@ -88463,10 +88565,12 @@ function installHarnessHooks(home) {
88463
88565
  });
88464
88566
  }
88465
88567
 
88466
- // ../../apps/collector/src/hookHealth.ts
88568
+ // ../../apps/syncservice/src/hookHealth.ts
88467
88569
  var HOOK_OBSERVATION_GRACE_MS = 2 * 6e4;
88468
88570
  var hookHealthSchema = external_exports.object({
88469
88571
  harness: hookHarnessSchema,
88572
+ /** Latest recorded interactive Codex activity, not file discovery time. */
88573
+ codexActivity: external_exports.object({ client: codexClientSchema, at: external_exports.string() }).optional(),
88470
88574
  /** What this daemon's boot-time install did (installCollectorHooks / installHarnessHooks). */
88471
88575
  install: hookInstallOutcomeSchema,
88472
88576
  /** unverified: no in-scope session started since the install has been
@@ -88546,7 +88650,7 @@ function inspectHookConfig(harness, home) {
88546
88650
  var NOT_FIRING = {
88547
88651
  codex: () => ({
88548
88652
  problem: "Codex hooks are installed but not running",
88549
- fix: "In Codex, run /hooks and trust the Powerplant hooks."
88653
+ fix: codexHookInstructions("unknown")
88550
88654
  }),
88551
88655
  claude: () => ({
88552
88656
  problem: "Claude Code hooks are installed but didn't run for a new session",
@@ -88588,10 +88692,10 @@ function describeHookSilence(harness, state, home) {
88588
88692
  return { kind: "not-firing", ...NOT_FIRING[harness](home) };
88589
88693
  }
88590
88694
  }
88591
- var HARNESS_OF_SOURCE = {
88592
- "claude-code": "claude",
88593
- codex: "codex",
88594
- cursor: "cursor"
88695
+ var NATIVE_HOOK_NAME_BY_HARNESS = {
88696
+ "claude-local": "claude",
88697
+ "codex-local": "codex",
88698
+ "cursor-local": "cursor"
88595
88699
  };
88596
88700
  function hookSessionId(harness, externalId) {
88597
88701
  if (harness !== "codex") return externalId;
@@ -88636,11 +88740,10 @@ function createHookHealthTracker(deps) {
88636
88740
  }
88637
88741
  };
88638
88742
  const admit = (session, nowMs) => {
88639
- const harness = HARNESS_OF_SOURCE[session.item.source];
88640
- if (harness === void 0) return;
88743
+ const harness = NATIVE_HOOK_NAME_BY_HARNESS[session.item.harness];
88641
88744
  if (session.item.automation === true || session.item.startedAt === void 0) return;
88642
88745
  if (!(Date.parse(session.item.startedAt) > installedAtMs)) return;
88643
- const sessionId = hookSessionId(harness, session.item.externalId);
88746
+ const sessionId = hookSessionId(harness, session.item.harnessSessionId);
88644
88747
  if (sessionId === null) return;
88645
88748
  const key = `${harness}:${sessionId}`;
88646
88749
  if (judged.has(key) || candidates.has(key)) return;
@@ -88652,7 +88755,7 @@ function createHookHealthTracker(deps) {
88652
88755
  const name = HARNESS_NAMES[harness];
88653
88756
  if (fired) {
88654
88757
  if (current.state === "firing") return false;
88655
- health[harness] = { harness, install: current.install, state: "firing" };
88758
+ health[harness] = { ...current, state: "firing", silence: void 0 };
88656
88759
  log3(
88657
88760
  current.state === "silent" ? `${name} hooks are firing again (session ${candidate.sessionId} has a hook record)` : `${name} hooks verified firing (session ${candidate.sessionId} has a hook record)`
88658
88761
  );
@@ -88661,8 +88764,7 @@ function createHookHealthTracker(deps) {
88661
88764
  const silence = describeHookSilence(harness, inspect(harness), home);
88662
88765
  if (current.silence?.problem === silence.problem) return false;
88663
88766
  health[harness] = {
88664
- harness,
88665
- install: current.install,
88767
+ ...current,
88666
88768
  state: "silent",
88667
88769
  silence: { ...silence, since: new Date(nowMs).toISOString() }
88668
88770
  };
@@ -88689,9 +88791,24 @@ function createHookHealthTracker(deps) {
88689
88791
  };
88690
88792
  return {
88691
88793
  observe(sessions, nowMs) {
88692
- for (const session of sessions) admit(session, nowMs);
88794
+ let activityChanged = false;
88795
+ for (const session of sessions) {
88796
+ if (session.item.harness === "codex-local" && session.item.automation !== true && session.codexNoninteractive !== true) {
88797
+ const at = session.item.endedAt ?? session.item.startedAt;
88798
+ const timestamp = at === void 0 ? NaN : Date.parse(at);
88799
+ const previous = health.codex.codexActivity;
88800
+ if (Number.isFinite(timestamp) && timestamp <= nowMs && (previous === void 0 || timestamp > Date.parse(previous.at))) {
88801
+ health.codex = { ...health.codex, codexActivity: {
88802
+ client: session.codexClient ?? "unknown",
88803
+ at: new Date(timestamp).toISOString()
88804
+ } };
88805
+ activityChanged = true;
88806
+ }
88807
+ }
88808
+ admit(session, nowMs);
88809
+ }
88693
88810
  let observed;
88694
- let changed = false;
88811
+ let changed = activityChanged;
88695
88812
  let failure2;
88696
88813
  for (const [key, candidate] of candidates) {
88697
88814
  if (nowMs - candidate.firstSeenMs < HOOK_OBSERVATION_GRACE_MS) continue;
@@ -88721,7 +88838,7 @@ function createHookHealthTracker(deps) {
88721
88838
  };
88722
88839
  }
88723
88840
 
88724
- // ../../apps/collector/src/status.ts
88841
+ // ../../apps/syncservice/src/status.ts
88725
88842
  var HEARTBEAT_INTERVAL_MS = 6e4;
88726
88843
  var STALLED_AFTER_MS = 5 * 6e4;
88727
88844
  var CONTROL_POLL_MS = 15e3;
@@ -88867,7 +88984,7 @@ function isPidAlive(pid) {
88867
88984
  }
88868
88985
  }
88869
88986
 
88870
- // ../../apps/collector/src/credentialMigration.ts
88987
+ // ../../apps/syncservice/src/credentialMigration.ts
88871
88988
  function assertCredentialMigrationReady(appEnv) {
88872
88989
  const reason = credentialMigrationBlocker(appEnv);
88873
88990
  if (reason === null) return;
@@ -88898,7 +89015,7 @@ function credentialMigrationBlocker(appEnv) {
88898
89015
  return null;
88899
89016
  }
88900
89017
 
88901
- // ../../apps/collector/src/macosCredentialStore.ts
89018
+ // ../../apps/syncservice/src/macosCredentialStore.ts
88902
89019
  var LEGACY_SERVICE = "powerplant-collector";
88903
89020
  var KEY_SERVICE = "powerplant-collector-encryption";
88904
89021
  var keySchema = external_exports.string().regex(/^[0-9a-f]{64}$/);
@@ -89098,7 +89215,7 @@ var MacosCredentialStore = class {
89098
89215
  }
89099
89216
  };
89100
89217
 
89101
- // ../../apps/collector/src/credentials.ts
89218
+ // ../../apps/syncservice/src/credentials.ts
89102
89219
  var storedCredentialsSchema = external_exports.object({
89103
89220
  machineId: external_exports.string().min(1),
89104
89221
  machineName: external_exports.string().min(1),
@@ -89254,13 +89371,13 @@ function fallbackFile(appEnv) {
89254
89371
  return path14.join(os12.homedir(), ".config", "powerplant", `collector-${appEnv}.json`);
89255
89372
  }
89256
89373
 
89257
- // ../../apps/collector/src/enroll.ts
89374
+ // ../../apps/syncservice/src/enroll.ts
89258
89375
  import { spawn } from "node:child_process";
89259
89376
  import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
89260
89377
  import http5 from "node:http";
89261
89378
  import os13 from "node:os";
89262
89379
 
89263
- // ../../apps/collector/src/upload.ts
89380
+ // ../../apps/syncservice/src/upload.ts
89264
89381
  import { readFileSync as readFileSync9 } from "node:fs";
89265
89382
  import { gzipSync } from "node:zlib";
89266
89383
  function parseApiResponse(schema, body, route) {
@@ -89379,7 +89496,7 @@ async function uploadSessions(apiUrl, machineToken, items) {
89379
89496
  unchanged: external_exports.number(),
89380
89497
  outOfPolicy: external_exports.number(),
89381
89498
  deferred: external_exports.number().optional(),
89382
- foreignOwned: external_exports.array(external_exports.object({ source: external_exports.string(), externalId: external_exports.string() })).optional()
89499
+ foreignOwned: external_exports.array(external_exports.object({ source: external_exports.enum(LEGACY_COLLECTOR_SESSION_SOURCES), externalId: external_exports.string() })).optional()
89383
89500
  })
89384
89501
  }),
89385
89502
  await response.json().catch(() => null),
@@ -89389,7 +89506,16 @@ async function uploadSessions(apiUrl, machineToken, items) {
89389
89506
  unchanged += result.data.unchanged;
89390
89507
  outOfPolicy += result.data.outOfPolicy;
89391
89508
  deferred += result.data.deferred ?? 0;
89392
- foreignOwned.push(...result.data.foreignOwned ?? []);
89509
+ for (const identity of result.data.foreignOwned ?? []) {
89510
+ const harness = harnessFromLegacySessionSource(identity.source);
89511
+ if (harness.kind !== "harness") {
89512
+ throw new Error("sessions ingest returned an unsupported ownership identity");
89513
+ }
89514
+ foreignOwned.push({
89515
+ harness: external_exports.enum(COLLECTOR_SESSION_HARNESSES).parse(harness.harness),
89516
+ harnessSessionId: identity.externalId
89517
+ });
89518
+ }
89393
89519
  }
89394
89520
  return { upserted, unchanged, outOfPolicy, deferred, ...foreignOwned.length > 0 ? { foreignOwned } : {} };
89395
89521
  }
@@ -89462,7 +89588,7 @@ async function uploadRawSessions(apiUrl, machineToken, transcriptUploadSources,
89462
89588
  shipped?.set(transcriptUploadSourcePath, session.mtimeMs);
89463
89589
  continue;
89464
89590
  }
89465
- const query = `source=${session.item.source}&externalId=${encodeURIComponent(session.item.externalId)}`;
89591
+ const query = `harness=${session.item.harness}&harnessSessionId=${encodeURIComponent(session.item.harnessSessionId)}`;
89466
89592
  const response = await fetchWithRetry(
89467
89593
  "uploading a raw transcript",
89468
89594
  `${apiUrl}/api/ingest/sessions/raw?${query}`,
@@ -89496,7 +89622,7 @@ async function uploadRawSessions(apiUrl, machineToken, transcriptUploadSources,
89496
89622
  } catch (error63) {
89497
89623
  if (error63 instanceof RateLimitedError) rateLimited ??= error63;
89498
89624
  summary.failed.push(
89499
- `${session.item.externalId}: ${error63 instanceof Error ? error63.message : String(error63)}`
89625
+ `${session.item.harnessSessionId}: ${error63 instanceof Error ? error63.message : String(error63)}`
89500
89626
  );
89501
89627
  }
89502
89628
  }
@@ -89504,7 +89630,7 @@ async function uploadRawSessions(apiUrl, machineToken, transcriptUploadSources,
89504
89630
  return summary;
89505
89631
  }
89506
89632
 
89507
- // ../../apps/collector/src/enroll.ts
89633
+ // ../../apps/syncservice/src/enroll.ts
89508
89634
  var APPROVAL_TIMEOUT_MS = 5 * 60 * 1e3;
89509
89635
  var gotrueTokenSchema = external_exports.object({ access_token: external_exports.string().min(1) });
89510
89636
  var gotrueErrorSchema = external_exports.object({
@@ -89562,7 +89688,7 @@ async function runEnrollment(config2, options) {
89562
89688
  let scopePaths = (options.scope ?? []).map(normalizeScopePath);
89563
89689
  let captureMode = scopePaths.length > 0 ? "scope" : "org-repos";
89564
89690
  if (captureMode === "scope") {
89565
- log3(`- Folders that will upload once approved: ${scopePaths.join(", ")}`);
89691
+ log3(`Folders that will upload once approved: ${scopePaths.join(", ")}`);
89566
89692
  }
89567
89693
  const result = await enroll(config2, {
89568
89694
  name,
@@ -89577,7 +89703,7 @@ async function runEnrollment(config2, options) {
89577
89703
  if (config2.appEnv === "development") {
89578
89704
  const home = normalizeScopePath(os13.homedir());
89579
89705
  log3(
89580
- `- No GitHub integration on org "${result.org.name}", syncing sessions under ${home} (your home folder, local DB only). Re-enroll with --scope <path> to narrow.`
89706
+ `No GitHub integration on org "${result.org.name}", syncing sessions under ${home} (your home folder, local DB only). Re-enroll with --scope <path> to narrow.`
89581
89707
  );
89582
89708
  captureMode = "scope";
89583
89709
  scopePaths = [home];
@@ -89614,14 +89740,6 @@ async function runEnrollment(config2, options) {
89614
89740
  // claims are unknown, and the first sweep must not stamp over them.
89615
89741
  ...workspace.integration === "linked" && workspace.owners.length === 0 && workspace.repos === null && { unresolved: true }
89616
89742
  }));
89617
- const policy = captureMode === "org-repos" ? {
89618
- mode: "org-repos",
89619
- allowedOwners: orgPolicy?.owners ?? [],
89620
- allowedRepos: orgPolicy?.repos ?? null,
89621
- ...workspacePolicies !== void 0 && { workspaceClaims: workspacePolicies },
89622
- memberFolders: [],
89623
- repoOf: () => null
89624
- } : { mode: "scope", scopePaths, repoOf: () => null };
89625
89743
  const credentials = {
89626
89744
  machineId: result.machine.id,
89627
89745
  machineName: result.machine.name,
@@ -89637,9 +89755,7 @@ async function runEnrollment(config2, options) {
89637
89755
  scopePaths
89638
89756
  };
89639
89757
  const location = saveCredentials(config2.appEnv, credentials);
89640
- log3(`- Enrolled "${result.machine.name}" (${result.machine.id}) into org "${result.org.name}".`);
89641
- log3(`- Machine token stored in ${location}.`);
89642
- log3(`- ${describeEnrollmentCapture(policy)}.`);
89758
+ log3(`Machine token stored in ${location}`);
89643
89759
  return credentials;
89644
89760
  }
89645
89761
  async function enroll(config2, options, createAuthClient = gotrueAuthClient, listener = {}) {
@@ -89822,7 +89938,7 @@ function waitForApproval(approvalUrl, state, options) {
89822
89938
  server.listen(port, "127.0.0.1", () => {
89823
89939
  const address = server.address();
89824
89940
  if (onListening && address !== null && typeof address === "object") onListening(address.port);
89825
- log3(`- Opening approval page\u2026 ${approvalUrl}`);
89941
+ log3(`Opening approval page\u2026 ${approvalUrl}`);
89826
89942
  open3(approvalUrl);
89827
89943
  });
89828
89944
  });
@@ -89837,7 +89953,7 @@ function openBrowser(url2) {
89837
89953
  spawn(command, [url2], { stdio: "ignore", detached: true }).unref();
89838
89954
  }
89839
89955
 
89840
- // ../../apps/collector/src/folders.ts
89956
+ // ../../apps/syncservice/src/folders.ts
89841
89957
  var defaultDeps = { load: loadCredentials, persist: saveCredentials };
89842
89958
  function requireEnrolled(config2, enrollCommand, deps) {
89843
89959
  const credentials = deps.load(config2.appEnv);
@@ -89898,7 +90014,7 @@ function removeFolder(config2, rawPath, enrollCommand, log3, deps = defaultDeps)
89898
90014
  log3(`Removed ${folder}, sessions there stay local from the next sync pass.`);
89899
90015
  }
89900
90016
 
89901
- // ../../apps/collector/src/claudeCode.ts
90017
+ // ../../apps/syncservice/src/claudeCode.ts
89902
90018
  import os14 from "node:os";
89903
90019
  import path15 from "node:path";
89904
90020
  import { setImmediate as yieldToEventLoop2 } from "node:timers/promises";
@@ -90024,7 +90140,7 @@ async function collectClaudeCodeSessions(options = {}) {
90024
90140
  mtimeMs: stat.mtimeMs,
90025
90141
  transcriptPath,
90026
90142
  ...cwd && { cwd },
90027
- item: { source: "claude-code", externalId: sessionId, status, capturedVia: decision.via }
90143
+ item: { harness: "claude-local", harnessSessionId: sessionId, status, capturedVia: decision.via }
90028
90144
  });
90029
90145
  continue;
90030
90146
  }
@@ -90082,8 +90198,8 @@ async function collectClaudeCodeSessions(options = {}) {
90082
90198
  transcriptPath,
90083
90199
  ...cwd && { cwd },
90084
90200
  item: {
90085
- source: "claude-code",
90086
- externalId: sessionId,
90201
+ harness: "claude-local",
90202
+ harnessSessionId: sessionId,
90087
90203
  status,
90088
90204
  ...summary.startedAt && { startedAt: summary.startedAt },
90089
90205
  ...endedAt && { endedAt },
@@ -90207,11 +90323,11 @@ function claudeCodeSessionCwd(sessionId, claudeDir = path15.join(os14.homedir(),
90207
90323
  return void 0;
90208
90324
  }
90209
90325
 
90210
- // ../../apps/collector/src/protectedRepoDiscovery.ts
90326
+ // ../../apps/syncservice/src/protectedRepoDiscovery.ts
90211
90327
  import os15 from "node:os";
90212
90328
  import path16 from "node:path";
90213
90329
 
90214
- // ../../apps/collector/src/syncWindow.ts
90330
+ // ../../apps/syncservice/src/syncWindow.ts
90215
90331
  var STEADY_SYNC_WINDOW_DAYS = 3;
90216
90332
  var DEEP_FIRST_SYNC_DAYS = 90;
90217
90333
  var DEEP_FIRST_SYNC_MAX_SESSIONS = 100;
@@ -90242,7 +90358,7 @@ function describeScanReach(window2, narrowSinceMs) {
90242
90358
  return `changed since ${new Date(narrowSinceMs).toISOString()}`;
90243
90359
  }
90244
90360
 
90245
- // ../../apps/collector/src/protectedRepoDiscovery.ts
90361
+ // ../../apps/syncservice/src/protectedRepoDiscovery.ts
90246
90362
  var defaultDiscoveryDeps = {
90247
90363
  collectClaude: collectClaudeCodeSessions,
90248
90364
  collectCodex: collectCodexSessions,
@@ -90438,7 +90554,7 @@ function sameList(a, b2) {
90438
90554
  return a.length === b2.length && a.every((root, index) => root === b2[index]);
90439
90555
  }
90440
90556
 
90441
- // ../../apps/collector/src/recentCatchup.ts
90557
+ // ../../apps/syncservice/src/recentCatchup.ts
90442
90558
  function createRecentCatchup(run, now = Date.now) {
90443
90559
  let coveredSince = now();
90444
90560
  let nextCheck = coveredSince + 15e3;
@@ -90478,7 +90594,7 @@ function recentSyncOptions(shared, narrowSinceMs, selection) {
90478
90594
  };
90479
90595
  }
90480
90596
 
90481
- // ../../apps/collector/src/branchFacts.ts
90597
+ // ../../apps/syncservice/src/branchFacts.ts
90482
90598
  import { readFileSync as readFileSync10 } from "node:fs";
90483
90599
  import path17 from "node:path";
90484
90600
  var SHA_SHAPE = /^[0-9a-f]{40}$/;
@@ -90512,13 +90628,13 @@ function branchFactsOf(sessions, observe) {
90512
90628
  if (!session.cwd) return [];
90513
90629
  const observed = observe(session.cwd);
90514
90630
  if (!observed) return [];
90515
- const key = `${session.item.source}
90516
- ${session.item.externalId}
90631
+ const key = `${session.item.harness}
90632
+ ${session.item.harnessSessionId}
90517
90633
  ${observed.repoFullName}
90518
90634
  ${observed.branch}`;
90519
90635
  if (seen.has(key)) return [];
90520
90636
  seen.add(key);
90521
- return [{ source: session.item.source, externalId: session.item.externalId, ...observed }];
90637
+ return [{ harness: session.item.harness, harnessSessionId: session.item.harnessSessionId, ...observed }];
90522
90638
  });
90523
90639
  }
90524
90640
  function branchObserver(environment = {}) {
@@ -90556,7 +90672,7 @@ function readIfExists2(p) {
90556
90672
  }
90557
90673
  }
90558
90674
 
90559
- // ../../apps/collector/src/previewRegistration.ts
90675
+ // ../../apps/syncservice/src/previewRegistration.ts
90560
90676
  async function registerAnnouncedPreviews(apiUrl, machineToken, collected, memo2, deps = {}) {
90561
90677
  const readTranscript = deps.readTranscript ?? readIfExists;
90562
90678
  const upload = deps.upload ?? uploadPreviewRegistration;
@@ -90574,7 +90690,11 @@ async function registerAnnouncedPreviews(apiUrl, machineToken, collected, memo2,
90574
90690
  try {
90575
90691
  const text = readTranscript(session.transcriptPath);
90576
90692
  if (text === null) continue;
90577
- const previews = announcedPreviewsFromTurns(parseSessionTurns(session.item.source, text)).filter(
90693
+ const legacyIdentity = legacySessionSourceFromHarness(session.item.harness);
90694
+ if (legacyIdentity.kind === "unsupported") {
90695
+ throw new Error(`Transcript parsing does not support ${session.item.harness}`);
90696
+ }
90697
+ const previews = announcedPreviewsFromTurns(parseSessionTurns(legacyIdentity.source, text)).filter(
90578
90698
  (preview) => preview.url.length <= MAX_PREVIEW_URL_LENGTH && redactText(preview.url) === preview.url
90579
90699
  ).slice(-MAX_REGISTERED_PREVIEWS).map((preview) => ({
90580
90700
  ...preview,
@@ -90586,32 +90706,32 @@ async function registerAnnouncedPreviews(apiUrl, machineToken, collected, memo2,
90586
90706
  continue;
90587
90707
  }
90588
90708
  const outcome = await upload(apiUrl, machineToken, {
90589
- source: session.item.source,
90590
- externalId: session.item.externalId,
90709
+ harness: session.item.harness,
90710
+ harnessSessionId: session.item.harnessSessionId,
90591
90711
  previews
90592
90712
  });
90593
90713
  if (outcome === "foreign-owner") {
90594
90714
  memo2.set(session.transcriptPath, { examinedMtimeMs: session.mtimeMs, foreignOwner: true });
90595
- summary.foreignOwned.push(session.item.externalId);
90715
+ summary.foreignOwned.push(session.item.harnessSessionId);
90596
90716
  continue;
90597
90717
  }
90598
90718
  if (outcome === "previews-off") {
90599
90719
  memo2.set(session.transcriptPath, { examinedMtimeMs: session.mtimeMs, previewsOff: true });
90600
- summary.previewsOff.push(session.item.externalId);
90720
+ summary.previewsOff.push(session.item.harnessSessionId);
90601
90721
  continue;
90602
90722
  }
90603
90723
  memo2.set(session.transcriptPath, { examinedMtimeMs: session.mtimeMs, registeredJson });
90604
90724
  summary.registered += 1;
90605
90725
  } catch (error63) {
90606
90726
  summary.failed.push(
90607
- `${session.item.externalId}: ${error63 instanceof Error ? error63.message : String(error63)}`
90727
+ `${session.item.harnessSessionId}: ${error63 instanceof Error ? error63.message : String(error63)}`
90608
90728
  );
90609
90729
  }
90610
90730
  }
90611
90731
  return summary;
90612
90732
  }
90613
90733
 
90614
- // ../../apps/collector/src/sync.ts
90734
+ // ../../apps/syncservice/src/sync.ts
90615
90735
  var defaultPolicyDeps = {
90616
90736
  fetchPolicy: fetchCapturePolicy,
90617
90737
  load: loadCredentials,
@@ -90807,7 +90927,7 @@ async function runSyncPassInternal(config2, options, diagnostic) {
90807
90927
  for (const failure2 of codex.unreadable) log3(` codex rollout skipped, ${failure2}`);
90808
90928
  if (options.dryRun) {
90809
90929
  for (const s of items.slice(0, 10)) {
90810
- log3(` ${s.externalId} ${s.model ?? "model unmeasured"} ${s.title ?? "(untitled)"}`);
90930
+ log3(` ${s.harnessSessionId} ${s.model ?? "model unmeasured"} ${s.title ?? "(untitled)"}`);
90811
90931
  }
90812
90932
  if (items.length > 10) log3(` ... and ${items.length - 10} more`);
90813
90933
  log3("Dry run, nothing uploaded.");
@@ -90847,13 +90967,13 @@ async function runSyncPassInternal(config2, options, diagnostic) {
90847
90967
  items
90848
90968
  );
90849
90969
  const foreignKeys = new Set(
90850
- foreignOwned.map(({ source, externalId }) => JSON.stringify([source, externalId]))
90970
+ foreignOwned.map(({ harness, harnessSessionId }) => JSON.stringify([harness, harnessSessionId]))
90851
90971
  );
90852
90972
  const writable = collected.filter(
90853
- ({ item }) => !foreignKeys.has(JSON.stringify([item.source, item.externalId]))
90973
+ ({ item }) => !foreignKeys.has(JSON.stringify([item.harness, item.harnessSessionId]))
90854
90974
  );
90855
- for (const { source, externalId } of foreignOwned) {
90856
- log3(`Skipped ${source} session ${externalId}: already synced from another machine.`);
90975
+ for (const { harness, harnessSessionId } of foreignOwned) {
90976
+ log3(`Skipped ${harness} session ${harnessSessionId}: already synced from another machine.`);
90857
90977
  }
90858
90978
  Object.assign(diagnostic, { upserted, unchanged, outOfPolicy, deferred });
90859
90979
  log3(
@@ -90996,7 +91116,7 @@ function failedPassDiagnostic(error63) {
90996
91116
  return error63 instanceof Error ? failedPasses.get(error63) : void 0;
90997
91117
  }
90998
91118
 
90999
- // ../../apps/collector/src/versionSupport.ts
91119
+ // ../../apps/syncservice/src/versionSupport.ts
91000
91120
  var FETCH_TIMEOUT_MS = 3e3;
91001
91121
  var policyEnvelope = external_exports.object({
91002
91122
  data: external_exports.object({
@@ -91036,15 +91156,15 @@ function isUpdateAvailable(cliVersion2, latestVersion) {
91036
91156
  }
91037
91157
  function unsupportedVersionNotice(cliVersion2, oldestSupportedVersion) {
91038
91158
  if (!isUnsupportedVersion(cliVersion2, oldestSupportedVersion)) return null;
91039
- return `\u26A0 Powerplant CLI ${cliVersion2} is no longer supported (oldest supported: ${oldestSupportedVersion}). Update now: powerplant update (or npm install -g @usepowerplant/cli). Unsupported versions can stop working without further notice.`;
91159
+ return `! Powerplant CLI ${cliVersion2} is no longer supported (oldest supported: ${oldestSupportedVersion}). Update now: powerplant update (or npm install -g @usepowerplant/cli). Unsupported versions can stop working without further notice.`;
91040
91160
  }
91041
91161
 
91042
- // ../../apps/collector/src/watch.ts
91162
+ // ../../apps/syncservice/src/watch.ts
91043
91163
  import { existsSync as existsSync8, watch as fsWatch } from "node:fs";
91044
91164
  import os16 from "node:os";
91045
91165
  import path18 from "node:path";
91046
91166
 
91047
- // ../../apps/collector/src/selfRestart.ts
91167
+ // ../../apps/syncservice/src/selfRestart.ts
91048
91168
  import { statSync as statSync3 } from "node:fs";
91049
91169
  var ENTRY_CHECK_INTERVAL_MS = 5 * 6e4;
91050
91170
  function watchEntryForUpdate(entryPath2, onChanged, options = {}) {
@@ -91073,7 +91193,7 @@ function defaultStat(file2) {
91073
91193
  }
91074
91194
  }
91075
91195
 
91076
- // ../../apps/collector/src/watch.ts
91196
+ // ../../apps/syncservice/src/watch.ts
91077
91197
  var WATCH_DEBOUNCE_MS = 5e3;
91078
91198
  var WATCH_MAX_WAIT_MS = 3e4;
91079
91199
  var SAFETY_NET_INTERVAL_MS = 60 * 60 * 1e3;
@@ -91613,12 +91733,12 @@ function describeDelay(ms) {
91613
91733
  return seconds < 120 ? `${seconds}s` : `${Math.round(seconds / 60)} minutes`;
91614
91734
  }
91615
91735
 
91616
- // ../../apps/collector/src/localSessionFacts.ts
91736
+ // ../../apps/syncservice/src/localSessionFacts.ts
91617
91737
  import { existsSync as existsSync9, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
91618
91738
  import os17 from "node:os";
91619
91739
  import path20 from "node:path";
91620
91740
 
91621
- // ../../apps/collector/src/codexReviewFacts.ts
91741
+ // ../../apps/syncservice/src/codexReviewFacts.ts
91622
91742
  import { closeSync as closeSync6, lstatSync as lstatSync5, openSync as openSync6, readSync as readSync4, realpathSync as realpathSync3 } from "node:fs";
91623
91743
  import path19 from "node:path";
91624
91744
  var pointerSchema = external_exports.object({
@@ -91688,7 +91808,7 @@ function readPrefix(file2) {
91688
91808
  }
91689
91809
  }
91690
91810
 
91691
- // ../../apps/collector/src/localSessionFacts.ts
91811
+ // ../../apps/syncservice/src/localSessionFacts.ts
91692
91812
  var WORKING_FRESH_MS = 9e4;
91693
91813
  var STORES = [
91694
91814
  {
@@ -91749,6 +91869,7 @@ async function readLocalSessionFacts(sessions, onError2, home = os17.homedir(),
91749
91869
  if (file2 === null || !existsSync9(file2)) continue;
91750
91870
  const db = await openLocalDatabase(file2);
91751
91871
  try {
91872
+ db.prepare("pragma busy_timeout = 250").get();
91752
91873
  const columns = new Set(
91753
91874
  external_exports.array(external_exports.object({ name: external_exports.string() })).parse(db.prepare(`pragma table_info(${store.table})`).all()).map((column) => column.name)
91754
91875
  );
@@ -91817,7 +91938,129 @@ function localSessionKey(session) {
91817
91938
  return JSON.stringify([session.source, session.externalId]);
91818
91939
  }
91819
91940
 
91941
+ // src/hookPreferences.ts
91942
+ var preferencesSchema = external_exports.object({
91943
+ version: external_exports.literal(1),
91944
+ codexNotFiringDismissed: external_exports.boolean()
91945
+ });
91946
+ function hookPreferencesPath(appEnv, home) {
91947
+ return path21.join(collectorStateDir(home), `hook-preferences-${appEnv}.json`);
91948
+ }
91949
+ function readHookPreferences(appEnv, home) {
91950
+ const file2 = hookPreferencesPath(appEnv, home);
91951
+ try {
91952
+ return preferencesSchema.parse(JSON.parse(readFileSync11(file2, "utf8")));
91953
+ } catch (error63) {
91954
+ if (error63 instanceof Error && "code" in error63 && error63.code === "ENOENT") {
91955
+ return { version: 1, codexNotFiringDismissed: false };
91956
+ }
91957
+ throw new ExpectedCliError(`Cannot read hook preferences at ${file2}. Restore or remove that file, then retry.`, { cause: error63 });
91958
+ }
91959
+ }
91960
+ function readHookPreferencesForMenu(appEnv, home) {
91961
+ try {
91962
+ return { codexHookWarningDismissed: readHookPreferences(appEnv, home).codexNotFiringDismissed };
91963
+ } catch (error63) {
91964
+ if (!(error63 instanceof ExpectedCliError)) throw error63;
91965
+ return { hookPreferencesError: error63.message };
91966
+ }
91967
+ }
91968
+ function dismissCodexHookWarning(appEnv, home) {
91969
+ const preferences = readHookPreferences(appEnv, home);
91970
+ if (preferences.codexNotFiringDismissed) return;
91971
+ const file2 = hookPreferencesPath(appEnv, home);
91972
+ mkdirSync10(path21.dirname(file2), { recursive: true });
91973
+ const temporary = `${file2}.${process.pid}.tmp`;
91974
+ writeFileSync9(temporary, JSON.stringify({ ...preferences, codexNotFiringDismissed: true }, null, 2), { mode: 384 });
91975
+ renameSync5(temporary, file2);
91976
+ }
91977
+
91978
+ // src/mcpPreferences.ts
91979
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync12, renameSync as renameSync6, writeFileSync as writeFileSync10 } from "node:fs";
91980
+ import path22 from "node:path";
91981
+ var preferenceSchema = external_exports.object({
91982
+ optedIn: external_exports.boolean().optional(),
91983
+ dismissedWarning: mcpWarningSchema.optional()
91984
+ });
91985
+ var preferencesSchema2 = external_exports.object({
91986
+ version: external_exports.literal(1),
91987
+ clients: external_exports.object({
91988
+ claude: preferenceSchema.optional(),
91989
+ codex: preferenceSchema.optional(),
91990
+ cursor: preferenceSchema.optional()
91991
+ })
91992
+ });
91993
+ var emptyMcpPreferences = () => ({ version: 1, clients: {} });
91994
+ function mcpPreferencesPath(appEnv, home) {
91995
+ return path22.join(collectorStateDir(home), `mcp-preferences-${appEnv}.json`);
91996
+ }
91997
+ function readMcpPreferences(appEnv, home) {
91998
+ const file2 = mcpPreferencesPath(appEnv, home);
91999
+ try {
92000
+ return preferencesSchema2.parse(JSON.parse(readFileSync12(file2, "utf8")));
92001
+ } catch (error63) {
92002
+ if (error63 instanceof Error && "code" in error63 && error63.code === "ENOENT") return emptyMcpPreferences();
92003
+ throw new ExpectedCliError(`Cannot read MCP preferences at ${file2}. Restore or remove that file, then retry.`, { cause: error63 });
92004
+ }
92005
+ }
92006
+ function writeMcpPreferences(appEnv, preferences, home) {
92007
+ const file2 = mcpPreferencesPath(appEnv, home);
92008
+ mkdirSync11(path22.dirname(file2), { recursive: true });
92009
+ const temporary = `${file2}.${process.pid}.tmp`;
92010
+ writeFileSync10(temporary, JSON.stringify(preferencesSchema2.parse(preferences), null, 2), { mode: 384 });
92011
+ renameSync6(temporary, file2);
92012
+ }
92013
+ function recordMcpChoices(appEnv, offered, selected, home) {
92014
+ const preferences = readMcpPreferences(appEnv, home);
92015
+ for (const client of offered) {
92016
+ preferences.clients[client] = { optedIn: selected.includes(client) };
92017
+ }
92018
+ writeMcpPreferences(appEnv, preferences, home);
92019
+ }
92020
+ function recordMcpConnectChoices(appEnv, detected, requested, home) {
92021
+ const chosen = requested === void 0 ? detected : detected.filter((client) => requested.has(client));
92022
+ recordMcpChoices(appEnv, chosen, chosen, home);
92023
+ }
92024
+ function readMcpPreferencesForMenu(appEnv, home) {
92025
+ try {
92026
+ return { mcpPreferences: readMcpPreferences(appEnv, home) };
92027
+ } catch (error63) {
92028
+ if (!(error63 instanceof ExpectedCliError)) throw error63;
92029
+ return { mcpPreferencesError: error63.message };
92030
+ }
92031
+ }
92032
+ function dismissMcpWarning(appEnv, event, home) {
92033
+ const preferences = readMcpPreferences(appEnv, home);
92034
+ const previous = preferences.clients[event.client];
92035
+ if (previous?.dismissedWarning === event.warning) return false;
92036
+ preferences.clients[event.client] = { ...previous, dismissedWarning: event.warning };
92037
+ writeMcpPreferences(appEnv, preferences, home);
92038
+ return true;
92039
+ }
92040
+
92041
+ // src/menubarAnalytics.ts
92042
+ import { randomUUID as randomUUID3 } from "node:crypto";
92043
+ async function reportMenubarEvent(event, credentials, warn2, fetchImpl = fetch) {
92044
+ if (credentials === null) return false;
92045
+ const runId = randomUUID3();
92046
+ let status;
92047
+ try {
92048
+ const response = await fetchImpl(`${credentials.apiUrl}/api/collector/menubar-events`, {
92049
+ method: "POST",
92050
+ headers: { authorization: `Bearer ${credentials.token}`, "content-type": "application/json", ...cliVersionHeaders() },
92051
+ body: JSON.stringify(event),
92052
+ signal: AbortSignal.timeout(3e3)
92053
+ });
92054
+ if (response.ok) return true;
92055
+ status = response.status;
92056
+ } catch {
92057
+ }
92058
+ warn2(JSON.stringify({ level: "warn", runId, operation: "menubar-analytics", outcome: status === void 0 ? "unavailable" : "refused", ...status === void 0 ? {} : { status } }));
92059
+ return false;
92060
+ }
92061
+
91820
92062
  // src/clientFailure.ts
92063
+ import { constants } from "node:os";
91821
92064
  function clientFailure(error63) {
91822
92065
  if (error63 instanceof ExpectedCliError) {
91823
92066
  return { outcome: "failed", domain: "Powerplant", code: "EXPECTED_CLI_OUTCOME" };
@@ -91835,14 +92078,14 @@ function nativeFailureRecord(error63) {
91835
92078
 
91836
92079
  // src/desktopDiagnostics.ts
91837
92080
  import os19 from "node:os";
91838
- import path22 from "node:path";
92081
+ import path24 from "node:path";
91839
92082
 
91840
92083
  // src/memberSessions.ts
91841
92084
  import { execFileSync as execFileSync4 } from "node:child_process";
91842
92085
  import { existsSync as existsSync10 } from "node:fs";
91843
92086
  import { open as open2, readdir as readdir2 } from "node:fs/promises";
91844
92087
  import os18 from "node:os";
91845
- import path21 from "node:path";
92088
+ import path23 from "node:path";
91846
92089
  var memberSessionSchema = external_exports.object({
91847
92090
  id: external_exports.string().min(1),
91848
92091
  source: external_exports.string().min(1),
@@ -91959,10 +92202,10 @@ function detectClaudeDesktop(probe) {
91959
92202
  return detectDesktopScheme(["Claude.app"], "claude", probe);
91960
92203
  }
91961
92204
  function detectDesktopScheme(bundles, scheme, probe = { exists: existsSync10, readUrlSchemes: realReadUrlSchemes }) {
91962
- const roots = ["/Applications", path21.join(os18.homedir(), "Applications")];
92205
+ const roots = ["/Applications", path23.join(os18.homedir(), "Applications")];
91963
92206
  return roots.some(
91964
92207
  (root) => bundles.some((bundle) => {
91965
- const bundlePath = path21.join(root, bundle);
92208
+ const bundlePath = path23.join(root, bundle);
91966
92209
  return probe.exists(bundlePath) && probe.readUrlSchemes(bundlePath).includes(scheme);
91967
92210
  })
91968
92211
  );
@@ -91972,7 +92215,7 @@ function realReadUrlSchemes(bundlePath) {
91972
92215
  try {
91973
92216
  const json2 = execFileSync4(
91974
92217
  "plutil",
91975
- ["-extract", "CFBundleURLTypes", "json", "-o", "-", path21.join(bundlePath, "Contents", "Info.plist")],
92218
+ ["-extract", "CFBundleURLTypes", "json", "-o", "-", path23.join(bundlePath, "Contents", "Info.plist")],
91976
92219
  { stdio: ["ignore", "pipe", "ignore"] }
91977
92220
  ).toString();
91978
92221
  const parsed = urlSchemesSchema.safeParse(JSON.parse(json2));
@@ -91991,7 +92234,7 @@ var claudeDesktopSessionSchema = external_exports.object({
91991
92234
  * and still links: the flag must never cost the row its desktop link. */
91992
92235
  isArchived: external_exports.unknown().optional()
91993
92236
  });
91994
- async function readClaudeDesktopSessions(wanted, root = path21.join(os18.homedir(), "Library/Application Support/Claude/claude-code-sessions")) {
92237
+ async function readClaudeDesktopSessions(wanted, root = path23.join(os18.homedir(), "Library/Application Support/Claude/claude-code-sessions")) {
91995
92238
  const sessions = /* @__PURE__ */ new Map();
91996
92239
  const ambiguous = /* @__PURE__ */ new Set();
91997
92240
  if (wanted.size === 0) return sessions;
@@ -92002,7 +92245,7 @@ async function readClaudeDesktopSessions(wanted, root = path21.join(os18.homedir
92002
92245
  throw error63;
92003
92246
  });
92004
92247
  for (const entry of entries) {
92005
- const file2 = path21.join(directory, entry.name);
92248
+ const file2 = path23.join(directory, entry.name);
92006
92249
  if (entry.isDirectory() && depth < 2) {
92007
92250
  await visit3(file2, depth + 1);
92008
92251
  } else if (depth === 2 && entry.isFile() && /^local_.*\.json$/.test(entry.name)) {
@@ -92042,7 +92285,7 @@ function isMissingFile(error63) {
92042
92285
  }
92043
92286
 
92044
92287
  // src/desktopDiagnostics.ts
92045
- async function probeClaudeDesktopSessions(wanted, installed, reportFault, root = path22.join(os19.homedir(), "Library/Application Support/Claude/claude-code-sessions"), read = readClaudeDesktopSessions) {
92288
+ async function probeClaudeDesktopSessions(wanted, installed, reportFault, root = path24.join(os19.homedir(), "Library/Application Support/Claude/claude-code-sessions"), read = readClaudeDesktopSessions) {
92046
92289
  if (!installed || wanted.size === 0) {
92047
92290
  return { sessions: /* @__PURE__ */ new Map(), diagnostic: { outcome: "not-needed" } };
92048
92291
  }
@@ -92059,24 +92302,25 @@ async function probeClaudeDesktopSessions(wanted, installed, reportFault, root =
92059
92302
 
92060
92303
  // src/cli.ts
92061
92304
  import { spawn as spawn3 } from "node:child_process";
92062
- import { existsSync as existsSync14, mkdirSync as mkdirSync14, openSync as openSync9, realpathSync as realpathSync5, rmSync as rmSync7 } from "node:fs";
92063
- import path31 from "node:path";
92305
+ import { randomUUID as randomUUID4 } from "node:crypto";
92306
+ import { existsSync as existsSync14, mkdirSync as mkdirSync16, openSync as openSync9, realpathSync as realpathSync5, rmSync as rmSync7 } from "node:fs";
92307
+ import path33 from "node:path";
92064
92308
  import { parseArgs } from "node:util";
92065
92309
 
92066
92310
  // src/connect.ts
92067
92311
  import { execFileSync as execFileSync5, spawnSync } from "node:child_process";
92068
92312
  import {
92069
92313
  existsSync as existsSync11,
92070
- mkdirSync as mkdirSync10,
92314
+ mkdirSync as mkdirSync12,
92071
92315
  mkdtempSync,
92072
92316
  readdirSync as readdirSync5,
92073
- readFileSync as readFileSync11,
92317
+ readFileSync as readFileSync13,
92074
92318
  realpathSync as realpathSync4,
92075
92319
  statSync as statSync5,
92076
- writeFileSync as writeFileSync9
92320
+ writeFileSync as writeFileSync11
92077
92321
  } from "node:fs";
92078
92322
  import os20 from "node:os";
92079
- import path23 from "node:path";
92323
+ import path25 from "node:path";
92080
92324
  import { emitKeypressEvents } from "node:readline";
92081
92325
 
92082
92326
  // src/agentVersions.ts
@@ -92150,7 +92394,7 @@ function startTimeBudget(totalMs, now = Date.now) {
92150
92394
  return { remainingMs: () => Math.max(0, deadline - now()) };
92151
92395
  }
92152
92396
  function defaultApplicationsDirs(homeDir) {
92153
- return process.platform === "darwin" ? ["/Applications", path23.join(homeDir, "Applications")] : [];
92397
+ return process.platform === "darwin" ? ["/Applications", path25.join(homeDir, "Applications")] : [];
92154
92398
  }
92155
92399
  function detectClients(options = {}) {
92156
92400
  const homeDir = options.homeDir ?? os20.homedir();
@@ -92178,7 +92422,7 @@ function detectClients(options = {}) {
92178
92422
  clients.push({ client, bin, ...configDir !== void 0 && { configDir } });
92179
92423
  };
92180
92424
  for (const bin of whichAll("claude")) add("claude", bin);
92181
- const localClaude = path23.join(homeDir, ".local", "bin", "claude");
92425
+ const localClaude = path25.join(homeDir, ".local", "bin", "claude");
92182
92426
  if (existsSync11(localClaude)) add("claude", localClaude);
92183
92427
  for (const bin of desktopClaudeBinaries(homeDir)) add("claude", bin);
92184
92428
  const claudeBins = clients.filter((client) => client.client === "claude" && client.configDir === void 0).map((client) => client.bin);
@@ -92186,12 +92430,12 @@ function detectClients(options = {}) {
92186
92430
  for (const bin of claudeBins) add("claude", bin, configDir);
92187
92431
  }
92188
92432
  for (const bin of whichAll("codex")) add("codex", bin);
92189
- const localCodex = path23.join(homeDir, ".local", "bin", "codex");
92433
+ const localCodex = path25.join(homeDir, ".local", "bin", "codex");
92190
92434
  if (existsSync11(localCodex)) add("codex", localCodex);
92191
92435
  for (const bin of codexBundleBinaries(applicationsDirs, bundleSeams)) add("codex", bin);
92192
- const cursorDir = path23.join(homeDir, ".cursor");
92193
- if (existsSync11(cursorDir) || cursorAppInstalled(applicationsDirs, bundleSeams)) {
92194
- clients.push({ client: "cursor", bin: path23.join(cursorDir, "mcp.json") });
92436
+ const cursorDir = path25.join(homeDir, ".cursor");
92437
+ if (!options.requireCursorApp && existsSync11(cursorDir) || cursorAppInstalled(applicationsDirs, bundleSeams)) {
92438
+ clients.push({ client: "cursor", bin: path25.join(cursorDir, "mcp.json") });
92195
92439
  }
92196
92440
  return clients;
92197
92441
  }
@@ -92199,7 +92443,7 @@ function claudeConfigHomes(homeDir, env) {
92199
92443
  const homes = [];
92200
92444
  const seen = /* @__PURE__ */ new Set();
92201
92445
  try {
92202
- seen.add(realpathSync4(path23.join(homeDir, ".claude")));
92446
+ seen.add(realpathSync4(path25.join(homeDir, ".claude")));
92203
92447
  } catch {
92204
92448
  }
92205
92449
  const add = (configDir) => {
@@ -92211,7 +92455,7 @@ function claudeConfigHomes(homeDir, env) {
92211
92455
  }
92212
92456
  if (seen.has(real)) return;
92213
92457
  seen.add(real);
92214
- homes.push(path23.resolve(configDir));
92458
+ homes.push(path25.resolve(configDir));
92215
92459
  };
92216
92460
  let entries = [];
92217
92461
  try {
@@ -92219,8 +92463,8 @@ function claudeConfigHomes(homeDir, env) {
92219
92463
  } catch {
92220
92464
  }
92221
92465
  for (const entry of entries.sort()) {
92222
- if (entry.startsWith(".claude-") && existsSync11(path23.join(homeDir, entry, ".claude.json"))) {
92223
- add(path23.join(homeDir, entry));
92466
+ if (entry.startsWith(".claude-") && existsSync11(path25.join(homeDir, entry, ".claude.json"))) {
92467
+ add(path25.join(homeDir, entry));
92224
92468
  }
92225
92469
  }
92226
92470
  if (env.CLAUDE_CONFIG_DIR) add(env.CLAUDE_CONFIG_DIR);
@@ -92248,7 +92492,7 @@ function appBundles(applicationsDirs, namePrefixes) {
92248
92492
  for (const entry of entries) {
92249
92493
  if (!entry.endsWith(".app")) continue;
92250
92494
  if (!namePrefixes.some((prefix) => entry.startsWith(prefix))) continue;
92251
- bundles.push(path23.join(dir, entry));
92495
+ bundles.push(path25.join(dir, entry));
92252
92496
  }
92253
92497
  }
92254
92498
  return bundles;
@@ -92268,7 +92512,7 @@ function codexBundleBinaries(applicationsDirs, seams) {
92268
92512
  const infoTimeoutMs = budgetedTimeout(BUNDLE_INFO_TIMEOUT_MS, appDir, seams);
92269
92513
  if (infoTimeoutMs === null) continue;
92270
92514
  if (seams.readBundleInfo(appDir, infoTimeoutMs)?.bundleId !== CODEX_BUNDLE_ID) continue;
92271
- const bin = path23.join(appDir, "Contents", "Resources", "codex");
92515
+ const bin = path25.join(appDir, "Contents", "Resources", "codex");
92272
92516
  if (!isExecutableFile(bin)) continue;
92273
92517
  if (!signedByTeam(bin, OPENAI_TEAM_ID, "OpenAI", appDir, seams)) continue;
92274
92518
  found.push(bin);
@@ -92280,7 +92524,7 @@ function trustedCursorBundle(appDir, seams) {
92280
92524
  if (infoTimeoutMs === null) return null;
92281
92525
  const info = seams.readBundleInfo(appDir, infoTimeoutMs);
92282
92526
  if (info?.executable === void 0) return null;
92283
- const bin = path23.join(appDir, "Contents", "MacOS", info.executable);
92527
+ const bin = path25.join(appDir, "Contents", "MacOS", info.executable);
92284
92528
  if (!isExecutableFile(bin)) return null;
92285
92529
  if (!signedByTeam(bin, CURSOR_TEAM_ID, "Cursor", appDir, seams)) return null;
92286
92530
  return info;
@@ -92317,7 +92561,7 @@ var bundleInfoSchema = external_exports.object({
92317
92561
  function realReadBundleInfo(appDir, timeoutMs) {
92318
92562
  const result = spawnSync(
92319
92563
  "plutil",
92320
- ["-convert", "json", "-o", "-", path23.join(appDir, "Contents", "Info.plist")],
92564
+ ["-convert", "json", "-o", "-", path25.join(appDir, "Contents", "Info.plist")],
92321
92565
  { encoding: "utf8", timeout: timeoutMs }
92322
92566
  );
92323
92567
  if (result.status !== 0) return null;
@@ -92339,14 +92583,14 @@ function realVerifySignature(binPath, teamId, timeoutMs) {
92339
92583
  }).status === 0;
92340
92584
  }
92341
92585
  function desktopClaudeBinaries(homeDir) {
92342
- const root = path23.join(homeDir, "Library", "Application Support", "Claude", "claude-code");
92586
+ const root = path25.join(homeDir, "Library", "Application Support", "Claude", "claude-code");
92343
92587
  let versions;
92344
92588
  try {
92345
92589
  versions = readdirSync5(root);
92346
92590
  } catch {
92347
92591
  return [];
92348
92592
  }
92349
- return versions.map((version2) => path23.join(root, version2, "claude.app", "Contents", "MacOS", "claude")).filter((bin) => existsSync11(bin));
92593
+ return versions.map((version2) => path25.join(root, version2, "claude.app", "Contents", "MacOS", "claude")).filter((bin) => existsSync11(bin));
92350
92594
  }
92351
92595
  function defaultWhichAll(name) {
92352
92596
  try {
@@ -92367,7 +92611,7 @@ function runConnect(clients, deps) {
92367
92611
  failed: 0
92368
92612
  };
92369
92613
  if (clients.length === 0) {
92370
- deps.log("No coding agents found (looked for `claude`, `codex`, and Cursor), nothing to connect.");
92614
+ deps.log("No coding agents found (looked for claude, codex, and Cursor)");
92371
92615
  return outcome;
92372
92616
  }
92373
92617
  for (const [agent, candidates] of agents) {
@@ -92417,8 +92661,8 @@ function connectTarget(agent, candidates, all, deps) {
92417
92661
  }
92418
92662
  if (last.state !== "failed") return last;
92419
92663
  if (index < candidates.length - 1) {
92420
- deps.log(`${name} could not be used, ${last.detail}`);
92421
- deps.log(`\u2192 trying another ${AGENT_DISPLAY_NAMES[agent]} installation\u2026`);
92664
+ deps.log(`! ${name}: could not be used, ${last.detail}`);
92665
+ deps.log(`\u2192 ${AGENT_DISPLAY_NAMES[agent]}: trying another installation\u2026`);
92422
92666
  } else {
92423
92667
  deps.log(`\u2717 ${name}: ${last.detail}`);
92424
92668
  }
@@ -92468,22 +92712,25 @@ async function pickAgents(clients, deps) {
92468
92712
  const kept = new Set(selected);
92469
92713
  const skippedNames = products.filter((product) => !kept.has(product)).map((product) => AGENT_DISPLAY_NAMES[product]);
92470
92714
  if (skippedNames.length > 0) deps.log(`Skipping ${skippedNames.join(" and ")}.`);
92471
- return clients.filter((client) => kept.has(client.client));
92715
+ const chosen = clients.filter((client) => kept.has(client.client));
92716
+ deps.onChoice?.(chosen);
92717
+ return chosen;
92472
92718
  }
92473
92719
  function realCheckboxPrompt(question, choices, seams = {}) {
92474
92720
  const input2 = seams.input ?? process.stdin;
92475
92721
  const output2 = seams.output ?? process.stdout;
92722
+ const indent = seams.indent ?? "";
92476
92723
  const raiseInterrupt = seams.raiseInterrupt ?? (() => process.kill(process.pid, "SIGINT"));
92477
92724
  const selected = new Set(choices.map((choice) => choice.value));
92478
92725
  let active = 0;
92479
92726
  let settled = false;
92480
92727
  const wasRaw = input2.isRaw === true;
92481
92728
  const render = () => [
92482
- `? ${question}`,
92729
+ `${indent}? ${question}`,
92483
92730
  ...choices.map(
92484
- (choice, index) => `${index === active ? "\u276F" : " "} [${selected.has(choice.value) ? "x" : " "}] ${choice.label}`
92731
+ (choice, index) => `${indent}${index === active ? "\u276F" : " "} [${selected.has(choice.value) ? "x" : " "}] ${choice.label}`
92485
92732
  ),
92486
- " \u2191/\u2193 move \xB7 space toggle \xB7 enter confirm"
92733
+ `${indent} \u2191/\u2193 move \xB7 space toggle \xB7 enter confirm`
92487
92734
  ].join("\n");
92488
92735
  const redraw = () => {
92489
92736
  output2.write(`\r\x1B[${choices.length + 1}A\x1B[J${render()}`);
@@ -92577,26 +92824,22 @@ function connectClaude(client, name, deps) {
92577
92824
  const { missing, registeredUrl } = probe;
92578
92825
  if (missing || registeredUrl !== void 0 && registeredUrl !== deps.mcpUrl) {
92579
92826
  if (!missing) {
92580
- deps.log(`${name}: registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
92827
+ deps.log(`${name} was registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
92581
92828
  deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
92582
92829
  }
92583
92830
  const add = deps.run(bin, claudeAddArgs(deps), env);
92584
92831
  if (add.status !== 0) {
92585
92832
  return failed(`registering the Powerplant MCP failed, ${describeFailure(add)}`);
92586
92833
  }
92587
- deps.log(`${name}: Powerplant MCP registered (user scope).`);
92588
92834
  } else if (probe.authenticated) {
92589
- deps.log(`\u2713 ${name} MCP already connected`);
92835
+ deps.log(`\u2713 ${name}: MCP already connected`);
92590
92836
  return { state: "connected", unchanged: true };
92591
92837
  } else if (deps.officialClients?.["claude-code"]) {
92592
- deps.log(`${name}: re-registering with the pre-registered client before sign-in.`);
92593
92838
  deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
92594
92839
  const add = deps.run(bin, claudeAddArgs(deps), env);
92595
92840
  if (add.status !== 0) {
92596
92841
  return failed(`registering the Powerplant MCP failed, ${describeFailure(add)}`);
92597
92842
  }
92598
- } else {
92599
- deps.log(`${name}: Powerplant MCP already registered.`);
92600
92843
  }
92601
92844
  return login(bin, name, ["mcp", "login", deps.serverName], deps, env);
92602
92845
  }
@@ -92815,9 +93058,7 @@ function healOrphanCodexOauthTable(name, deps) {
92815
93058
  const { content, changed } = unpatchCodexConfigToml(existing, deps.serverName);
92816
93059
  if (!changed) return;
92817
93060
  deps.writeTextFile(deps.codexConfigPath, content);
92818
- deps.log(
92819
- `${name}: removed leftover sign-in settings from an interrupted setup, codex can read its configuration again.`
92820
- );
93061
+ deps.log(`Removed leftover ${name} sign-in settings from an interrupted setup.`);
92821
93062
  }
92822
93063
  function connectCodex(bin, name, deps) {
92823
93064
  healOrphanCodexOauthTable(name, deps);
@@ -92829,7 +93070,7 @@ function connectCodex(bin, name, deps) {
92829
93070
  const wrongUrl = registeredUrl !== void 0 && registeredUrl !== deps.mcpUrl;
92830
93071
  const alreadyConnected = !missing && !wrongUrl && probe.authenticated;
92831
93072
  if (missing || wrongUrl) {
92832
- if (wrongUrl) deps.log(`${name}: registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
93073
+ if (wrongUrl) deps.log(`${name} was registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
92833
93074
  if (codexAddLogsIn(bin, deps)) {
92834
93075
  ensureCodexCallbackPort(name, deps);
92835
93076
  const outcome = login(bin, name, codexAddArgs(deps, { withOfficialClientId: true }), deps);
@@ -92840,27 +93081,21 @@ function connectCodex(bin, name, deps) {
92840
93081
  if (add.status !== 0) {
92841
93082
  return failed(`registering the Powerplant MCP failed, ${describeFailure(add)}`);
92842
93083
  }
92843
- deps.log(`${name}: Powerplant MCP registered.`);
92844
93084
  } else if (alreadyConnected) {
92845
- deps.log(`\u2713 ${name} MCP already connected`);
92846
- } else {
92847
- deps.log(`${name}: Powerplant MCP already registered.`);
93085
+ deps.log(`\u2713 ${name}: MCP already connected`);
92848
93086
  }
92849
93087
  ensureCodexOfficialClient(name, deps);
92850
93088
  if (alreadyConnected) return { state: "connected", unchanged: true };
92851
93089
  return login(bin, name, ["mcp", "login", deps.serverName], deps);
92852
93090
  }
92853
- function applyCodexConfigPatch(name, deps, patch, successLine) {
93091
+ function applyCodexConfigPatch(name, deps, patch) {
92854
93092
  if (patch.conflict !== void 0) {
92855
93093
  deps.log(
92856
- `${name}: ${patch.conflict}, sign-in may fail until the port conflict is resolved; then re-run ${deps.connectCommand}.`
93094
+ `! ${name}: ${patch.conflict}, sign-in may fail until the port conflict is resolved, then re-run ${deps.connectCommand}`
92857
93095
  );
92858
93096
  return;
92859
93097
  }
92860
- if (patch.changed) {
92861
- deps.writeTextFile(deps.codexConfigPath, patch.content);
92862
- deps.log(`${name}: ${successLine}`);
92863
- }
93098
+ if (patch.changed) deps.writeTextFile(deps.codexConfigPath, patch.content);
92864
93099
  }
92865
93100
  function ensureCodexCallbackPort(name, deps) {
92866
93101
  const official = deps.officialClients?.codex;
@@ -92868,8 +93103,7 @@ function ensureCodexCallbackPort(name, deps) {
92868
93103
  applyCodexConfigPatch(
92869
93104
  name,
92870
93105
  deps,
92871
- patchCodexCallbackPort(deps.readTextFile(deps.codexConfigPath), official.callbackPort),
92872
- "OAuth callback port pinned in config.toml."
93106
+ patchCodexCallbackPort(deps.readTextFile(deps.codexConfigPath), official.callbackPort)
92873
93107
  );
92874
93108
  }
92875
93109
  function ensureCodexOfficialClient(name, deps) {
@@ -92883,8 +93117,7 @@ function ensureCodexOfficialClient(name, deps) {
92883
93117
  deps.serverName,
92884
93118
  official.clientId,
92885
93119
  official.callbackPort
92886
- ),
92887
- "pre-registered Powerplant client configured in config.toml."
93120
+ )
92888
93121
  );
92889
93122
  }
92890
93123
  function connectCursor(mcpJsonPath, name, deps) {
@@ -92901,24 +93134,23 @@ function connectCursor(mcpJsonPath, name, deps) {
92901
93134
  );
92902
93135
  }
92903
93136
  if (patch.changed) deps.writeTextFile(mcpJsonPath, patch.content);
92904
- const configured = patch.changed ? "configured" : "already configured";
92905
93137
  if (deps.openUrl(cursorInstallDeeplink(deps.serverName, patch.entry))) {
92906
- deps.log(`\u2192 ${name} ${configured}, approve inside Cursor when it asks.`);
93138
+ deps.log(`\u2192 ${name}: approve inside Cursor when it asks`);
92907
93139
  return { state: "configured", unchanged: !patch.changed };
92908
93140
  }
92909
93141
  deps.log(
92910
- `\u2192 ${name} ${configured}, could not open Cursor; in Cursor's MCP settings, enable the ${deps.serverName} server and sign in.`
93142
+ `! ${name}: could not open Cursor, enable the ${deps.serverName} server in Cursor's MCP settings and sign in`
92911
93143
  );
92912
93144
  return { state: "pending", unchanged: false };
92913
93145
  }
92914
93146
  function login(bin, name, args, deps, env) {
92915
- deps.log(`\u2192 ${name} approve in your browser\u2026`);
93147
+ deps.log(`\u2192 ${name}: approve in your browser\u2026`);
92916
93148
  const status = deps.runInteractive(bin, args, env);
92917
93149
  if (status === 0) {
92918
- deps.log(`\u2713 ${name} MCP connected`);
93150
+ deps.log(`\u2713 ${name}: MCP connected`);
92919
93151
  return { state: "connected", unchanged: false };
92920
93152
  }
92921
- deps.log(`\u2192 ${name} MCP sign-in not completed, finish later with: ${deps.connectCommand}`);
93153
+ deps.log(`! ${name}: sign-in not completed`);
92922
93154
  return { state: "pending", unchanged: false };
92923
93155
  }
92924
93156
  function runDisconnect(clients, deps) {
@@ -92939,7 +93171,9 @@ function runDisconnect(clients, deps) {
92939
93171
  const results = [...groupByConnectionTarget(candidates).values()].map(
92940
93172
  (targetCandidates) => disconnectTarget(agent, targetCandidates, deps)
92941
93173
  );
92942
- outcome[aggregateDisconnectTargets(results)] += 1;
93174
+ const state = aggregateDisconnectTargets(results);
93175
+ outcome[state] += 1;
93176
+ if (state !== "failed") deps.onDisconnected?.(agent);
92943
93177
  }
92944
93178
  return outcome;
92945
93179
  }
@@ -92959,7 +93193,7 @@ function disconnectTarget(agent, candidates, deps) {
92959
93193
  }
92960
93194
  if (last !== "failed") return last;
92961
93195
  if (index < candidates.length - 1) {
92962
- deps.log(`\u2192 trying another ${AGENT_DISPLAY_NAMES[agent]} installation\u2026`);
93196
+ deps.log(`\u2192 ${AGENT_DISPLAY_NAMES[agent]}: trying another installation\u2026`);
92963
93197
  }
92964
93198
  }
92965
93199
  return last;
@@ -93045,11 +93279,11 @@ function anyClientStillConnected(clients, deps) {
93045
93279
  });
93046
93280
  }
93047
93281
  function describeBinary(bin) {
93048
- return `${path23.basename(bin)} (${bin.replace(os20.homedir(), "~")})`;
93282
+ return `${path25.basename(bin)} (${bin.replace(os20.homedir(), "~")})`;
93049
93283
  }
93050
93284
  function describeClaudeTarget(client) {
93051
93285
  if (client.configDir === void 0) return describeBinary(client.bin);
93052
- return `${path23.basename(client.bin)} (${client.configDir.replace(os20.homedir(), "~")})`;
93286
+ return `${path25.basename(client.bin)} (${client.configDir.replace(os20.homedir(), "~")})`;
93053
93287
  }
93054
93288
  var FAILURE_DETAIL_MAX_CHARS = 200;
93055
93289
  function describeFailure(result) {
@@ -93062,7 +93296,7 @@ function describeFailure(result) {
93062
93296
  }
93063
93297
  var neutralDirMemo;
93064
93298
  function neutralWorkdir() {
93065
- neutralDirMemo ??= mkdtempSync(path23.join(os20.tmpdir(), "powerplant-connect-"));
93299
+ neutralDirMemo ??= mkdtempSync(path25.join(os20.tmpdir(), "powerplant-connect-"));
93066
93300
  return neutralDirMemo;
93067
93301
  }
93068
93302
  async function fetchOfficialClients(apiUrl, log3) {
@@ -93092,25 +93326,25 @@ async function fetchOfficialClients(apiUrl, log3) {
93092
93326
  }
93093
93327
  function realReadTextFile(filePath) {
93094
93328
  try {
93095
- return readFileSync11(filePath, "utf8");
93329
+ return readFileSync13(filePath, "utf8");
93096
93330
  } catch {
93097
93331
  return null;
93098
93332
  }
93099
93333
  }
93100
93334
  function realReadTextFileStrict(filePath) {
93101
93335
  try {
93102
- return readFileSync11(filePath, "utf8");
93336
+ return readFileSync13(filePath, "utf8");
93103
93337
  } catch (error63) {
93104
93338
  if (error63 instanceof Error && error63.code === "ENOENT") return null;
93105
93339
  throw error63;
93106
93340
  }
93107
93341
  }
93108
93342
  function realWriteTextFile(filePath, content) {
93109
- mkdirSync10(path23.dirname(filePath), { recursive: true });
93110
- writeFileSync9(filePath, content);
93343
+ mkdirSync12(path25.dirname(filePath), { recursive: true });
93344
+ writeFileSync11(filePath, content);
93111
93345
  }
93112
93346
  function codexConfigPath(homeDir = os20.homedir()) {
93113
- return path23.join(process.env.CODEX_HOME ?? path23.join(homeDir, ".codex"), "config.toml");
93347
+ return path25.join(process.env.CODEX_HOME ?? path25.join(homeDir, ".codex"), "config.toml");
93114
93348
  }
93115
93349
  function realOpenUrl(url2) {
93116
93350
  const bin = process.platform === "darwin" ? "open" : process.platform === "linux" ? "xdg-open" : null;
@@ -93171,8 +93405,8 @@ function realRunInteractive(bin, args, env) {
93171
93405
 
93172
93406
  // src/connections.ts
93173
93407
  import { execFileSync as execFileSync6, spawnSync as spawnSync2 } from "node:child_process";
93174
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "node:fs";
93175
- import path24 from "node:path";
93408
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync12 } from "node:fs";
93409
+ import path26 from "node:path";
93176
93410
  function probeConnections(clients, deps) {
93177
93411
  const reports = [];
93178
93412
  for (const kind of ["claude", "codex", "cursor"]) {
@@ -93216,7 +93450,7 @@ function aggregateClaudeTargets(targets) {
93216
93450
  if (targets.length === 1 || worst.report.state === "signed-in") return worst.report;
93217
93451
  return {
93218
93452
  ...worst.report,
93219
- target: worst.configDir === void 0 ? "default profile" : path24.basename(worst.configDir)
93453
+ target: worst.configDir === void 0 ? "default profile" : path26.basename(worst.configDir)
93220
93454
  };
93221
93455
  }
93222
93456
  function probeClient(client, deps) {
@@ -93295,12 +93529,12 @@ var detectedClientsSchema = external_exports.object({
93295
93529
  )
93296
93530
  });
93297
93531
  function detectedClientsPath(homeDir) {
93298
- return path24.join(collectorStateDir(homeDir), "detected-clients.json");
93532
+ return path26.join(collectorStateDir(homeDir), "detected-clients.json");
93299
93533
  }
93300
93534
  function saveDetectedClients(clients, pathValue, homeDir) {
93301
93535
  try {
93302
93536
  const file2 = detectedClientsPath(homeDir);
93303
- mkdirSync11(path24.dirname(file2), { recursive: true });
93537
+ mkdirSync13(path26.dirname(file2), { recursive: true });
93304
93538
  const record2 = {
93305
93539
  detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
93306
93540
  path: pathValue,
@@ -93310,7 +93544,7 @@ function saveDetectedClients(clients, pathValue, homeDir) {
93310
93544
  ...configDir !== void 0 && { configDir }
93311
93545
  }))
93312
93546
  };
93313
- writeFileSync10(file2, JSON.stringify(record2, null, 2));
93547
+ writeFileSync12(file2, JSON.stringify(record2, null, 2));
93314
93548
  } catch {
93315
93549
  }
93316
93550
  }
@@ -93332,7 +93566,7 @@ function mergeDetectedClients(detected, saved, exists) {
93332
93566
  const known = new Set(detected.map(key));
93333
93567
  const revived = saved.clients.filter((client) => {
93334
93568
  const clientKey = key(client);
93335
- if (known.has(clientKey) || client.bin.includes(".app/") || !exists(client.bin) || client.configDir !== void 0 && !exists(client.configDir)) {
93569
+ if (known.has(clientKey) || client.client === "cursor" || client.bin.includes(".app/") || !exists(client.bin) || client.configDir !== void 0 && !exists(client.configDir)) {
93336
93570
  return false;
93337
93571
  }
93338
93572
  known.add(clientKey);
@@ -93387,7 +93621,7 @@ function whichAllWith(pathValue) {
93387
93621
  import { closeSync as closeSync7, fstatSync, openSync as openSync7, readSync as readSync5 } from "node:fs";
93388
93622
 
93389
93623
  // src/update.ts
93390
- import path26 from "node:path";
93624
+ import path28 from "node:path";
93391
93625
 
93392
93626
  // src/duration.ts
93393
93627
  function duration3(ms) {
@@ -93405,11 +93639,11 @@ function ago(ms) {
93405
93639
  }
93406
93640
 
93407
93641
  // src/installOwner.ts
93408
- import { accessSync, constants as constants2, readFileSync as readFileSync12 } from "node:fs";
93409
- import path25 from "node:path";
93642
+ import { accessSync, constants as constants2, readFileSync as readFileSync14 } from "node:fs";
93643
+ import path27 from "node:path";
93410
93644
 
93411
93645
  // src/version.ts
93412
- var CLI_VERSION = true ? "0.4.13" : "0.0.0-checkout";
93646
+ var CLI_VERSION = true ? "0.4.15" : "0.0.0-checkout";
93413
93647
  var CLI_RELEASE_BUILD = true ? true : false;
93414
93648
  var CLI_PACKAGE_NAME = "@usepowerplant/cli";
93415
93649
 
@@ -93433,13 +93667,13 @@ function inspectInstall(entryPath2, env) {
93433
93667
  inPlace: { ok: false, reason: `the install at ${packageDir} isn't a layout this CLI recognises` }
93434
93668
  };
93435
93669
  }
93436
- const modulesDir = path25.dirname(path25.dirname(packageDir));
93437
- const prefix = manager === "npm" ? path25.dirname(path25.dirname(modulesDir)) : null;
93670
+ const modulesDir = path27.dirname(path27.dirname(packageDir));
93671
+ const prefix = manager === "npm" ? path27.dirname(path27.dirname(modulesDir)) : null;
93438
93672
  const group = /^(.*\/global\/v11\/[^/]+)\/node_modules\//.exec(packageDir)?.[1];
93439
93673
  if (manager === "pnpm" && group !== void 0) {
93440
93674
  let dependencies = [];
93441
93675
  try {
93442
- const raw = env.readTextFile?.(path25.join(group, "package.json"));
93676
+ const raw = env.readTextFile?.(path27.join(group, "package.json"));
93443
93677
  const manifest = external_exports.object({ dependencies: external_exports.record(external_exports.string(), external_exports.string()) }).parse(JSON.parse(raw ?? "null"));
93444
93678
  dependencies = Object.keys(manifest.dependencies);
93445
93679
  } catch {
@@ -93466,7 +93700,7 @@ function detectManager(packageDir, pnpmHome) {
93466
93700
  return null;
93467
93701
  }
93468
93702
  function linkedEntryPath(realEntryPath, invokedEntryPath) {
93469
- if (invokedEntryPath !== void 0 && /\/global\/v11\/[^/]+\/node_modules\//.test(invokedEntryPath) && invokedEntryPath.endsWith(`${PACKAGE_SEGMENT}dist/cli.js`)) return path25.normalize(invokedEntryPath);
93703
+ if (invokedEntryPath !== void 0 && /\/global\/v11\/[^/]+\/node_modules\//.test(invokedEntryPath) && invokedEntryPath.endsWith(`${PACKAGE_SEGMENT}dist/cli.js`)) return path27.normalize(invokedEntryPath);
93470
93704
  const store = realEntryPath.lastIndexOf("/.pnpm/");
93471
93705
  if (store === -1) return realEntryPath;
93472
93706
  const at = realEntryPath.indexOf(PACKAGE_SEGMENT, store);
@@ -93493,7 +93727,7 @@ function manualUpdateCommand(manager, version2, prefix = null, channel3 = "lates
93493
93727
  return [bin, ...args].join(" ");
93494
93728
  }
93495
93729
  function installedVersion(packageDir, readTextFile) {
93496
- const raw = readTextFile(path25.join(packageDir, "package.json"));
93730
+ const raw = readTextFile(path27.join(packageDir, "package.json"));
93497
93731
  if (raw === null) return null;
93498
93732
  try {
93499
93733
  const parsed = JSON.parse(raw);
@@ -93510,7 +93744,7 @@ function realInspectEnvironment() {
93510
93744
  pnpmHome: process.env.PNPM_HOME,
93511
93745
  readTextFile: (file2) => {
93512
93746
  try {
93513
- return readFileSync12(file2, "utf8");
93747
+ return readFileSync14(file2, "utf8");
93514
93748
  } catch (error63) {
93515
93749
  if (error63 instanceof Error && "code" in error63 && error63.code === "ENOENT") return null;
93516
93750
  throw error63;
@@ -93559,10 +93793,10 @@ function releaseNotServed(managerOutput) {
93559
93793
  return /\bETARGET\b|\bnotarget\b|ERR_PNPM_NO_MATCHING_VERSION/.test(managerOutput);
93560
93794
  }
93561
93795
  function updateProgressPath(homeDir) {
93562
- return path26.join(collectorStateDir(homeDir), "cli-update.json");
93796
+ return path28.join(collectorStateDir(homeDir), "cli-update.json");
93563
93797
  }
93564
93798
  function updateLogPath(homeDir) {
93565
- return path26.join(collectorStateDir(homeDir), "cli-update.log");
93799
+ return path28.join(collectorStateDir(homeDir), "cli-update.log");
93566
93800
  }
93567
93801
  function readUpdateProgress(readTextFile, file2 = updateProgressPath()) {
93568
93802
  const raw = readTextFile(file2);
@@ -93725,34 +93959,33 @@ function automaticUpdatesChoice(control) {
93725
93959
  return control.autoUpdate ? "on" : "off";
93726
93960
  }
93727
93961
  async function offerAutomaticUpdates(deps, options) {
93728
- const { log: log3, indent } = options;
93962
+ const { output: output2 } = options;
93729
93963
  if (deps.readControl().autoUpdate !== void 0) return "already-chosen";
93730
- const offCommand = "powerplant update --automatic off";
93731
93964
  if (!options.promptAllowed) {
93732
93965
  deps.set(true);
93733
- log3(`${indent}\u2713 Automatic updates on (the default), turn off any time with \`${offCommand}\``);
93966
+ output2.log("\u2713 Automatic updates on");
93734
93967
  return "on";
93735
93968
  }
93736
93969
  for (; ; ) {
93737
93970
  const answer = await deps.promptLine(
93738
- `${indent}Keep the Powerplant CLI up to date automatically? (recommended) [Y/n] `
93971
+ `${output2.indent}Keep the Powerplant CLI up to date automatically? (recommended) [Y/n] `
93739
93972
  );
93740
93973
  if (answer === null) {
93741
- log3(`${indent}Automatic updates left off, turn on with \`powerplant update --automatic on\``);
93974
+ output2.log(`Automatic updates left off, turn on with \`powerplant update --automatic on\``);
93742
93975
  return "left-unchosen";
93743
93976
  }
93744
93977
  const normalized = answer.trim().toLowerCase();
93745
93978
  if (normalized === "" || normalized === "y" || normalized === "yes") {
93746
93979
  deps.set(true);
93747
- log3(`${indent}\u2713 Automatic updates on, turn off any time with \`${offCommand}\``);
93980
+ output2.log("\u2713 Automatic updates on");
93748
93981
  return "on";
93749
93982
  }
93750
93983
  if (normalized === "n" || normalized === "no") {
93751
93984
  deps.set(false);
93752
- log3(`${indent}Automatic updates off, turn on with \`powerplant update --automatic on\``);
93985
+ output2.log(`Automatic updates off, turn on with \`powerplant update --automatic on\``);
93753
93986
  return "off";
93754
93987
  }
93755
- log3(`${indent}Please answer y or n.`);
93988
+ output2.log("Please answer y or n.");
93756
93989
  }
93757
93990
  }
93758
93991
  function parseAutomaticFlag(value) {
@@ -93792,13 +94025,13 @@ function redactedLogTail(raw) {
93792
94025
  while (lines.length > 0 && lines[lines.length - 1]?.trim() === "") lines.pop();
93793
94026
  return lines.slice(-DOCTOR_LOG_TAIL_LINES);
93794
94027
  }
93795
- function readDoctorLogTail(path32) {
94028
+ function readDoctorLogTail(path34) {
93796
94029
  let fd;
93797
94030
  try {
93798
- fd = openSync7(path32, "r");
94031
+ fd = openSync7(path34, "r");
93799
94032
  } catch (error63) {
93800
- if (error63.code === "ENOENT") return { path: path32, lines: null };
93801
- return { path: path32, lines: null, readError: error63 instanceof Error ? error63.message : String(error63) };
94033
+ if (error63.code === "ENOENT") return { path: path34, lines: null };
94034
+ return { path: path34, lines: null, readError: error63 instanceof Error ? error63.message : String(error63) };
93802
94035
  }
93803
94036
  try {
93804
94037
  const size = fstatSync(fd).size;
@@ -93807,9 +94040,9 @@ function readDoctorLogTail(path32) {
93807
94040
  readSync5(fd, buffer, 0, buffer.length, offset);
93808
94041
  let text = buffer.toString("utf8");
93809
94042
  if (offset > 0) text = text.slice(text.indexOf("\n") + 1);
93810
- return { path: path32, lines: redactedLogTail(text) };
94043
+ return { path: path34, lines: redactedLogTail(text) };
93811
94044
  } catch (error63) {
93812
- return { path: path32, lines: null, readError: error63 instanceof Error ? error63.message : String(error63) };
94045
+ return { path: path34, lines: null, readError: error63 instanceof Error ? error63.message : String(error63) };
93813
94046
  } finally {
93814
94047
  closeSync7(fd);
93815
94048
  }
@@ -93910,8 +94143,9 @@ function serviceLines(i) {
93910
94143
  }
93911
94144
  }
93912
94145
  for (const hook of status.hooks ?? []) {
94146
+ const silence = hookWarning(hook, i.now);
93913
94147
  out.push(
93914
- hook.silence ? `Hooks (${hook.harness}): ${hook.silence.problem}. ${hook.silence.fix}` : `Hooks (${hook.harness}): ${hook.state}, install ${hook.install}`
94148
+ silence ? `Hooks (${hook.harness}): ${silence.problem}. ${silence.fix}` : `Hooks (${hook.harness}): ${hook.state}, install ${hook.install}`
93915
94149
  );
93916
94150
  }
93917
94151
  return out;
@@ -93968,6 +94202,7 @@ function isCliEnv(value) {
93968
94202
  return value in CLI_ENVIRONMENTS;
93969
94203
  }
93970
94204
  function describeEnvironment(config2, env, explicitEnv) {
94205
+ if (config2.appEnv === "production") return null;
93971
94206
  const steeredByEnvVar = explicitEnv === void 0 && env.POWERPLANT_ENV !== void 0;
93972
94207
  return `Environment: ${config2.appEnv} (API ${config2.apiUrl})${steeredByEnvVar ? ", set by POWERPLANT_ENV" : ""}`;
93973
94208
  }
@@ -94064,36 +94299,36 @@ function pausedSince(control, now) {
94064
94299
  }
94065
94300
  function pausedNotice(control, resumeCommand2, now) {
94066
94301
  if (!control.paused) return null;
94067
- return `\u23F8 ${pausedSince(control, now)}. Nothing uploads until you run \`${resumeCommand2}\`.`;
94302
+ return `! ${pausedSince(control, now)}. Nothing uploads until you run \`${resumeCommand2}\`.`;
94068
94303
  }
94069
94304
  function pausedSyncNotice(control, resumeCommand2, now, dryRun) {
94070
94305
  if (!control.paused || dryRun) return pausedNotice(control, resumeCommand2, now);
94071
- return `\u23F8 ${pausedSince(control, now)}. This pass uploads because you asked for it. Background syncing stays paused until you run \`${resumeCommand2}\`.`;
94306
+ return `! ${pausedSince(control, now)}. This pass uploads because you asked for it. Background syncing stays paused until you run \`${resumeCommand2}\`.`;
94072
94307
  }
94073
94308
  async function offerResume(deps, options) {
94074
- const { log: log3, indent } = options;
94309
+ const { output: output2 } = options;
94075
94310
  const control = deps.readControl();
94076
94311
  if (!control.paused) return "not-paused";
94077
94312
  const now = deps.now();
94078
94313
  const age = pausedFor(control, now);
94079
- log3(`${indent}! ${pausedSince(control, now)}, the background sync is running but uploads nothing`);
94080
- if (options.promptAllowed && await confirmResume(deps, log3, indent)) {
94314
+ output2.log(`! ${pausedSince(control, now)}, the background sync is running but uploads nothing`);
94315
+ if (options.promptAllowed && await confirmResume(deps, output2)) {
94081
94316
  deps.resume();
94082
- log3(
94083
- `${indent}\u2713 Syncing resumed, the background sync is catching up on ${age === null ? "the pause" : `the paused ${age}`}`
94317
+ output2.log(
94318
+ `\u2713 Syncing resumed, the background sync is catching up on ${age === null ? "the pause" : `the paused ${age}`}`
94084
94319
  );
94085
94320
  return "resumed";
94086
94321
  }
94087
- log3(`${indent}Nothing uploads until you run \`${deps.resumeCommand}\``);
94322
+ output2.log(`Nothing uploads until you run \`${deps.resumeCommand}\``);
94088
94323
  return "still-paused";
94089
94324
  }
94090
- async function confirmResume(deps, log3, indent) {
94325
+ async function confirmResume(deps, output2) {
94091
94326
  for (; ; ) {
94092
- const answer = await deps.promptLine(`${indent}Resume syncing now? [Y/n] `);
94327
+ const answer = await deps.promptLine(`${output2.indent}Resume syncing now? [Y/n] `);
94093
94328
  const normalized = answer?.trim().toLowerCase() ?? "";
94094
94329
  if (answer === null || normalized === "n" || normalized === "no") return false;
94095
94330
  if (normalized === "" || normalized === "y" || normalized === "yes") return true;
94096
- log3(`${indent}Please answer "y" or "n".`);
94331
+ output2.log('Please answer "y" or "n".');
94097
94332
  }
94098
94333
  }
94099
94334
 
@@ -94121,39 +94356,43 @@ function syncNote(credentials) {
94121
94356
  return `Uploads nothing yet, ${org} has no GitHub integration.`;
94122
94357
  }
94123
94358
  }
94359
+ function initExitCode(summary) {
94360
+ return summary === "ready" || summary === "already-set-up" ? 0 : 1;
94361
+ }
94362
+ function enrolledLine(credentials) {
94363
+ return `\u2713 ${credentials.machineName} enrolled${credentials.orgName ? ` in ${credentials.orgName}` : ""}`;
94364
+ }
94124
94365
  async function runInit(deps) {
94125
- const { log: log3 } = deps;
94366
+ const { command, stage } = deps.terminal;
94126
94367
  const existing = deps.loadCredentials();
94127
- log3("\u26A1 Powerplant");
94128
- log3(` ${existing ? "Checking" : "Setting up"} this machine \xB7 ${deps.environmentName}`);
94129
- log3("");
94368
+ command.log("\u26A1 Powerplant");
94369
+ command.detail(`${existing ? "Checking" : "Setting up"} this machine \xB7 ${deps.environmentName}`);
94370
+ command.log("");
94371
+ command.log("1/3 Enroll this machine");
94130
94372
  let enrolled = false;
94131
94373
  let credentials;
94132
94374
  if (existing) {
94133
- log3(
94134
- `\u2713 Machine enrolled as ${existing.machineName}${existing.orgName ? ` in ${existing.orgName}` : ""}`
94375
+ stage.log(
94376
+ `\u2713 Already enrolled as ${existing.machineName}${existing.orgName ? ` in ${existing.orgName}` : ""}`
94135
94377
  );
94136
94378
  credentials = existing;
94137
94379
  } else {
94138
- log3("1/3 Enroll this machine");
94139
- credentials = await deps.activity("Waiting for approval in your browser\u2026", deps.enroll);
94140
- log3(
94141
- ` \u2713 ${credentials.machineName} enrolled${credentials.orgName ? ` in ${credentials.orgName}` : ""}`
94142
- );
94380
+ credentials = await stage.activity("Waiting for approval in your browser\u2026", deps.enroll);
94381
+ stage.log(enrolledLine(credentials));
94143
94382
  enrolled = true;
94144
94383
  }
94145
- log3("");
94384
+ command.log("");
94146
94385
  const orgName = credentials.orgName;
94147
94386
  let repoDiscoveryDidWork = false;
94148
94387
  let protectedFoldersNeedAttention = false;
94149
94388
  let installed = false;
94150
94389
  let menubarDidWork = false;
94151
94390
  let pauseOffer = "not-paused";
94152
- log3("2/3 Start background sync");
94153
- log3(" When syncing is enabled, session transcripts upload to Powerplant for the team whose capture settings match the repository.");
94154
- log3(` ${syncNote(credentials)}`);
94391
+ command.log("2/3 Start background sync");
94392
+ stage.log("When syncing is enabled, session transcripts upload to Powerplant for the team whose capture settings match the repository.");
94393
+ stage.log(syncNote(credentials));
94155
94394
  if (deps.platform === "darwin") {
94156
- const protectedSessions = await deps.activity(
94395
+ const protectedSessions = await stage.activity(
94157
94396
  "Checking recent session locations\u2026",
94158
94397
  deps.findProtectedSessions
94159
94398
  );
@@ -94166,54 +94405,54 @@ async function runInit(deps) {
94166
94405
  const toProbe = [];
94167
94406
  let needsAttention = false;
94168
94407
  if (fresh.length > 0) {
94169
- log3(" Coding agents recorded recent sessions in folders macOS is currently hiding from Powerplant:");
94170
- logProtectedFolders(log3, fresh);
94408
+ stage.log("Coding agents recorded recent sessions in folders macOS is currently hiding from Powerplant:");
94409
+ logProtectedFolders(stage, fresh);
94171
94410
  if (!deps.promptAllowed) {
94172
94411
  needsAttention = true;
94173
- logProtectedSessionsStayLocal(log3, fresh);
94174
- log3(` Run \`powerplant init\` in a terminal to ${consented ? "scan" : "review"} them.`);
94412
+ logProtectedSessionsStayLocal(stage, fresh);
94413
+ stage.detail(`Run \`powerplant init\` in a terminal to ${consented ? "scan" : "review"} them.`);
94175
94414
  } else {
94176
- log3(
94177
- consented ? ` You already allowed Git metadata scans. Checking those folders for ${org}'s work repositories.` : ` If you allow it, Powerplant reads only Git metadata there, to find ${org}'s work repositories.`
94415
+ stage.log(
94416
+ consented ? `You already allowed Git metadata scans. Checking those folders for ${org}'s work repositories.` : `If you allow it, Powerplant reads only Git metadata there, to find ${org}'s work repositories.`
94178
94417
  );
94179
- if (consented || await confirmProtectedRepoDiscovery(deps)) toProbe.push(...fresh);
94418
+ if (consented || await confirmProtectedRepoDiscovery(deps, stage)) toProbe.push(...fresh);
94180
94419
  else {
94181
94420
  needsAttention = true;
94182
- logProtectedSessionsStayLocal(log3, fresh);
94421
+ logProtectedSessionsStayLocal(stage, fresh);
94183
94422
  }
94184
94423
  }
94185
94424
  }
94186
94425
  if (blocked.length > 0) {
94187
94426
  if (deps.promptAllowed) {
94188
- log3(` Checking whether macOS still blocks ${displayRoots(blocked)}.`);
94427
+ stage.log(`Checking whether macOS still blocks ${displayRoots(blocked)}.`);
94189
94428
  toProbe.push(...blocked);
94190
94429
  } else {
94191
94430
  needsAttention = true;
94192
- logBlockedByMacOS(log3, blocked);
94431
+ logBlockedByMacOS(stage, blocked);
94193
94432
  }
94194
94433
  }
94195
94434
  if (toProbe.length > 0) {
94196
- log3(' macOS may label Powerplant as "node" because Powerplant runs on Node.js.');
94435
+ stage.log('macOS may label Powerplant as "node" because Powerplant runs on Node.js.');
94197
94436
  const probe = async (roots) => {
94198
- const result2 = await deps.activity(
94437
+ const result2 = await stage.activity(
94199
94438
  "Scanning recorded session folders for Git repositories\u2026",
94200
94439
  () => deps.allowProtectedRepoDiscovery(roots)
94201
94440
  );
94202
- needsAttention = reportProtectedRepoDiscovery(log3, result2) || needsAttention;
94441
+ needsAttention = reportProtectedRepoDiscovery(stage, result2) || needsAttention;
94203
94442
  const unblocked = result2.unmatched.filter((entry) => reviewOf(entry) === "blocked");
94204
94443
  if (unblocked.length > 0) {
94205
- log3(` \u2713 macOS now lets Powerplant read ${displayRoots(unblocked)}. No work repositories were found there.`);
94444
+ stage.log(`\u2713 macOS now lets Powerplant read ${displayRoots(unblocked)}. No work repositories were found there.`);
94206
94445
  }
94207
94446
  if (result2.enabled.length > 0 || unblocked.length > 0) repoDiscoveryDidWork = true;
94208
94447
  return result2;
94209
94448
  };
94210
94449
  const result = await probe(toProbe);
94211
94450
  if (result.needsReview.length > 0) {
94212
- log3(" Some of those sessions use Git checkouts in other folders macOS is hiding from Powerplant:");
94213
- logProtectedFolders(log3, result.needsReview);
94451
+ stage.log("Some of those sessions use Git checkouts in other folders macOS is hiding from Powerplant:");
94452
+ logProtectedFolders(stage, result.needsReview);
94214
94453
  const second = await probe([...result.unreviewed, ...result.needsReview]);
94215
94454
  if (second.unreviewed.length > 0) {
94216
- logProtectedSessionsStayLocal(log3, second.unreviewed);
94455
+ logProtectedSessionsStayLocal(stage, second.unreviewed);
94217
94456
  needsAttention = true;
94218
94457
  }
94219
94458
  }
@@ -94222,137 +94461,125 @@ async function runInit(deps) {
94222
94461
  }
94223
94462
  }
94224
94463
  if (deps.platform !== "darwin") {
94225
- log3(
94226
- " Background sync is macOS-only for now. Run `powerplant sync` on a schedule of your choosing instead."
94464
+ stage.log(
94465
+ "Background sync is macOS-only for now. Run `powerplant sync` on a schedule of your choosing instead."
94227
94466
  );
94228
94467
  } else {
94229
94468
  const fresh = !deps.serviceUpToDate();
94230
94469
  if (fresh) {
94231
- await deps.activity("Installing background sync\u2026", deps.installService);
94232
- await deps.activity("Checking background sync version\u2026", () => deps.ensureServiceVersion(true));
94470
+ await stage.activity("Installing background sync\u2026", deps.installService);
94471
+ await stage.activity("Checking background sync version\u2026", () => deps.ensureServiceVersion(true));
94233
94472
  installed = true;
94234
94473
  } else {
94235
- installed = await deps.activity("Checking background sync version\u2026", () => deps.ensureServiceVersion(false));
94474
+ installed = await stage.activity("Checking background sync version\u2026", () => deps.ensureServiceVersion(false));
94236
94475
  }
94237
- pauseOffer = await offerResume(deps.pause, { log: log3, indent: " ", promptAllowed: deps.promptAllowed });
94238
- if (pauseOffer === "not-paused") log3(fresh ? " \u2713 Background sync is running" : "\u2713 Background sync is running");
94239
- await offerAutomaticUpdates(deps.autoUpdate, { log: log3, indent: " ", promptAllowed: deps.promptAllowed });
94476
+ pauseOffer = await offerResume(deps.pause, { output: stage, promptAllowed: deps.promptAllowed });
94477
+ if (pauseOffer === "not-paused") stage.log("\u2713 Background sync is running");
94478
+ await offerAutomaticUpdates(deps.autoUpdate, { output: stage, promptAllowed: deps.promptAllowed });
94240
94479
  if (deps.menubarApp !== null) {
94241
- const app = await deps.activity("Setting up the menu bar app\u2026", deps.menubarApp);
94242
- menubarDidWork = narrateMenubarApp(log3, app);
94480
+ const app = await stage.activity("Setting up the menu bar app\u2026", deps.menubarApp);
94481
+ menubarDidWork = narrateMenubarApp(stage, app);
94243
94482
  }
94244
94483
  }
94245
- log3("");
94246
- log3("3/3 Give your agents Powerplant MCP access");
94484
+ command.log("");
94485
+ command.log("3/3 Give your agents Powerplant MCP access");
94247
94486
  let outcome = null;
94248
94487
  try {
94249
94488
  outcome = await deps.connect();
94250
94489
  } catch (error63) {
94251
- log3(` \u2717 Could not give your agents Powerplant MCP access, ${error63 instanceof Error ? error63.message : String(error63)}`);
94490
+ stage.log(`\u2717 Could not give your agents Powerplant MCP access, ${error63 instanceof Error ? error63.message : String(error63)}`);
94252
94491
  }
94253
94492
  if (outcome?.found === 0) {
94254
- log3(
94255
- deps.platform === "darwin" ? ` This machine still syncs once one is installed, then run: ${deps.connectCommand}` : ` Once one is installed, run: ${deps.connectCommand}`
94256
- );
94493
+ stage.log(`Once one is installed, run \`${deps.connectCommand}\``);
94257
94494
  }
94258
- log3("");
94495
+ command.log("");
94259
94496
  const connectDidWork = outcome !== null && outcome.connected + outcome.configured > outcome.unchanged;
94260
94497
  const connectSettled = outcome !== null && outcome.found > 0 && outcome.pending === 0 && outcome.failed === 0 && outcome.skipped === 0 && outcome.unchanged === outcome.found && !connectDidWork;
94261
94498
  if (!enrolled && !installed && !menubarDidWork && !repoDiscoveryDidWork && !protectedFoldersNeedAttention && pauseOffer === "not-paused" && connectSettled) {
94262
- log3("Everything is already set up.");
94263
- return;
94499
+ command.log("\u2713 Everything is already set up");
94500
+ return "already-set-up";
94264
94501
  }
94265
94502
  const connectedAny = outcome !== null && outcome.connected + outcome.configured > 0;
94266
94503
  const connectIncomplete = outcome === null || outcome.pending > 0 || outcome.failed > 0 || outcome.skipped > 0 && !connectedAny;
94267
94504
  if (pauseOffer === "still-paused") {
94268
- log3("! Syncing is paused");
94269
- log3("");
94270
- log3(`Nothing uploads until you run \`${deps.pause.resumeCommand}\``);
94271
- if (connectIncomplete) log3(`Finish MCP setup: ${deps.connectCommand}`);
94272
- return;
94505
+ command.log("! Syncing is paused");
94506
+ command.log("");
94507
+ command.detail(`Nothing uploads until you run \`${deps.pause.resumeCommand}\``);
94508
+ if (connectIncomplete) command.detail(`Finish MCP setup: \`${deps.connectCommand}\``);
94509
+ return "paused";
94273
94510
  }
94274
94511
  if (connectIncomplete) {
94275
94512
  const onlySkipped = outcome !== null && outcome.skipped > 0 && outcome.pending === 0 && outcome.failed === 0;
94276
- log3(onlySkipped ? "! MCP setup was skipped" : "! Setup needs one more step");
94277
- log3("");
94278
- log3(
94279
- deps.platform === "darwin" ? "Your synced sessions will still appear in Powerplant." : "Your synced sessions will appear after `powerplant sync` runs."
94280
- );
94281
- log3("");
94282
- log3(`${onlySkipped ? "Add MCP later" : "Finish MCP setup"}: ${deps.connectCommand}`);
94283
- return;
94284
- }
94285
- log3("\u2713 Syncing is ready");
94286
- log3("");
94287
- log3(` Success! See your team's activity: ${deps.webUrl}`);
94288
- log3("");
94289
- log3(
94290
- deps.platform === "darwin" ? " As you code, try asking the Powerplant MCP about your sessions." : " As you code, run `powerplant sync`, then try asking the Powerplant MCP about your sessions."
94291
- );
94292
- log3("");
94293
- log3(
94294
- " Consider adding to your AGENTS file that the Powerplant MCP can be used to check for other team members' WIP, or for analyzing agent sessions that weren't following your docs and instructions."
94513
+ command.log(onlySkipped ? "! MCP setup was skipped" : "! Setup needs one more step");
94514
+ command.log("");
94515
+ command.detail(`${onlySkipped ? "Add MCP later" : "Finish MCP setup"}: \`${deps.connectCommand}\``);
94516
+ return onlySkipped ? "mcp-skipped" : "needs-step";
94517
+ }
94518
+ command.log("\u2713 Syncing is ready");
94519
+ command.log("");
94520
+ command.detail(
94521
+ deps.platform === "darwin" ? `See your team's activity: ${deps.webUrl}` : `Run \`powerplant sync\` after coding, then see your team's activity: ${deps.webUrl}`
94295
94522
  );
94296
94523
  if (outcome !== null && outcome.skipped > 0) {
94297
- log3("");
94298
- log3(` Add MCP to the agents you skipped any time: ${deps.connectCommand}`);
94524
+ command.detail(`Add MCP to the agents you skipped any time: \`${deps.connectCommand}\``);
94299
94525
  }
94526
+ return "ready";
94300
94527
  }
94301
- function narrateMenubarApp(log3, outcome) {
94528
+ function narrateMenubarApp(stage, outcome) {
94302
94529
  switch (outcome.kind) {
94303
94530
  case "installed":
94304
- log3(" \u2713 Menu bar app installed, look for the bolt in your menu bar");
94531
+ stage.log("\u2713 Menu bar app installed, look for the bolt in your menu bar");
94305
94532
  return true;
94306
94533
  case "updated":
94307
- log3(" \u2713 Menu bar app updated to match this CLI");
94534
+ stage.log("\u2713 Menu bar app updated to match this CLI");
94308
94535
  return true;
94309
94536
  case "already-current":
94310
- log3(" \u2713 Menu bar app is installed");
94537
+ stage.log("\u2713 Menu bar app is installed");
94311
94538
  return outcome.launched;
94312
94539
  case "skipped":
94313
94540
  return false;
94314
94541
  case "failed":
94315
- log3(` ! Could not set up the menu bar app: ${outcome.detail}`);
94316
- log3(" Rerun `powerplant init` to try again.");
94542
+ stage.log(`! Could not set up the menu bar app: ${outcome.detail}`);
94543
+ stage.detail("Rerun `powerplant init` to try again.");
94317
94544
  return true;
94318
94545
  }
94319
94546
  }
94320
- async function confirmProtectedRepoDiscovery(deps) {
94547
+ async function confirmProtectedRepoDiscovery(deps, stage) {
94321
94548
  for (; ; ) {
94322
94549
  const answer = await deps.promptLine(
94323
- "Scan Git metadata for your org's work repositories? [y/N] "
94550
+ `${stage.indent}Scan Git metadata for your org's work repositories? [y/N] `
94324
94551
  );
94325
94552
  const normalized = answer?.trim().toLowerCase() ?? "";
94326
94553
  if (normalized === "" || normalized === "n" || normalized === "no") return false;
94327
94554
  if (normalized === "y" || normalized === "yes") return true;
94328
- deps.log(' Please answer "y" or "n".');
94555
+ stage.log('Please answer "y" or "n".');
94329
94556
  }
94330
94557
  }
94331
- function logProtectedFolders(log3, roots) {
94558
+ function logProtectedFolders(stage, roots) {
94332
94559
  for (const folder of roots.flatMap((entry) => entry.folders)) {
94333
- log3(` ${folder.displayPath} (${folder.sessionCount} session${folder.sessionCount === 1 ? "" : "s"})`);
94560
+ stage.detail(`${folder.displayPath} (${folder.sessionCount} session${folder.sessionCount === 1 ? "" : "s"})`);
94334
94561
  }
94335
94562
  }
94336
- function reportProtectedRepoDiscovery(log3, result) {
94563
+ function reportProtectedRepoDiscovery(stage, result) {
94337
94564
  if (result.enabled.length > 0) {
94338
- log3(` \u2713 Repository scanning enabled for ${displayRoots(result.enabled)}`);
94565
+ stage.log(`\u2713 Repository scanning enabled for ${displayRoots(result.enabled)}`);
94339
94566
  }
94340
- if (result.blocked.length > 0) logBlockedByMacOS(log3, result.blocked);
94567
+ if (result.blocked.length > 0) logBlockedByMacOS(stage, result.blocked);
94341
94568
  return result.blocked.length > 0;
94342
94569
  }
94343
- function logBlockedByMacOS(log3, roots) {
94344
- log3(` ! macOS blocked Powerplant from reading ${displayRoots(roots)}.`);
94345
- log3(` Sessions there will stay local. ${MACOS_BLOCKED_FOLDER_REMEDY}`);
94570
+ function logBlockedByMacOS(stage, roots) {
94571
+ stage.log(`! macOS blocked Powerplant from reading ${displayRoots(roots)}.`);
94572
+ stage.detail(`Sessions there will stay local. ${MACOS_BLOCKED_FOLDER_REMEDY}`);
94346
94573
  }
94347
94574
  function displayRoots(roots) {
94348
94575
  return roots.map((entry) => entry.displayRoot).join(", ");
94349
94576
  }
94350
- function logProtectedSessionsStayLocal(log3, found) {
94577
+ function logProtectedSessionsStayLocal(stage, found) {
94351
94578
  const total = found.reduce((sum2, entry) => sum2 + entry.sessionCount, 0);
94352
- log3(
94353
- ` ! Repository matching for ${total} recent session${total === 1 ? "" : "s"} under ${displayRoots(found)} was not enabled.`
94579
+ stage.log(
94580
+ `! Repository matching for ${total} recent session${total === 1 ? "" : "s"} under ${displayRoots(found)} was not enabled.`
94354
94581
  );
94355
- log3(" Sessions outside folders you explicitly added will stay local.");
94582
+ stage.detail("Sessions outside folders you explicitly added will stay local.");
94356
94583
  }
94357
94584
  async function realPromptLine(question) {
94358
94585
  const prompt = createInterface2({ input: process.stdin, output: process.stdout });
@@ -94366,7 +94593,7 @@ async function realPromptLine(question) {
94366
94593
  }
94367
94594
 
94368
94595
  // src/menu.ts
94369
- import path27 from "node:path";
94596
+ import path29 from "node:path";
94370
94597
  var MENU_CONTRACT = 1;
94371
94598
  var CLIENT_NAMES = { claude: "Claude Code", codex: "Codex", cursor: "Cursor" };
94372
94599
  function renderMenu(i) {
@@ -94382,13 +94609,22 @@ function renderMenu(i) {
94382
94609
  more.push({ type: "section", title: "Agents authorized for MCP" });
94383
94610
  for (const connection of i.connections) {
94384
94611
  const { row, action, warns } = connectionRow(connection, envArgs);
94385
- if (warns) {
94612
+ const preference = i.mcpPreferences?.clients[connection.client];
94613
+ const eligible = warns && (connection.state !== "not-connected" || preference?.optedIn === true);
94614
+ const visible = eligible && preference?.dismissedWarning !== connection.state;
94615
+ const dismiss = i.mcpPreferencesError === void 0 ? {
94616
+ type: "action",
94617
+ title: `Dismiss ${CLIENT_NAMES[connection.client]} warning`,
94618
+ run: ["dismiss-mcp-warning", connection.client, connection.state, ...envArgs]
94619
+ } : void 0;
94620
+ if (visible) {
94386
94621
  attention = true;
94387
- items.push(row);
94622
+ items.push({ ...row, ...dismiss && { dismiss } });
94388
94623
  if (action) items.push(action);
94389
94624
  }
94390
- more.push(row);
94625
+ more.push(warns && !visible ? { ...row, mark: "muted" } : row);
94391
94626
  if (action) more.push(action);
94627
+ if (visible && dismiss) more.push(dismiss);
94392
94628
  }
94393
94629
  more.push({ type: "separator" });
94394
94630
  }
@@ -94414,6 +94650,16 @@ function renderMenu(i) {
94414
94650
  items.push({ type: "action", title: "Restart background sync\u2026", terminal: ["restart", ...envArgs] });
94415
94651
  items.push({ type: "separator" });
94416
94652
  }
94653
+ if (i.mcpPreferencesError !== void 0) {
94654
+ items.push(problem("MCP choices can't be read", "Restore or remove the preferences file."));
94655
+ items.push({ type: "action", title: "Copy MCP repair details", copy: i.mcpPreferencesError });
94656
+ items.push({ type: "separator" });
94657
+ }
94658
+ if (i.hookPreferencesError !== void 0) {
94659
+ items.push(problem("Hook warning preference can't be read", "Restore or remove the preferences file."));
94660
+ items.push({ type: "action", title: "Copy hook preference repair details", copy: i.hookPreferencesError });
94661
+ items.push({ type: "separator" });
94662
+ }
94417
94663
  if (i.credentialsError !== void 0) {
94418
94664
  items.push(problem("Stored enrollment can't be read", i.credentialsError));
94419
94665
  items.push({ type: "action", title: "Enroll Again\u2026", terminal: ["init", ...envArgs] });
@@ -94428,7 +94674,10 @@ function renderMenu(i) {
94428
94674
  trailing: "Enrolled"
94429
94675
  });
94430
94676
  items.push({ type: "separator" });
94431
- items.push(...collectorBlock(i, envArgs, problem));
94677
+ items.push(...collectorBlock(i, envArgs, problem, (title, subtitle, dismiss) => {
94678
+ attention = true;
94679
+ return { type: "status", mark: "warn", title, subtitle, ...dismiss && { dismiss } };
94680
+ }, more));
94432
94681
  }
94433
94682
  const agents = recentAgentItems(i);
94434
94683
  if (agents !== null) {
@@ -94509,7 +94758,7 @@ function failedUpdateDetail(i, progress) {
94509
94758
  }
94510
94759
  return progress.detail;
94511
94760
  }
94512
- function collectorBlock(i, envArgs, problem) {
94761
+ function collectorBlock(i, envArgs, problem, warning2, more) {
94513
94762
  const restart = {
94514
94763
  type: "action",
94515
94764
  title: "Restart background sync",
@@ -94578,9 +94827,26 @@ function collectorBlock(i, envArgs, problem) {
94578
94827
  break;
94579
94828
  }
94580
94829
  const status = i.daemon.status;
94581
- const silentHooks = (status.hooks ?? []).flatMap(
94582
- (hook) => hook.silence ? [problem(hook.silence.problem, hook.silence.fix)] : []
94583
- );
94830
+ const silentHooks = (status.hooks ?? []).flatMap((hook) => {
94831
+ const silence = hookWarning(hook, i.now);
94832
+ if (!silence) return [];
94833
+ if (hook.harness !== "codex" || silence.kind !== "not-firing") {
94834
+ return [problem(silence.problem, silence.fix)];
94835
+ }
94836
+ const title = "Codex hook install incomplete";
94837
+ const subtitle = silence.fix;
94838
+ if (i.codexHookWarningDismissed) {
94839
+ more.push({ type: "status", mark: "muted", title, subtitle });
94840
+ return [];
94841
+ }
94842
+ const dismiss = i.hookPreferencesError === void 0 ? {
94843
+ type: "action",
94844
+ title: "Dismiss Codex hooks warning",
94845
+ run: ["dismiss-codex-hook-warning", ...envArgs]
94846
+ } : void 0;
94847
+ if (dismiss) more.push(dismiss);
94848
+ return [warning2(title, subtitle, dismiss)];
94849
+ });
94584
94850
  if (i.control.paused) {
94585
94851
  return [
94586
94852
  {
@@ -94632,7 +94898,7 @@ function agentRow(session, i) {
94632
94898
  const when = ago(i.now - Date.parse(session.lastActivityAt));
94633
94899
  const localMachine = i.credentials !== null && session.machineId === i.credentials.machineId;
94634
94900
  const desktopSessionId = localMachine && session.source === "claude-code" ? i.claudeDesktopSessions?.get(session.externalId)?.sessionId : void 0;
94635
- const app = desktopSessionId !== void 0 ? "Claude desktop" : isSessionSource(session.source) ? describeSessionSource(session.source) : session.source;
94901
+ const app = desktopSessionId !== void 0 ? "Claude desktop" : isLegacySessionSource(session.source) ? describeSessionSource(session.source) : session.source;
94636
94902
  const links = sessionLinks(session, i.config.webUrl, {
94637
94903
  codexDesktop: i.codexDesktop,
94638
94904
  localMachine,
@@ -94648,6 +94914,12 @@ function agentRow(session, i) {
94648
94914
  agent.harness = {
94649
94915
  type: "action",
94650
94916
  title: links.extra.label,
94917
+ reportClick: [
94918
+ "report-agent-click",
94919
+ isLegacySessionSource(session.source) ? session.source : "unknown",
94920
+ "focus" in links.extra ? "focus" : "terminal" in links.extra ? "resume" : /^(codex|claude):/.test(links.extra.url) ? "desktop" : "web",
94921
+ ...envArgs
94922
+ ],
94651
94923
  ..."url" in links.extra ? { url: links.extra.url } : {
94652
94924
  ..."focus" in links.extra && { focus: links.extra.focus },
94653
94925
  terminal: [...links.extra.terminal, ...envArgs]
@@ -94764,7 +95036,7 @@ function daemonVersionNote(i) {
94764
95036
  }
94765
95037
  var VERSION_CACHE_TTL_MS = 60 * 6e4;
94766
95038
  function versionCachePath(homeDir, source = "npm") {
94767
- return path27.join(collectorStateDir(homeDir), source === "npm" ? "version-check.json" : "version-check-promoted.json");
95039
+ return path29.join(collectorStateDir(homeDir), source === "npm" ? "version-check.json" : "version-check-promoted.json");
94768
95040
  }
94769
95041
  async function cachedLatestVersion(options) {
94770
95042
  const raw = options.readTextFile(options.cacheFile);
@@ -94796,7 +95068,7 @@ function writeVersionCache(options) {
94796
95068
  import { execFileSync as execFileSync7 } from "node:child_process";
94797
95069
  import { readdir as readdir3, readFile as readFile2 } from "node:fs/promises";
94798
95070
  import os21 from "node:os";
94799
- import path28 from "node:path";
95071
+ import path30 from "node:path";
94800
95072
  var sessionFileAsObserved = external_exports.looseObject({
94801
95073
  pid: external_exports.number().int().positive(),
94802
95074
  sessionId: external_exports.string().min(1),
@@ -94805,7 +95077,7 @@ var sessionFileAsObserved = external_exports.looseObject({
94805
95077
  var START_TIME_TOLERANCE_MS = 3e4;
94806
95078
  var SESSION_FILE = /^(\d+)\.json$/;
94807
95079
  function claudeSessionsDir(homeDir = os21.homedir()) {
94808
- return path28.join(homeDir, ".claude", "sessions");
95080
+ return path30.join(homeDir, ".claude", "sessions");
94809
95081
  }
94810
95082
  async function readLiveTerminalSessions(wanted, deps = {}) {
94811
95083
  const found = /* @__PURE__ */ new Map();
@@ -94830,7 +95102,7 @@ async function readLiveTerminalSessions(wanted, deps = {}) {
94830
95102
  }
94831
95103
  continue;
94832
95104
  }
94833
- const session = await readSessionFile(path28.join(sessionsDir, entry), report2);
95105
+ const session = await readSessionFile(path30.join(sessionsDir, entry), report2);
94834
95106
  if (session === null) continue;
94835
95107
  if (session.pid !== Number(match[1])) {
94836
95108
  report2({
@@ -94868,7 +95140,7 @@ async function readSessionFile(file2, report2) {
94868
95140
  report2({
94869
95141
  operation: "claude-session-registry-shape",
94870
95142
  message: "A Claude Code session file has a shape this CLI can't read",
94871
- context: { file: path28.basename(file2), shape: describeShape(raw) }
95143
+ context: { file: path30.basename(file2), shape: describeShape(raw) }
94872
95144
  });
94873
95145
  return null;
94874
95146
  }
@@ -95009,14 +95281,9 @@ function automaticUpdatesLine(control) {
95009
95281
  }
95010
95282
  function renderStatus(i) {
95011
95283
  const lines = [];
95012
- lines.push(`Environment: ${i.config.appEnv} (API ${i.config.apiUrl})`);
95013
- lines.push(
95014
- `CLI: powerplant ${i.cliVersion}` + (isUpdateAvailable(i.cliVersion, i.latestVersion) ? `, ${i.latestVersion} is available: powerplant update` : "")
95015
- );
95016
- const unsupported = unsupportedVersionNotice(i.cliVersion, i.oldestSupportedVersion);
95017
- if (unsupported !== null) lines.push(unsupported);
95284
+ if (i.config.appEnv !== "production") lines.push(`Environment: ${i.config.appEnv} (API ${i.config.apiUrl})`);
95018
95285
  if (i.credentialsError !== void 0) {
95019
- lines.push(`\u26A0 ${i.credentialsError}`);
95286
+ lines.push(`\u2717 ${i.credentialsError}`);
95020
95287
  } else if (!i.credentials) {
95021
95288
  lines.push("Not enrolled, run: powerplant init");
95022
95289
  } else {
@@ -95028,7 +95295,7 @@ function renderStatus(i) {
95028
95295
  for (const entry of i.protectedSessions ?? []) {
95029
95296
  const sessions = `${entry.sessionCount} recent agent session${entry.sessionCount === 1 ? "" : "s"}`;
95030
95297
  lines.push(
95031
- protectedRootReview(i.credentials, entry.root) === "blocked" ? `\u26A0 macOS is blocking Powerplant from reading ${entry.displayRoot} (${sessions}). Those sessions are staying local. ${MACOS_BLOCKED_FOLDER_REMEDY}` : `\u26A0 Repository matching is not enabled for ${sessions} under ${entry.displayRoot}. Sessions outside folders you explicitly added are staying local, run \`powerplant init\` to review Git repository scanning.`
95298
+ protectedRootReview(i.credentials, entry.root) === "blocked" ? `! macOS is blocking Powerplant from reading ${entry.displayRoot} (${sessions}). Those sessions are staying local. ${MACOS_BLOCKED_FOLDER_REMEDY}` : `! Repository matching is not enabled for ${sessions} under ${entry.displayRoot}. Sessions outside folders you explicitly added are staying local, run \`powerplant init\` to review Git repository scanning.`
95032
95299
  );
95033
95300
  }
95034
95301
  }
@@ -95054,6 +95321,11 @@ function renderStatus(i) {
95054
95321
  lines.push(...renderDaemon(i));
95055
95322
  break;
95056
95323
  }
95324
+ lines.push(
95325
+ `CLI: powerplant ${i.cliVersion}` + (isUpdateAvailable(i.cliVersion, i.latestVersion) ? `, ${i.latestVersion} is available: powerplant update` : "")
95326
+ );
95327
+ const unsupported = unsupportedVersionNotice(i.cliVersion, i.oldestSupportedVersion);
95328
+ if (unsupported !== null) lines.push(unsupported);
95057
95329
  return lines;
95058
95330
  }
95059
95331
  function renderDaemon(i) {
@@ -95071,7 +95343,7 @@ function renderDaemon(i) {
95071
95343
  const lines = [];
95072
95344
  if (i.daemon.state === "stalled") {
95073
95345
  lines.push(
95074
- `\u26A0 Background sync stalled, no heartbeat for ${duration3(i.daemon.staleMs)} (pid ${status.pid}). Run: powerplant restart`
95346
+ `\u2717 Background sync stalled, no heartbeat for ${duration3(i.daemon.staleMs)} (pid ${status.pid}). Run: powerplant restart`
95075
95347
  );
95076
95348
  } else {
95077
95349
  lines.push(
@@ -95096,11 +95368,12 @@ function renderDaemon(i) {
95096
95368
  lines.push(signals === null ? " No pass has run yet in this run." : ` ${signals}`);
95097
95369
  if (status.lastPass && !status.lastPass.ok) {
95098
95370
  lines.push(
95099
- ` \u26A0 Last pass failed: ${status.lastPass.error ?? "unknown error"} (${status.consecutiveFailures} consecutive failure${status.consecutiveFailures === 1 ? "" : "s"}).`
95371
+ ` \u2717 Last pass failed: ${status.lastPass.error ?? "unknown error"} (${status.consecutiveFailures} consecutive failure${status.consecutiveFailures === 1 ? "" : "s"}).`
95100
95372
  );
95101
95373
  }
95102
95374
  for (const hook of status.hooks ?? []) {
95103
- if (hook.silence) lines.push(` \u26A0 ${hook.silence.problem}. ${hook.silence.fix}`);
95375
+ const silence = hookWarning(hook, i.now);
95376
+ if (silence) lines.push(` ! ${silence.problem}. ${silence.fix}`);
95104
95377
  }
95105
95378
  return lines;
95106
95379
  }
@@ -95191,11 +95464,15 @@ var ANSI = {
95191
95464
  resetUnderline: "\x1B[24m"
95192
95465
  };
95193
95466
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
95467
+ var COLUMNS = {
95468
+ command: { line: 0, detail: 2 },
95469
+ stage: { line: 5, detail: 7 }
95470
+ };
95194
95471
  function terminalUsesEffects(interactive, env) {
95195
95472
  return interactive && !("NO_COLOR" in env);
95196
95473
  }
95197
95474
  function colorPrefix(line) {
95198
- const status = /^(\s*)([✓!✗→⏸⚠])/.exec(line);
95475
+ const status = /^(\s*)([✓!✗→])/.exec(line);
95199
95476
  if (status) {
95200
95477
  const color = status[2] === "\u2713" ? ANSI.green : status[2] === "\u2717" ? ANSI.red : ANSI.yellow;
95201
95478
  return `${status[1]}${color}${status[2]}${ANSI.resetColor}${line.slice(status[0].length)}`;
@@ -95211,11 +95488,8 @@ function styleUrls(line) {
95211
95488
  (url2) => `${ANSI.cyan}${ANSI.underline}${url2}${ANSI.resetUnderline}${ANSI.resetColor}`
95212
95489
  );
95213
95490
  }
95214
- function styleCommands(line, dimmed) {
95215
- return line.replace(
95216
- /`([^`]+)`/g,
95217
- (_, command) => `${ANSI.bold}${command}${ANSI.resetDim}${dimmed ? ANSI.dim : ""}`
95218
- );
95491
+ function styleCommands(line) {
95492
+ return line.replace(/`([^`]+)`/g, (_, command) => `${ANSI.bold}${command}${ANSI.resetDim}`);
95219
95493
  }
95220
95494
  function dim(line) {
95221
95495
  return `${ANSI.dim}${line}${ANSI.resetDim}`;
@@ -95228,22 +95502,20 @@ function withDimTerminal(write, work) {
95228
95502
  write(ANSI.resetDim);
95229
95503
  }
95230
95504
  }
95231
- function styleLine(line) {
95232
- if (/^\s*- Opening approval page… https:\/\//.test(line)) return dim(line);
95233
- if (/^\s*[✓!✗→⏸⚠]/.test(line)) return styleCommands(styleUrls(colorPrefix(line)), false);
95234
- if (line.startsWith(" ")) {
95235
- const urlStart = line.search(/https:\/\//);
95236
- if (urlStart >= 0) {
95237
- return `${ANSI.dim}${styleCommands(line.slice(0, urlStart), true)}${ANSI.resetDim}${styleUrls(line.slice(urlStart))}`;
95238
- }
95239
- return `${ANSI.dim}${styleCommands(line, true)}${ANSI.resetDim}`;
95240
- }
95241
- return styleCommands(styleUrls(colorPrefix(line)), false);
95505
+ function skippable(line, place) {
95506
+ if (/^\s*[✓!✗→]/.test(line)) return false;
95507
+ if (/`[^`]+`|https:\/\//.test(line)) return false;
95508
+ return place.level === "stage" ? !place.detail : place.detail;
95509
+ }
95510
+ function styleLine(line, place) {
95511
+ if (skippable(line, place)) return dim(line);
95512
+ return styleCommands(styleUrls(colorPrefix(line)));
95242
95513
  }
95243
95514
  function createTerminalOutput(options) {
95244
95515
  const interactive = options.interactive;
95245
95516
  const color = interactive && options.color;
95246
95517
  let activityLabel = null;
95518
+ let activityIndent = "";
95247
95519
  let frameIndex = 0;
95248
95520
  let timer = null;
95249
95521
  const renderActivity = () => {
@@ -95251,24 +95523,26 @@ function createTerminalOutput(options) {
95251
95523
  const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length];
95252
95524
  frameIndex += 1;
95253
95525
  const glyph = color ? `${ANSI.amber}${frame}${ANSI.resetColor}` : frame;
95254
- options.write(`${ANSI.clearLine} ${glyph} ${activityLabel}`);
95526
+ options.write(`${ANSI.clearLine}${activityIndent}${glyph} ${activityLabel}`);
95255
95527
  };
95256
95528
  const clearActivity = () => {
95257
95529
  if (activityLabel !== null) options.write(ANSI.clearLine);
95258
95530
  };
95259
- const log3 = (line) => {
95531
+ const log3 = (line, place) => {
95260
95532
  const rerender = activityLabel !== null;
95261
95533
  if (rerender) clearActivity();
95262
- options.write(`${color ? styleLine(line) : line}
95534
+ options.write(`${color ? styleLine(line, place) : line}
95263
95535
  `);
95264
95536
  if (rerender) renderActivity();
95265
95537
  };
95266
- const activity = async (label2, work) => {
95538
+ const activity = async (place, label2, work) => {
95539
+ const indent = " ".repeat(COLUMNS[place.level].line);
95267
95540
  if (!interactive) {
95268
- log3(` \u2026 ${label2}`);
95541
+ log3(`${indent}\u2026 ${label2}`, place);
95269
95542
  return await work();
95270
95543
  }
95271
95544
  activityLabel = label2;
95545
+ activityIndent = indent;
95272
95546
  frameIndex = 0;
95273
95547
  renderActivity();
95274
95548
  timer = setInterval(renderActivity, 80);
@@ -95282,13 +95556,27 @@ function createTerminalOutput(options) {
95282
95556
  activityLabel = null;
95283
95557
  }
95284
95558
  };
95285
- return { log: log3, activity };
95559
+ const writer = (level) => {
95560
+ const columns = COLUMNS[level];
95561
+ const indent = " ".repeat(columns.line);
95562
+ const detailIndent = " ".repeat(columns.detail);
95563
+ const line = { level, detail: false };
95564
+ const detail = { level, detail: true };
95565
+ return {
95566
+ indent,
95567
+ // A blank line separates stages; it carries no indentation.
95568
+ log: (text) => log3(text === "" ? "" : `${indent}${text}`, line),
95569
+ detail: (text) => log3(`${detailIndent}${text}`, detail),
95570
+ activity: (label2, work) => activity(line, label2, work)
95571
+ };
95572
+ };
95573
+ return { command: writer("command"), stage: writer("stage") };
95286
95574
  }
95287
95575
 
95288
95576
  // src/credentialUpgrade.ts
95289
95577
  import { spawn as spawn2 } from "node:child_process";
95290
- import { closeSync as closeSync8, mkdirSync as mkdirSync12, openSync as openSync8 } from "node:fs";
95291
- import path29 from "node:path";
95578
+ import { closeSync as closeSync8, mkdirSync as mkdirSync14, openSync as openSync8 } from "node:fs";
95579
+ import path31 from "node:path";
95292
95580
  async function prepareCredentialUpgrade(deps) {
95293
95581
  if (!deps.needsMigration() || !deps.serviceExists() || deps.ready()) return "ready";
95294
95582
  if (deps.installing()) return "busy";
@@ -95321,7 +95609,7 @@ async function prepareCredentialUpgrade(deps) {
95321
95609
  }
95322
95610
  }
95323
95611
  async function tryCredentialUpgradeLock(file2) {
95324
- mkdirSync12(path29.dirname(file2), { recursive: true, mode: 448 });
95612
+ mkdirSync14(path31.dirname(file2), { recursive: true, mode: 448 });
95325
95613
  closeSync8(openSync8(file2, "a", 384));
95326
95614
  const child = spawn2("/usr/bin/lockf", ["-k", "-s", "-t", "0", file2, "/bin/sh", "-c", "printf 'ready\\n'; exec /bin/cat >/dev/null"], {
95327
95615
  detached: true,
@@ -95439,9 +95727,9 @@ async function tryCredentialUpgradeLock(file2) {
95439
95727
  }
95440
95728
 
95441
95729
  // src/menubarApp.ts
95442
- import { existsSync as existsSync13, mkdirSync as mkdirSync13, renameSync as renameSync5, rmSync as rmSync6 } from "node:fs";
95730
+ import { existsSync as existsSync13, mkdirSync as mkdirSync15, renameSync as renameSync7, rmSync as rmSync6 } from "node:fs";
95443
95731
  import os22 from "node:os";
95444
- import path30 from "node:path";
95732
+ import path32 from "node:path";
95445
95733
  import { spawnSync as spawnSync4 } from "node:child_process";
95446
95734
  var MENUBAR_APP_ZIP = "dist/menubar/Powerplant.app.zip";
95447
95735
  var MENUBAR_APP_NAME = "Powerplant.app";
@@ -95480,13 +95768,13 @@ async function syncMenubarApp(ops, context2) {
95480
95768
  }
95481
95769
  function realMenubarAppOps(input2) {
95482
95770
  const home = input2.homeDir ?? os22.homedir();
95483
- const userAppPath = path30.join(home, "Applications", MENUBAR_APP_NAME);
95484
- const candidates = [userAppPath, path30.join("/Applications", MENUBAR_APP_NAME)];
95771
+ const userAppPath = path32.join(home, "Applications", MENUBAR_APP_NAME);
95772
+ const candidates = [userAppPath, path32.join("/Applications", MENUBAR_APP_NAME)];
95485
95773
  return {
95486
95774
  cliVersion: input2.cliVersion,
95487
95775
  packagedZip: () => {
95488
95776
  if (input2.packageDir === null) return null;
95489
- const zip = path30.join(input2.packageDir, MENUBAR_APP_ZIP);
95777
+ const zip = path32.join(input2.packageDir, MENUBAR_APP_ZIP);
95490
95778
  return existsSync13(zip) ? zip : null;
95491
95779
  },
95492
95780
  installedApp: () => {
@@ -95506,10 +95794,10 @@ function realMenubarAppOps(input2) {
95506
95794
  throw new Error(`the running app at ${appPath} did not quit`);
95507
95795
  },
95508
95796
  replace: (zip, appPath) => {
95509
- const parent = path30.dirname(appPath);
95510
- mkdirSync13(parent, { recursive: true });
95511
- const staging = path30.join(parent, `.${MENUBAR_APP_NAME}.swap-${process.pid}`);
95512
- const retired = path30.join(parent, `.${MENUBAR_APP_NAME}.old-${process.pid}`);
95797
+ const parent = path32.dirname(appPath);
95798
+ mkdirSync15(parent, { recursive: true });
95799
+ const staging = path32.join(parent, `.${MENUBAR_APP_NAME}.swap-${process.pid}`);
95800
+ const retired = path32.join(parent, `.${MENUBAR_APP_NAME}.old-${process.pid}`);
95513
95801
  rmSync6(staging, { recursive: true, force: true });
95514
95802
  rmSync6(retired, { recursive: true, force: true });
95515
95803
  try {
@@ -95519,16 +95807,16 @@ function realMenubarAppOps(input2) {
95519
95807
  `ditto could not extract ${zip} (${extract.stderr?.toString().trim() || `exit ${extract.status}`})`
95520
95808
  );
95521
95809
  }
95522
- const extracted = path30.join(staging, MENUBAR_APP_NAME);
95523
- if (!existsSync13(path30.join(extracted, "Contents", "Info.plist"))) {
95810
+ const extracted = path32.join(staging, MENUBAR_APP_NAME);
95811
+ if (!existsSync13(path32.join(extracted, "Contents", "Info.plist"))) {
95524
95812
  throw new Error(`${zip} does not contain ${MENUBAR_APP_NAME}`);
95525
95813
  }
95526
95814
  const hadOld = existsSync13(appPath);
95527
- if (hadOld) renameSync5(appPath, retired);
95815
+ if (hadOld) renameSync7(appPath, retired);
95528
95816
  try {
95529
- renameSync5(extracted, appPath);
95817
+ renameSync7(extracted, appPath);
95530
95818
  } catch (error63) {
95531
- if (hadOld) renameSync5(retired, appPath);
95819
+ if (hadOld) renameSync7(retired, appPath);
95532
95820
  throw error63;
95533
95821
  }
95534
95822
  } finally {
@@ -95548,7 +95836,7 @@ function realMenubarAppOps(input2) {
95548
95836
  };
95549
95837
  }
95550
95838
  function appProcessIds(appPath) {
95551
- const executable = path30.join(appPath, "Contents", "MacOS", "PowerplantMenubar");
95839
+ const executable = path32.join(appPath, "Contents", "MacOS", "PowerplantMenubar");
95552
95840
  const result = spawnSync4("ps", ["-axo", "pid=,comm="], { encoding: "utf8" });
95553
95841
  if (result.status !== 0) {
95554
95842
  throw new Error(`ps could not list processes (${result.error?.message ?? `exit ${result.status}`})`);
@@ -95577,10 +95865,10 @@ var workspaceSchema = external_exports.object({
95577
95865
  active: external_exports.boolean()
95578
95866
  });
95579
95867
  var FETCH_TIMEOUT_MS2 = 1e4;
95580
- async function callApi(credentials, path32, init3, fetchImpl) {
95868
+ async function callApi(credentials, path34, init3, fetchImpl) {
95581
95869
  let response;
95582
95870
  try {
95583
- response = await fetchImpl(`${credentials.apiUrl}${path32}`, {
95871
+ response = await fetchImpl(`${credentials.apiUrl}${path34}`, {
95584
95872
  ...init3,
95585
95873
  headers: {
95586
95874
  authorization: `Bearer ${credentials.token}`,
@@ -95599,7 +95887,7 @@ async function callApi(credentials, path32, init3, fetchImpl) {
95599
95887
  );
95600
95888
  }
95601
95889
  if (!response.ok) {
95602
- throw new ExpectedCliError(`Powerplant answered ${response.status} for ${path32}.`);
95890
+ throw new ExpectedCliError(`Powerplant answered ${response.status} for ${path34}.`);
95603
95891
  }
95604
95892
  return response.json();
95605
95893
  }
@@ -95684,7 +95972,8 @@ Commands:
95684
95972
  update Update this CLI to the latest published version, using the
95685
95973
  package manager that installed it, and restart background sync.
95686
95974
  --automatic on|off sets whether the background sync installs
95687
- new releases itself (on from the first install).
95975
+ new releases itself. \`powerplant init\` asks once; a machine
95976
+ that was never asked stays off.
95688
95977
  restart Restart the background sync.
95689
95978
  pause Pause background syncing: the service keeps running but
95690
95979
  uploads nothing. An explicit \`powerplant sync\` still runs.
@@ -95782,9 +96071,11 @@ ${USAGE}`);
95782
96071
  const chosenEnv = values.env;
95783
96072
  const config2 = resolveCliConfig(process.env, chosenEnv);
95784
96073
  const banner = describeEnvironment(config2, process.env, chosenEnv);
95785
- console.error(
95786
- terminalUsesEffects(process.stderr.isTTY === true, process.env) ? dim(banner) : banner
95787
- );
96074
+ if (banner !== null) {
96075
+ console.error(
96076
+ terminalUsesEffects(process.stderr.isTTY === true, process.env) ? dim(banner) : banner
96077
+ );
96078
+ }
95788
96079
  const dsn = reportingDsn(process.env, config2, CLI_RELEASE_BUILD);
95789
96080
  if (dsn !== void 0) process.env.SENTRY_DSN = dsn;
95790
96081
  initCollectorReporting(config2.appEnv, CLI_VERSION);
@@ -95816,7 +96107,7 @@ ${USAGE}`);
95816
96107
  install: () => {
95817
96108
  installService(config2, watchCommand(config2));
95818
96109
  },
95819
- tryLock: () => tryCredentialUpgradeLock(path31.join(collectorStateDir(), `credential-upgrade-${config2.appEnv}.lock`)),
96110
+ tryLock: () => tryCredentialUpgradeLock(path33.join(collectorStateDir(), `credential-upgrade-${config2.appEnv}.lock`)),
95820
96111
  now: Date.now,
95821
96112
  sleep: () => new Promise((resolve2) => setTimeout(resolve2, 250)),
95822
96113
  restartCommand: `powerplant restart${config2.appEnv === "production" ? "" : ` --env ${config2.appEnv}`}`,
@@ -95854,15 +96145,25 @@ ${USAGE}`);
95854
96145
  stdoutIsTty: process.stdout.isTTY === true
95855
96146
  });
95856
96147
  const pause = realPauseDeps(config2.appEnv, withEnv("powerplant resume"), realPromptLine);
96148
+ const terminalEffects = terminalUsesEffects(process.stdout.isTTY === true, process.env);
96149
+ const terminal = createTerminalOutput({
96150
+ interactive: terminalEffects && !values.verbose,
96151
+ color: terminalEffects,
96152
+ write: (chunk) => process.stdout.write(chunk)
96153
+ });
95857
96154
  if (!PAUSE_NOTICE_SKIPPED.has(command)) {
95858
96155
  const notice = pausedNotice(pause.readControl(), pause.resumeCommand, Date.now());
95859
96156
  if (notice !== null) console.error(styledFor(process.stderr)(notice));
95860
96157
  }
95861
96158
  const agentCount = (clients) => new Set(clients.map((client) => client.client)).size;
95862
- const connect3 = async (log3) => {
96159
+ const connect3 = async (output2) => {
96160
+ const log3 = output2.log;
95863
96161
  const detected = detectClients({ warn: log3 });
95864
96162
  saveDetectedClients(detected, process.env.PATH ?? "");
95865
96163
  let clients = clientFilter === void 0 ? detected : detected.filter((client) => clientFilter.has(client.client));
96164
+ if (!pickerOn || clientFilter !== void 0) {
96165
+ recordMcpConnectChoices(config2.appEnv, detected.map((client) => client.client), clientFilter);
96166
+ }
95866
96167
  if (clientFilter !== void 0 && clients.length === 0) {
95867
96168
  log3(
95868
96169
  `No ${[...clientFilter].join(" or ")} installation found on this machine, nothing to connect.`
@@ -95879,7 +96180,11 @@ ${USAGE}`);
95879
96180
  }
95880
96181
  let skipped = 0;
95881
96182
  if (pickerOn && clientFilter === void 0 && clients.length > 0) {
95882
- clients = await pickAgents(clients, { log: log3, promptCheckboxes: realCheckboxPrompt });
96183
+ clients = await pickAgents(clients, {
96184
+ log: log3,
96185
+ promptCheckboxes: (question, choices) => realCheckboxPrompt(question, choices, { indent: output2.indent }),
96186
+ onChoice: (selected) => recordMcpChoices(config2.appEnv, detected.map((client) => client.client), selected.map((client) => client.client))
96187
+ });
95883
96188
  skipped = agentCount(detected) - agentCount(clients);
95884
96189
  if (clients.length === 0) {
95885
96190
  log3(`Powerplant MCP wasn't added to any agents. Run any time: ${connectCommand}`);
@@ -95914,19 +96219,13 @@ ${USAGE}`);
95914
96219
  };
95915
96220
  switch (command) {
95916
96221
  case "init": {
95917
- const terminalEffects = terminalUsesEffects(process.stdout.isTTY === true, process.env);
95918
- const terminal = createTerminalOutput({
95919
- interactive: terminalEffects && !values.verbose,
95920
- color: terminalEffects,
95921
- write: (chunk) => process.stdout.write(chunk)
95922
- });
95923
- await runInit({
95924
- log: terminal.log,
95925
- activity: terminal.activity,
96222
+ const summary = await runInit({
96223
+ terminal,
95926
96224
  loadCredentials: () => loadCredentials(config2.appEnv),
95927
- // Enrollment's own narration (org, token location, capture boundary)
95928
- // indents under stage 1.
95929
- enroll: () => enroll2((line) => terminal.log(` ${line}`)),
96225
+ // Enrollment's own lines (approval URL, token location) are detail
96226
+ // lines under stage 1's spinner; init prints the result line, and
96227
+ // stage 2 states the capture boundary.
96228
+ enroll: () => enroll2(terminal.stage.detail),
95930
96229
  // Discovery may read a worktree pointer under a root the store
95931
96230
  // already allows, so a revoked checkout root still surfaces.
95932
96231
  findProtectedSessions: () => findRecentProtectedSessions({
@@ -95959,16 +96258,17 @@ ${USAGE}`);
95959
96258
  set: (enabled) => setAutomaticUpdates(config2.appEnv, enabled),
95960
96259
  promptLine: realPromptLine
95961
96260
  },
95962
- connect: () => connect3((line) => terminal.log(` ${line}`)),
96261
+ connect: () => connect3(terminal.stage),
95963
96262
  menubarApp: managesMenubarApp(config2) ? () => syncMenubarApp(thisInstallMenubarAppOps(), "init") : null,
95964
96263
  connectCommand,
95965
96264
  environmentName: config2.appEnv,
95966
96265
  webUrl: config2.webUrl
95967
96266
  });
96267
+ process.exitCode = initExitCode(summary);
95968
96268
  return;
95969
96269
  }
95970
96270
  case "connect": {
95971
- const outcome = await connect3(console.log);
96271
+ const outcome = await connect3(terminal.command);
95972
96272
  if (outcome.pending > 0) {
95973
96273
  console.log(`Some logins are unfinished, re-run \`${connectCommand}\` any time.`);
95974
96274
  }
@@ -95983,6 +96283,7 @@ ${USAGE}`);
95983
96283
  return;
95984
96284
  }
95985
96285
  const outcome = runDisconnect(clients, {
96286
+ onDisconnected: (client) => recordMcpChoices(config2.appEnv, [client], []),
95986
96287
  log: console.log,
95987
96288
  serverName: mcpServerNameFor(config2.appEnv),
95988
96289
  disconnectCommand,
@@ -96001,8 +96302,14 @@ The access you granted these agents stays on your Powerplant account until you r
96001
96302
  return;
96002
96303
  }
96003
96304
  case "enroll": {
96004
- await enroll2();
96005
- await offerResume(pause, { log: console.log, indent: "", promptAllowed: pickerOn });
96305
+ const credentials = await terminal.command.activity(
96306
+ "Waiting for approval in your browser\u2026",
96307
+ () => enroll2(terminal.command.detail)
96308
+ );
96309
+ terminal.command.log(enrolledLine(credentials));
96310
+ terminal.command.detail(`Syncing: ${describeStoredCapture(credentials)}`);
96311
+ const offer = await offerResume(pause, { output: terminal.command, promptAllowed: pickerOn });
96312
+ if (offer === "still-paused") process.exitCode = 1;
96006
96313
  return;
96007
96314
  }
96008
96315
  case "status": {
@@ -96069,8 +96376,9 @@ The access you granted these agents stays on your Powerplant account until you r
96069
96376
  const budget = menuBudget;
96070
96377
  const saved = loadDetectedClients(realReadTextFile);
96071
96378
  const probePath = mergedPath(process.env.PATH, saved);
96379
+ const detected = detectClients({ whichAll: whichAllWith(probePath), budget, requireCursorApp: process.platform === "darwin" });
96072
96380
  const clients = mergeDetectedClients(
96073
- detectClients({ whichAll: whichAllWith(probePath), budget }),
96381
+ detected,
96074
96382
  saved,
96075
96383
  existsSync14
96076
96384
  );
@@ -96116,6 +96424,8 @@ The access you granted these agents stays on your Powerplant account until you r
96116
96424
  control: readCollectorControl(config2.appEnv),
96117
96425
  latestVersion,
96118
96426
  oldestSupportedVersion,
96427
+ ...readMcpPreferencesForMenu(config2.appEnv),
96428
+ ...readHookPreferencesForMenu(config2.appEnv),
96119
96429
  connections: probeConnections(clients, {
96120
96430
  mcpUrl: `${config2.apiUrl}/mcp`,
96121
96431
  serverName: mcpServerNameFor(config2.appEnv),
@@ -96135,6 +96445,27 @@ The access you granted these agents stays on your Powerplant account until you r
96135
96445
  console.log(JSON.stringify(payload));
96136
96446
  return;
96137
96447
  }
96448
+ case "report-agent-click": {
96449
+ const parsed2 = menubarAgentClickSchema.safeParse({ source: positionals[1], destination: positionals[2] });
96450
+ if (!parsed2.success) throw new ExpectedCliError("Expected an agent source and menu destination.");
96451
+ const stored = loadCredentialsSafely(config2);
96452
+ if (!await reportMenubarEvent({ event: MENUBAR_AGENT_CLICK, ...parsed2.data }, stored.credentials, console.error)) process.exitCode = 1;
96453
+ return;
96454
+ }
96455
+ case "dismiss-codex-hook-warning": {
96456
+ dismissCodexHookWarning(config2.appEnv);
96457
+ return;
96458
+ }
96459
+ case "dismiss-mcp-warning": {
96460
+ const parsed2 = mcpWarningDismissalSchema.safeParse({ client: positionals[1], warning: positionals[2] });
96461
+ if (!parsed2.success) throw new ExpectedCliError("Expected a client and MCP warning type to dismiss.");
96462
+ if (dismissMcpWarning(config2.appEnv, parsed2.data)) {
96463
+ const stored = loadCredentialsSafely(config2);
96464
+ if (stored.credentialsError) console.error(JSON.stringify({ level: "warn", runId: randomUUID4(), operation: "menubar-analytics", outcome: "credentials-unavailable" }));
96465
+ await reportMenubarEvent({ event: MENUBAR_MCP_WARNING_REMOVE, ...parsed2.data }, stored.credentials, console.error);
96466
+ }
96467
+ return;
96468
+ }
96138
96469
  // Which workspace this account resolves to — the web app and the MCP
96139
96470
  // follow it. Needs the machine credential only to name the member.
96140
96471
  case "workspace": {
@@ -96291,7 +96622,8 @@ ${USAGE}`);
96291
96622
  }
96292
96623
  }
96293
96624
  function styledFor(stream) {
96294
- return terminalUsesEffects(stream.isTTY === true, process.env) ? styleLine : (line) => line;
96625
+ if (!terminalUsesEffects(stream.isTTY === true, process.env)) return (line) => line;
96626
+ return (line) => styleLine(line, { level: "command", detail: line.startsWith(" ") });
96295
96627
  }
96296
96628
  function oldestSupportedFor(credentials) {
96297
96629
  return credentials === null ? Promise.resolve(null) : fetchOldestSupportedVersion(credentials.apiUrl, credentials.token);
@@ -96353,7 +96685,7 @@ function startBackgroundUpdate(config2, target) {
96353
96685
  readProgress: updateProgress.read,
96354
96686
  writeProgress: updateProgress.write,
96355
96687
  spawnChild: () => {
96356
- mkdirSync14(path31.dirname(updateLogPath()), { recursive: true });
96688
+ mkdirSync16(path33.dirname(updateLogPath()), { recursive: true });
96357
96689
  const log3 = openSync9(updateLogPath(), "a");
96358
96690
  const child = spawn3(process.execPath, [entryPath(), "update", ...envArgsFor(config2)], {
96359
96691
  detached: true,
@@ -96378,7 +96710,7 @@ function automaticUpdateCheck(config2) {
96378
96710
  "daemon"
96379
96711
  );
96380
96712
  if (app.kind === "updated") log3(`menu bar app updated to ${CLI_VERSION}`);
96381
- if (app.kind === "failed") log3(`\u26A0 menu bar app could not be updated: ${app.detail}`);
96713
+ if (app.kind === "failed") log3(`! menu bar app could not be updated: ${app.detail}`);
96382
96714
  }
96383
96715
  const decision = autoUpdateDecision({
96384
96716
  control: readCollectorControl(config2.appEnv),
@@ -96443,7 +96775,7 @@ var cliCommand = "none";
96443
96775
  main().catch(async (error63) => {
96444
96776
  if (error63 instanceof ExpectedCliError) {
96445
96777
  console.error(
96446
- terminalUsesEffects(process.stderr.isTTY === true, process.env) ? styleLine(error63.message) : error63.message
96778
+ terminalUsesEffects(process.stderr.isTTY === true, process.env) ? styleLine(error63.message, { level: "command", detail: false }) : error63.message
96447
96779
  );
96448
96780
  } else {
96449
96781
  console.error(error63);
@@ -96462,4 +96794,4 @@ undici/lib/web/websocket/frame.js:
96462
96794
  (*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
96463
96795
  */
96464
96796
 
96465
- //# debugId=66f773d5-e0b2-5538-a184-3ee15c3a469a
96797
+ //# debugId=bdd42bb0-e20a-5100-a257-b6dbb21d0f74