@phenx-inc/ctlsurf 0.17.1 → 0.17.3

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.
Files changed (52) hide show
  1. package/README.md +25 -2
  2. package/bin/ctlsurf-worker.js +24 -0
  3. package/out/headless/index.mjs +1033 -128
  4. package/out/headless/index.mjs.map +4 -4
  5. package/out/main/index.js +929 -17
  6. package/out/preload/index.js +15 -0
  7. package/out/renderer/assets/{cssMode-BtQxI2Eb.js → cssMode-BJfoToLX.js} +3 -3
  8. package/out/renderer/assets/{freemarker2-DRW5dmY5.js → freemarker2-T0eMtP1Z.js} +1 -1
  9. package/out/renderer/assets/{handlebars-CFLF3cP7.js → handlebars-Dbbib8fi.js} +1 -1
  10. package/out/renderer/assets/{html-DtnBOkwp.js → html-BRHT_oxc.js} +1 -1
  11. package/out/renderer/assets/{htmlMode-DMVysDCg.js → htmlMode-BRlZTxME.js} +3 -3
  12. package/out/renderer/assets/{index-CEjwKjtd.css → index-CBWAeUYW.css} +91 -0
  13. package/out/renderer/assets/{index-Dm70hk5s.js → index-RCAeuJTr.js} +476 -411
  14. package/out/renderer/assets/{javascript-ChlyA1sf.js → javascript-BbOZOxq9.js} +2 -2
  15. package/out/renderer/assets/{jsonMode-D1_oHzeN.js → jsonMode-CUvAeYcT.js} +3 -3
  16. package/out/renderer/assets/{liquid-D4ftdy1G.js → liquid-DRIACo_s.js} +1 -1
  17. package/out/renderer/assets/{lspLanguageFeatures-Ckqu5ubG.js → lspLanguageFeatures-Ds-3nH9p.js} +1 -1
  18. package/out/renderer/assets/{mdx-B9wsVYSC.js → mdx-D76jlpLO.js} +1 -1
  19. package/out/renderer/assets/{python-e23tD6IS.js → python-CMuRPKJi.js} +1 -1
  20. package/out/renderer/assets/{razor-CrDyXj3d.js → razor-DRoH5mal.js} +1 -1
  21. package/out/renderer/assets/{tsMode-BwGC5o4O.js → tsMode-dPJzgFD7.js} +1 -1
  22. package/out/renderer/assets/{typescript-Do-98d_O.js → typescript-D5USKnLj.js} +1 -1
  23. package/out/renderer/assets/{xml-Dpdu5R3m.js → xml-qYg1wt2P.js} +1 -1
  24. package/out/renderer/assets/{yaml-B0Zt7LCJ.js → yaml-Uc-CvnvL.js} +1 -1
  25. package/out/renderer/index.html +2 -2
  26. package/package.json +4 -2
  27. package/scripts/check-work-map-gpu.cjs +62 -0
  28. package/scripts/check-work-map-gpu.d.cts +13 -0
  29. package/scripts/postinstall.cjs +15 -0
  30. package/scripts/prepare-work-map.py +37 -0
  31. package/scripts/test-work-map-capability.cjs +45 -0
  32. package/scripts/test-work-map-ui.cjs +130 -0
  33. package/scripts/test-work-map.cjs +352 -0
  34. package/scripts/work-map-clef.py +81 -0
  35. package/src/main/index.ts +35 -1
  36. package/src/main/observer/observer.ts +2 -0
  37. package/src/main/orchestrator.ts +39 -4
  38. package/src/main/transcripts.ts +35 -16
  39. package/src/main/workMap/clef.ts +156 -0
  40. package/src/main/workMap/normalize.ts +172 -0
  41. package/src/main/workMap/source.ts +28 -0
  42. package/src/main/workMap/tree.ts +199 -0
  43. package/src/main/workMap/workMap.ts +244 -0
  44. package/src/preload/index.ts +17 -0
  45. package/src/renderer/App.tsx +15 -16
  46. package/src/renderer/components/ObserverPanel.tsx +3 -0
  47. package/src/renderer/components/SettingsDialog.tsx +0 -104
  48. package/src/renderer/components/WorkMapPanel.tsx +235 -0
  49. package/src/renderer/components/WorkMapToggle.tsx +50 -0
  50. package/src/renderer/lib/workMapHighlights.ts +41 -0
  51. package/src/renderer/styles.css +91 -0
  52. package/src/shared/workMap.d.ts +70 -0
@@ -6386,15 +6386,15 @@ function redactSensitive(body) {
6386
6386
  }
6387
6387
  return null;
6388
6388
  }
6389
- async function checkCredentialsFileSafety(path13, onWarn = (m) => console.warn(`anthropic-sdk: ${m}`)) {
6389
+ async function checkCredentialsFileSafety(path17, onWarn = (m) => console.warn(`anthropic-sdk: ${m}`)) {
6390
6390
  if (typeof process === "undefined" || process.platform === "win32")
6391
6391
  return;
6392
- const fs9 = await import("node:fs");
6393
- let resolved = path13;
6392
+ const fs12 = await import("node:fs");
6393
+ let resolved = path17;
6394
6394
  let st;
6395
6395
  try {
6396
- resolved = await fs9.promises.realpath(path13);
6397
- st = await fs9.promises.stat(resolved);
6396
+ resolved = await fs12.promises.realpath(path17);
6397
+ st = await fs12.promises.stat(resolved);
6398
6398
  } catch {
6399
6399
  return;
6400
6400
  }
@@ -6410,27 +6410,27 @@ async function checkCredentialsFileSafety(path13, onWarn = (m) => console.warn(`
6410
6410
  }
6411
6411
  }
6412
6412
  async function writeCredentialsFileAtomic(targetPath, data) {
6413
- const fs9 = await import("node:fs");
6414
- const path13 = await import("node:path");
6415
- const dir = path13.dirname(targetPath);
6416
- await fs9.promises.mkdir(dir, { recursive: true, mode: 448 });
6413
+ const fs12 = await import("node:fs");
6414
+ const path17 = await import("node:path");
6415
+ const dir = path17.dirname(targetPath);
6416
+ await fs12.promises.mkdir(dir, { recursive: true, mode: 448 });
6417
6417
  const tmpPath = `${targetPath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
6418
6418
  try {
6419
- const fh = await fs9.promises.open(tmpPath, "w", 384);
6419
+ const fh = await fs12.promises.open(tmpPath, "w", 384);
6420
6420
  try {
6421
6421
  await fh.writeFile(JSON.stringify(data, null, 2));
6422
6422
  await fh.sync();
6423
6423
  } finally {
6424
6424
  await fh.close();
6425
6425
  }
6426
- await fs9.promises.rename(tmpPath, targetPath);
6426
+ await fs12.promises.rename(tmpPath, targetPath);
6427
6427
  } catch (err) {
6428
- await fs9.promises.unlink(tmpPath).catch(() => {
6428
+ await fs12.promises.unlink(tmpPath).catch(() => {
6429
6429
  });
6430
6430
  throw err;
6431
6431
  }
6432
6432
  try {
6433
- const dirFh = await fs9.promises.open(dir, "r");
6433
+ const dirFh = await fs12.promises.open(dir, "r");
6434
6434
  try {
6435
6435
  await dirFh.sync();
6436
6436
  } finally {
@@ -6794,12 +6794,12 @@ var init_credentials = __esm({
6794
6794
  return null;
6795
6795
  }
6796
6796
  validateProfileName(profileName);
6797
- const fs9 = await import("node:fs");
6798
- const path13 = await import("node:path");
6799
- const configPath = path13.join(rootConfigPath, "configs", `${profileName}.json`);
6797
+ const fs12 = await import("node:fs");
6798
+ const path17 = await import("node:path");
6799
+ const configPath = path17.join(rootConfigPath, "configs", `${profileName}.json`);
6800
6800
  let configRaw;
6801
6801
  try {
6802
- configRaw = await fs9.promises.readFile(configPath, "utf-8");
6802
+ configRaw = await fs12.promises.readFile(configPath, "utf-8");
6803
6803
  } catch (err) {
6804
6804
  if (err?.code !== "ENOENT") {
6805
6805
  throw new Error(`failed to read config file ${configPath}: ${err}`);
@@ -6880,37 +6880,37 @@ var init_credentials = __esm({
6880
6880
  return null;
6881
6881
  }
6882
6882
  validateProfileName(profileName);
6883
- const path13 = await import("node:path");
6884
- return path13.join(rootConfigPath, "credentials", `${profileName}.json`);
6883
+ const path17 = await import("node:path");
6884
+ return path17.join(rootConfigPath, "credentials", `${profileName}.json`);
6885
6885
  };
6886
6886
  getRootConfigPath = async () => {
6887
6887
  if (!supportsLocalConfigFiles()) {
6888
6888
  return null;
6889
6889
  }
6890
- const path13 = await import("node:path");
6890
+ const path17 = await import("node:path");
6891
6891
  const configDir = readEnv("ANTHROPIC_CONFIG_DIR");
6892
6892
  if (configDir) {
6893
6893
  return configDir;
6894
6894
  }
6895
- const os7 = getPlatformHeaders()["X-Stainless-OS"];
6896
- if (os7 === "Windows") {
6895
+ const os8 = getPlatformHeaders()["X-Stainless-OS"];
6896
+ if (os8 === "Windows") {
6897
6897
  const appData = readEnv("APPDATA");
6898
6898
  if (appData) {
6899
- return path13.join(appData, "Anthropic");
6899
+ return path17.join(appData, "Anthropic");
6900
6900
  }
6901
6901
  const userProfile = readEnv("USERPROFILE");
6902
6902
  if (userProfile) {
6903
- return path13.join(userProfile, "AppData", "Roaming", "Anthropic");
6903
+ return path17.join(userProfile, "AppData", "Roaming", "Anthropic");
6904
6904
  }
6905
6905
  return null;
6906
6906
  }
6907
6907
  const xdgConfigHome = readEnv("XDG_CONFIG_HOME");
6908
6908
  if (xdgConfigHome) {
6909
- return path13.join(xdgConfigHome, "anthropic");
6909
+ return path17.join(xdgConfigHome, "anthropic");
6910
6910
  }
6911
6911
  const home = readEnv("HOME");
6912
6912
  if (home) {
6913
- return path13.join(home, ".config", "anthropic");
6913
+ return path17.join(home, ".config", "anthropic");
6914
6914
  }
6915
6915
  return null;
6916
6916
  };
@@ -6927,11 +6927,11 @@ var init_credentials = __esm({
6927
6927
  if (profileName) {
6928
6928
  return profileName;
6929
6929
  }
6930
- const fs9 = await import("node:fs");
6931
- const path13 = await import("node:path");
6932
- const filePath = path13.join(rootConfigPath, "active_config");
6930
+ const fs12 = await import("node:fs");
6931
+ const path17 = await import("node:path");
6932
+ const filePath = path17.join(rootConfigPath, "active_config");
6933
6933
  try {
6934
- return (await fs9.promises.readFile(filePath, "utf-8")).trim() || "default";
6934
+ return (await fs12.promises.readFile(filePath, "utf-8")).trim() || "default";
6935
6935
  } catch (err) {
6936
6936
  if (err?.code !== "ENOENT") {
6937
6937
  throw new Error(`failed to read ${filePath}: ${err}`);
@@ -6943,21 +6943,21 @@ var init_credentials = __esm({
6943
6943
  });
6944
6944
 
6945
6945
  // node_modules/@anthropic-ai/sdk/lib/credentials/identity-token.mjs
6946
- function identityTokenFromFile(path13) {
6947
- if (!path13) {
6946
+ function identityTokenFromFile(path17) {
6947
+ if (!path17) {
6948
6948
  throw new AnthropicError("Identity token file path is empty");
6949
6949
  }
6950
6950
  return async () => {
6951
- const fs9 = await import("node:fs");
6951
+ const fs12 = await import("node:fs");
6952
6952
  let content;
6953
6953
  try {
6954
- content = await fs9.promises.readFile(path13, "utf-8");
6954
+ content = await fs12.promises.readFile(path17, "utf-8");
6955
6955
  } catch (err) {
6956
- throw new AnthropicError(`Failed to read identity token file at ${path13}: ${err}`);
6956
+ throw new AnthropicError(`Failed to read identity token file at ${path17}: ${err}`);
6957
6957
  }
6958
6958
  const token = content.trim();
6959
6959
  if (!token) {
6960
- throw new AnthropicError(`Identity token file at ${path13} is empty`);
6960
+ throw new AnthropicError(`Identity token file at ${path17} is empty`);
6961
6961
  }
6962
6962
  return token;
6963
6963
  };
@@ -7042,11 +7042,11 @@ var init_oidc_federation = __esm({
7042
7042
  // node_modules/@anthropic-ai/sdk/lib/credentials/user-oauth.mjs
7043
7043
  function userOAuthProvider(config) {
7044
7044
  return async (opts) => {
7045
- const fs9 = await import("node:fs");
7045
+ const fs12 = await import("node:fs");
7046
7046
  await checkCredentialsFileSafety(config.credentialsPath, config.onSafetyWarning);
7047
7047
  let raw;
7048
7048
  try {
7049
- raw = await fs9.promises.readFile(config.credentialsPath, "utf-8");
7049
+ raw = await fs12.promises.readFile(config.credentialsPath, "utf-8");
7050
7050
  } catch (err) {
7051
7051
  throw new WorkloadIdentityError(`Credentials file not found at ${config.credentialsPath}: ${err}`);
7052
7052
  }
@@ -7218,11 +7218,11 @@ function resolveIdentityTokenProvider(auth) {
7218
7218
  }
7219
7219
  function cachedExchangeProvider(exchange, credentialsPath, onCacheWriteError, onSafetyWarning) {
7220
7220
  return async (opts) => {
7221
- const fs9 = await import("node:fs");
7221
+ const fs12 = await import("node:fs");
7222
7222
  await checkCredentialsFileSafety(credentialsPath, onSafetyWarning);
7223
7223
  let existing;
7224
7224
  try {
7225
- const raw = await fs9.promises.readFile(credentialsPath, "utf-8");
7225
+ const raw = await fs12.promises.readFile(credentialsPath, "utf-8");
7226
7226
  existing = JSON.parse(raw);
7227
7227
  const token = existing?.["access_token"];
7228
7228
  if (token && !opts?.forceRefresh) {
@@ -8282,12 +8282,12 @@ var init_path = __esm({
8282
8282
  "node_modules/@anthropic-ai/sdk/internal/utils/path.mjs"() {
8283
8283
  init_error();
8284
8284
  EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
8285
- createPathTagFunction = (pathEncoder = encodeURIPath) => function path13(statics, ...params) {
8285
+ createPathTagFunction = (pathEncoder = encodeURIPath) => function path17(statics, ...params) {
8286
8286
  if (statics.length === 1)
8287
8287
  return statics[0];
8288
8288
  let postPath = false;
8289
8289
  const invalidSegments = [];
8290
- const path14 = statics.reduce((previousValue, currentValue, index) => {
8290
+ const path18 = statics.reduce((previousValue, currentValue, index) => {
8291
8291
  if (/[?#]/.test(currentValue)) {
8292
8292
  postPath = true;
8293
8293
  }
@@ -8304,7 +8304,7 @@ var init_path = __esm({
8304
8304
  }
8305
8305
  return previousValue + currentValue + (index === params.length ? "" : encoded);
8306
8306
  }, "");
8307
- const pathOnly = path14.split(/[?#]/, 1)[0];
8307
+ const pathOnly = path18.split(/[?#]/, 1)[0];
8308
8308
  const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
8309
8309
  let match;
8310
8310
  while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
@@ -8325,10 +8325,10 @@ var init_path = __esm({
8325
8325
  }, "");
8326
8326
  throw new AnthropicError(`Path parameters result in path with invalid segments:
8327
8327
  ${invalidSegments.map((e) => e.error).join("\n")}
8328
- ${path14}
8328
+ ${path18}
8329
8329
  ${underline}`);
8330
8330
  }
8331
- return path14;
8331
+ return path18;
8332
8332
  };
8333
8333
  path5 = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
8334
8334
  }
@@ -16818,9 +16818,9 @@ var init_client = __esm({
16818
16818
  makeStatusError(status, error, message, headers) {
16819
16819
  return APIError.generate(status, error, message, headers);
16820
16820
  }
16821
- buildURL(path13, query, defaultBaseURL) {
16821
+ buildURL(path17, query, defaultBaseURL) {
16822
16822
  const baseURL = !__classPrivateFieldGet(this, _BaseAnthropic_instances, "m", _BaseAnthropic_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
16823
- const url = isAbsoluteURL(path13) ? new URL(path13) : new URL(baseURL + (baseURL.endsWith("/") && path13.startsWith("/") ? path13.slice(1) : path13));
16823
+ const url = isAbsoluteURL(path17) ? new URL(path17) : new URL(baseURL + (baseURL.endsWith("/") && path17.startsWith("/") ? path17.slice(1) : path17));
16824
16824
  const defaultQuery = this.defaultQuery();
16825
16825
  const pathQuery = Object.fromEntries(url.searchParams);
16826
16826
  if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
@@ -16892,24 +16892,24 @@ var init_client = __esm({
16892
16892
  backendMiddleware() {
16893
16893
  return [];
16894
16894
  }
16895
- get(path13, opts) {
16896
- return this.methodRequest("get", path13, opts);
16895
+ get(path17, opts) {
16896
+ return this.methodRequest("get", path17, opts);
16897
16897
  }
16898
- post(path13, opts) {
16899
- return this.methodRequest("post", path13, opts);
16898
+ post(path17, opts) {
16899
+ return this.methodRequest("post", path17, opts);
16900
16900
  }
16901
- patch(path13, opts) {
16902
- return this.methodRequest("patch", path13, opts);
16901
+ patch(path17, opts) {
16902
+ return this.methodRequest("patch", path17, opts);
16903
16903
  }
16904
- put(path13, opts) {
16905
- return this.methodRequest("put", path13, opts);
16904
+ put(path17, opts) {
16905
+ return this.methodRequest("put", path17, opts);
16906
16906
  }
16907
- delete(path13, opts) {
16908
- return this.methodRequest("delete", path13, opts);
16907
+ delete(path17, opts) {
16908
+ return this.methodRequest("delete", path17, opts);
16909
16909
  }
16910
- methodRequest(method, path13, opts) {
16910
+ methodRequest(method, path17, opts) {
16911
16911
  return this.request(Promise.resolve(opts).then((opts2) => {
16912
- return { method, path: path13, ...opts2 };
16912
+ return { method, path: path17, ...opts2 };
16913
16913
  }));
16914
16914
  }
16915
16915
  request(options, remainingRetries = null) {
@@ -17023,8 +17023,8 @@ var init_client = __esm({
17023
17023
  }));
17024
17024
  return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
17025
17025
  }
17026
- getAPIList(path13, Page2, opts) {
17027
- return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path13, ...opts2 })) : { method: "get", path: path13, ...opts });
17026
+ getAPIList(path17, Page2, opts) {
17027
+ return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path17, ...opts2 })) : { method: "get", path: path17, ...opts });
17028
17028
  }
17029
17029
  requestAPIList(Page2, options) {
17030
17030
  const request = this.makeRequest(options, null, void 0);
@@ -17140,14 +17140,14 @@ var init_client = __esm({
17140
17140
  }
17141
17141
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
17142
17142
  const options = { ...inputOptions };
17143
- const { method, path: path13, query, defaultBaseURL } = options;
17143
+ const { method, path: path17, query, defaultBaseURL } = options;
17144
17144
  if (this._authState.resolution) {
17145
17145
  await this._authState.resolution;
17146
17146
  }
17147
17147
  if (!this._baseURLIsExplicit && this._authState.baseURL && this.baseURL !== this._authState.baseURL) {
17148
17148
  this.baseURL = this._authState.baseURL;
17149
17149
  }
17150
- const url = this.buildURL(path13, query, defaultBaseURL);
17150
+ const url = this.buildURL(path17, query, defaultBaseURL);
17151
17151
  if ("timeout" in options)
17152
17152
  validatePositiveInteger("timeout", options.timeout);
17153
17153
  options.timeout = options.timeout ?? this.timeout;
@@ -17285,22 +17285,89 @@ var init_sdk = __esm({
17285
17285
  }
17286
17286
  });
17287
17287
 
17288
+ // scripts/check-work-map-gpu.cjs
17289
+ var require_check_work_map_gpu = __commonJS({
17290
+ "scripts/check-work-map-gpu.cjs"(exports, module) {
17291
+ function initialCapability3({ desktop = false, platform = process.platform, arch = process.arch } = {}) {
17292
+ if (!desktop) return { state: "unavailable", reason: "Work map is available only in the desktop app." };
17293
+ if (platform !== "darwin" || arch !== "arm64") return { state: "unavailable", reason: "Work map currently requires an Apple Silicon Mac with Metal GPU support." };
17294
+ return { state: "checking", reason: "Checking Apple GPU availability\u2026" };
17295
+ }
17296
+ function appleGpuFromReport(report) {
17297
+ if (!Array.isArray(report?.SPDisplaysDataType)) return null;
17298
+ return report.SPDisplaysDataType.find((gpu) => {
17299
+ const apple = gpu.spdisplays_vendor === "sppci_vendor_Apple" || /^Apple M\d/i.test(gpu.sppci_model || gpu._name || "");
17300
+ const metal = String(gpu.spdisplays_metal || gpu.spdisplays_metalsupport || gpu.spdisplays_mtlgpufamilysupport || "");
17301
+ return apple && /supported|metal/i.test(metal) && !/unsupported|not.supported|unavailable/i.test(metal);
17302
+ }) || null;
17303
+ }
17304
+ function usableElectronGpu(info) {
17305
+ if (info?.auxAttributes?.softwareRendering === true) return false;
17306
+ return Array.isArray(info?.gpuDevice) && info.gpuDevice.some((gpu) => gpu.active === true && (gpu.vendorId === 4203 || /Apple/i.test(gpu.deviceString || gpu.vendorString || "")));
17307
+ }
17308
+ function readGpuReport() {
17309
+ return new Promise((resolve4, reject) => {
17310
+ const { execFile: execFile3 } = __require("node:child_process");
17311
+ execFile3("/usr/sbin/system_profiler", ["SPDisplaysDataType", "-json"], { timeout: 5e3, maxBuffer: 1024 * 1024 }, (error, output) => {
17312
+ if (error) {
17313
+ reject(error);
17314
+ return;
17315
+ }
17316
+ try {
17317
+ resolve4(JSON.parse(output));
17318
+ } catch (error2) {
17319
+ reject(error2);
17320
+ }
17321
+ });
17322
+ });
17323
+ }
17324
+ async function detectCapability(options = {}) {
17325
+ const initial = initialCapability3(options);
17326
+ if (initial.state !== "checking") return initial;
17327
+ try {
17328
+ const gpu = appleGpuFromReport(await (options.readGpuReport || readGpuReport)());
17329
+ if (!gpu) return { state: "unavailable", reason: "No Apple GPU with Metal support was detected." };
17330
+ if (options.verifyGpu) {
17331
+ let timer;
17332
+ const usable = await Promise.race([
17333
+ options.verifyGpu(),
17334
+ new Promise((resolve4) => {
17335
+ timer = setTimeout(() => resolve4(false), 5e3);
17336
+ })
17337
+ ]).finally(() => clearTimeout(timer));
17338
+ if (!usable) return { state: "unavailable", reason: "The Apple GPU is unavailable to the desktop app." };
17339
+ }
17340
+ return { state: "available", reason: null, gpuName: String(gpu.sppci_model || gpu._name || "Apple GPU") };
17341
+ } catch {
17342
+ return { state: "unavailable", reason: "Apple GPU availability could not be verified. Work map is disabled for this launch." };
17343
+ }
17344
+ }
17345
+ module.exports = { initialCapability: initialCapability3, appleGpuFromReport, usableElectronGpu, detectCapability };
17346
+ if (__require.main === module) {
17347
+ detectCapability({ desktop: true }).then((capability) => {
17348
+ console.log(capability.state === "available" ? `[ctlsurf] Work map hardware detected: ${capability.gpuName}. The desktop app checks GPU access again at startup.` : `[ctlsurf] ${capability.reason} Other app features remain available.`);
17349
+ }).catch(() => {
17350
+ });
17351
+ }
17352
+ }
17353
+ });
17354
+
17288
17355
  // node_modules/electron/index.js
17289
17356
  var require_electron = __commonJS({
17290
17357
  "node_modules/electron/index.js"(exports, module) {
17291
- var fs9 = __require("fs");
17292
- var path13 = __require("path");
17293
- var pathFile = path13.join(__dirname, "path.txt");
17358
+ var fs12 = __require("fs");
17359
+ var path17 = __require("path");
17360
+ var pathFile = path17.join(__dirname, "path.txt");
17294
17361
  function getElectronPath() {
17295
17362
  let executablePath;
17296
- if (fs9.existsSync(pathFile)) {
17297
- executablePath = fs9.readFileSync(pathFile, "utf-8");
17363
+ if (fs12.existsSync(pathFile)) {
17364
+ executablePath = fs12.readFileSync(pathFile, "utf-8");
17298
17365
  }
17299
17366
  if (process.env.ELECTRON_OVERRIDE_DIST_PATH) {
17300
- return path13.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath || "electron");
17367
+ return path17.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath || "electron");
17301
17368
  }
17302
17369
  if (executablePath) {
17303
- return path13.join(__dirname, "dist", executablePath);
17370
+ return path17.join(__dirname, "dist", executablePath);
17304
17371
  } else {
17305
17372
  throw new Error("Electron failed to install correctly, please delete node_modules/electron and try installing again");
17306
17373
  }
@@ -17314,7 +17381,7 @@ var require_package = __commonJS({
17314
17381
  "package.json"(exports, module) {
17315
17382
  module.exports = {
17316
17383
  name: "@phenx-inc/ctlsurf",
17317
- version: "0.17.1",
17384
+ version: "0.17.3",
17318
17385
  description: "Agent-agnostic terminal and desktop app for ctlsurf \u2014 run Claude Code, Codex, or any coding agent with live session logging and remote control",
17319
17386
  main: "out/main/index.js",
17320
17387
  bin: {
@@ -17333,6 +17400,8 @@ var require_package = __commonJS({
17333
17400
  "THIRD-PARTY-NOTICES.md"
17334
17401
  ],
17335
17402
  scripts: {
17403
+ "test:workmap": "node scripts/test-work-map-capability.cjs && node scripts/test-work-map.cjs",
17404
+ "test:workmap:ui": "electron scripts/test-work-map-ui.cjs",
17336
17405
  dev: "electron-vite dev",
17337
17406
  "dev:terminal": "esbuild src/main/headless.ts --bundle --platform=node --target=node18 --format=esm --outfile=out/headless/index.mjs --external:node-pty --external:ws --sourcemap && node out/headless/index.mjs",
17338
17407
  build: "electron-vite build && npm run build:headless",
@@ -17340,7 +17409,7 @@ var require_package = __commonJS({
17340
17409
  prepublishOnly: "npm run build",
17341
17410
  preview: "electron-vite preview",
17342
17411
  package: "electron-builder",
17343
- postinstall: "node-gyp rebuild --directory=node_modules/node-pty 2>/dev/null || true"
17412
+ postinstall: "node scripts/postinstall.cjs"
17344
17413
  },
17345
17414
  keywords: [
17346
17415
  "ctlsurf",
@@ -17417,9 +17486,9 @@ function log(...args) {
17417
17486
  }
17418
17487
 
17419
17488
  // src/main/orchestrator.ts
17420
- import path10 from "path";
17421
- import fs7 from "fs";
17422
- import os4 from "os";
17489
+ import path14 from "path";
17490
+ import fs10 from "fs";
17491
+ import os5 from "os";
17423
17492
 
17424
17493
  // src/main/pty.ts
17425
17494
  import { createRequire } from "module";
@@ -17568,8 +17637,8 @@ var CtlsurfApi = class {
17568
17637
  }
17569
17638
  return h;
17570
17639
  }
17571
- async request(method, path13, body) {
17572
- const url = `${this.baseUrl}${path13}`;
17640
+ async request(method, path17, body) {
17641
+ const url = `${this.baseUrl}${path17}`;
17573
17642
  const opts = {
17574
17643
  method,
17575
17644
  headers: this.headers()
@@ -17580,7 +17649,7 @@ var CtlsurfApi = class {
17580
17649
  const res = await fetch(url, opts);
17581
17650
  if (!res.ok) {
17582
17651
  const text = await res.text();
17583
- throw new Error(`ctlsurf API ${method} ${path13}: ${res.status} ${text}`);
17652
+ throw new Error(`ctlsurf API ${method} ${path17}: ${res.status} ${text}`);
17584
17653
  }
17585
17654
  return res.json();
17586
17655
  }
@@ -17968,6 +18037,7 @@ ${str.slice(str.length - MAX_LOG_CHARS)}`;
17968
18037
  import fs from "fs";
17969
18038
  import path from "path";
17970
18039
  import os from "os";
18040
+ import { StringDecoder } from "string_decoder";
17971
18041
  function supportsTranscriptLogging(agentId) {
17972
18042
  return agentId === "claude" || agentId === "codex";
17973
18043
  }
@@ -17975,6 +18045,8 @@ var POLL_INTERVAL_MS = 1e3;
17975
18045
  var DISCOVERY_SLACK_MS = 1e4;
17976
18046
  var READ_CHUNK_BYTES = 64 * 1024;
17977
18047
  var MAX_ENTRY_CHARS = 2e4;
18048
+ var MAX_READ_PER_POLL = 512 * 1024;
18049
+ var MAX_LINE_CHARS = 1024 * 1024;
17978
18050
  var TranscriptTailer = class {
17979
18051
  agentId;
17980
18052
  cwd;
@@ -18042,7 +18114,7 @@ var TranscriptTailer = class {
18042
18114
  try {
18043
18115
  const stat2 = fs.statSync(filePath);
18044
18116
  if (stat2.mtimeMs >= this.sinceMs - DISCOVERY_SLACK_MS) {
18045
- this.files.set(filePath, { offset: 0, remainder: "", excluded: false });
18117
+ this.files.set(filePath, { offset: 0, remainder: "", excluded: false, decoder: new StringDecoder("utf8"), discardingLine: false, scoped: this.agentId === "claude" });
18046
18118
  }
18047
18119
  } catch {
18048
18120
  }
@@ -18072,7 +18144,14 @@ var TranscriptTailer = class {
18072
18144
  } catch {
18073
18145
  return;
18074
18146
  }
18075
- if (size <= tail.offset) return;
18147
+ if (size < tail.offset) {
18148
+ tail.offset = 0;
18149
+ tail.remainder = "";
18150
+ tail.decoder = new StringDecoder("utf8");
18151
+ tail.discardingLine = false;
18152
+ tail.scoped = this.agentId === "claude";
18153
+ }
18154
+ if (size === tail.offset) return;
18076
18155
  let fd;
18077
18156
  try {
18078
18157
  fd = fs.openSync(filePath, "r");
@@ -18081,17 +18160,26 @@ var TranscriptTailer = class {
18081
18160
  }
18082
18161
  try {
18083
18162
  const buf = Buffer.alloc(READ_CHUNK_BYTES);
18084
- while (tail.offset < size && !tail.excluded) {
18085
- const bytesRead = fs.readSync(fd, buf, 0, READ_CHUNK_BYTES, tail.offset);
18163
+ const end = Math.min(size, tail.offset + MAX_READ_PER_POLL);
18164
+ while (tail.offset < end && !tail.excluded) {
18165
+ const bytesRead = fs.readSync(fd, buf, 0, Math.min(READ_CHUNK_BYTES, end - tail.offset), tail.offset);
18086
18166
  if (bytesRead <= 0) break;
18087
18167
  tail.offset += bytesRead;
18088
- tail.remainder += buf.toString("utf-8", 0, bytesRead);
18168
+ tail.remainder += tail.decoder.write(buf.subarray(0, bytesRead));
18089
18169
  const lines = tail.remainder.split("\n");
18090
18170
  tail.remainder = lines.pop() || "";
18091
18171
  for (const line of lines) {
18092
- this.handleLine(line, tail);
18172
+ if (tail.discardingLine) {
18173
+ tail.discardingLine = false;
18174
+ continue;
18175
+ }
18176
+ if (line.length <= MAX_LINE_CHARS) this.handleLine(line, tail, filePath);
18093
18177
  if (tail.excluded) break;
18094
18178
  }
18179
+ if (tail.remainder.length > MAX_LINE_CHARS) {
18180
+ tail.remainder = "";
18181
+ tail.discardingLine = true;
18182
+ }
18095
18183
  }
18096
18184
  } catch (err) {
18097
18185
  console.error(`[transcripts] Read error for ${filePath}:`, err);
@@ -18102,7 +18190,7 @@ var TranscriptTailer = class {
18102
18190
  }
18103
18191
  }
18104
18192
  }
18105
- handleLine(line, tail) {
18193
+ handleLine(line, tail, filePath) {
18106
18194
  const trimmed = line.trim();
18107
18195
  if (!trimmed) return;
18108
18196
  let obj;
@@ -18111,16 +18199,18 @@ var TranscriptTailer = class {
18111
18199
  } catch {
18112
18200
  return;
18113
18201
  }
18202
+ const entry = this.agentId === "claude" ? this.parseClaudeLine(obj) : this.parseCodexLine(obj, tail);
18203
+ if (tail.excluded || !tail.scoped || obj?.isSidechain || obj?.isMeta) return;
18204
+ if (this.agentId === "claude" && typeof obj?.cwd === "string" && stripTrailingSep(obj.cwd) !== this.cwd) return;
18114
18205
  if (this.rawSink) {
18115
18206
  const rawMs = typeof obj?.timestamp === "string" ? Date.parse(obj.timestamp) : NaN;
18116
- if (!Number.isFinite(rawMs) || rawMs >= this.sinceMs - DISCOVERY_SLACK_MS) {
18207
+ if (obj?.type === "session_meta" || !Number.isFinite(rawMs) || rawMs >= this.sinceMs - DISCOVERY_SLACK_MS) {
18117
18208
  try {
18118
- this.rawSink(obj);
18209
+ this.rawSink(obj, { filePath, sinceMs: this.sinceMs });
18119
18210
  } catch {
18120
18211
  }
18121
18212
  }
18122
18213
  }
18123
- const entry = this.agentId === "claude" ? this.parseClaudeLine(obj) : this.parseCodexLine(obj, tail);
18124
18214
  if (!entry) return;
18125
18215
  const ms = Date.parse(entry.ts);
18126
18216
  if (Number.isFinite(ms) && ms < this.sinceMs - DISCOVERY_SLACK_MS) return;
@@ -18149,9 +18239,10 @@ var TranscriptTailer = class {
18149
18239
  const payload = obj.payload;
18150
18240
  if (obj.type === "session_meta") {
18151
18241
  const metaCwd = payload?.cwd;
18152
- if (typeof metaCwd === "string" && stripTrailingSep(metaCwd) !== this.cwd) {
18242
+ if (typeof metaCwd !== "string" || stripTrailingSep(metaCwd) !== this.cwd) {
18153
18243
  tail.excluded = true;
18154
18244
  }
18245
+ tail.scoped = !tail.excluded;
18155
18246
  return null;
18156
18247
  }
18157
18248
  if (obj.type !== "event_msg" || !payload || typeof payload !== "object") return null;
@@ -19848,7 +19939,7 @@ Your previous output was invalid (${lastError}). Return valid JSON matching the
19848
19939
  }
19849
19940
  }
19850
19941
  buildUser(window2) {
19851
- const compact = window2.map((e) => {
19942
+ const compact2 = window2.map((e) => {
19852
19943
  const out = { id: e.id, ts: e.ts, type: e.type };
19853
19944
  if (e.text) out.text = truncateForTier1(e.text);
19854
19945
  if (e.tool) out.tool = e.tool;
@@ -19868,7 +19959,7 @@ Your previous output was invalid (${lastError}). Return valid JSON matching the
19868
19959
  ${JSON.stringify(state)}
19869
19960
 
19870
19961
  WINDOW (${window2.length} events):
19871
- ${compact.join("\n")}`;
19962
+ ${compact2.join("\n")}`;
19872
19963
  }
19873
19964
  parse(text, windowIds) {
19874
19965
  const parsed = JSON.parse(text);
@@ -20682,8 +20773,799 @@ function extractToolResultText(content) {
20682
20773
  return content.filter((b) => b?.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n");
20683
20774
  }
20684
20775
 
20776
+ // src/main/workMap/workMap.ts
20777
+ var import_check_work_map_gpu = __toESM(require_check_work_map_gpu());
20778
+ import path13 from "path";
20779
+ import fs9 from "fs";
20780
+ import os4 from "os";
20781
+
20782
+ // src/main/workMap/clef.ts
20783
+ import { spawn as spawn2 } from "child_process";
20784
+ import fs7 from "fs";
20785
+ import path10 from "path";
20786
+ function validateDecisions(value, req) {
20787
+ const answers = value?.answers;
20788
+ if (!answers || Object.keys(answers).sort().join() !== Object.keys(req.questions).sort().join()) throw new Error("Clef returned an invalid decision schema");
20789
+ for (const [key, q] of Object.entries(req.questions)) {
20790
+ const a = answers[key];
20791
+ const allowed = Object.keys(q.criteria).sort();
20792
+ if (!a || !allowed.includes(a.choice) || !a.probabilities || Object.keys(a.probabilities).sort().join() !== allowed.join()) throw new Error("Clef returned an unknown branch or activity");
20793
+ const values = Object.values(a.probabilities);
20794
+ if (values.some((p) => typeof p !== "number" || !Number.isFinite(p) || p < 0 || p > 1) || Math.abs(values.reduce((s, p) => s + p, 0) - 1) > 2e-3 || a.probabilities[a.choice] < Math.max(...values) - 1e-6) throw new Error("Clef returned invalid probabilities");
20795
+ }
20796
+ return answers;
20797
+ }
20798
+ var ClefWorker = class {
20799
+ constructor(scriptPath, onChange) {
20800
+ this.scriptPath = scriptPath;
20801
+ this.onChange = onChange;
20802
+ }
20803
+ state = "idle";
20804
+ error = null;
20805
+ child = null;
20806
+ ready = null;
20807
+ rejectReady = null;
20808
+ pending = null;
20809
+ seq = 0;
20810
+ generation = 0;
20811
+ idle = null;
20812
+ loadTimeout = null;
20813
+ requestTimeout = null;
20814
+ stopping = Promise.resolve();
20815
+ change(state, error = null) {
20816
+ this.state = state;
20817
+ this.error = error;
20818
+ this.onChange();
20819
+ }
20820
+ async predict(settings, request) {
20821
+ const generation = this.generation;
20822
+ try {
20823
+ await this.start(settings, generation);
20824
+ if (!this.child || generation !== this.generation) throw new Error("Clef process stopped");
20825
+ if (this.pending) throw new Error("Clef is already processing a batch");
20826
+ if (this.idle) clearTimeout(this.idle);
20827
+ this.change("thinking");
20828
+ const response = await new Promise((resolve4, reject) => {
20829
+ this.pending = { id: ++this.seq, resolve: resolve4, reject };
20830
+ this.requestTimeout = setTimeout(() => this.fail("Clef timed out; turn the map off and on to retry."), 2e4);
20831
+ this.child.stdin.write(JSON.stringify({ id: this.seq, request }) + "\n", (err) => {
20832
+ if (err) this.fail(`Clef input failed: ${err.message}`);
20833
+ });
20834
+ });
20835
+ const answers = validateDecisions(response, request);
20836
+ this.change("ready");
20837
+ this.armIdle();
20838
+ return answers;
20839
+ } catch (err) {
20840
+ if (generation === this.generation) this.fail(err instanceof Error ? err.message : String(err));
20841
+ throw err;
20842
+ }
20843
+ }
20844
+ async start(settings, generation) {
20845
+ await this.stopping;
20846
+ if (generation !== this.generation) throw new Error("Clef process stopped");
20847
+ if (this.ready) return this.ready;
20848
+ if (process.platform !== "darwin" || process.arch !== "arm64") throw new Error("Local Clef-Flash requires an Apple Silicon Mac. Choose Rules on this machine.");
20849
+ if (!fs7.existsSync(settings.pythonPath) || !fs7.existsSync(path10.join(settings.modelPath, "clef_mlx.py"))) {
20850
+ throw new Error("Clef runtime not found. Open Local model setup and select the Python executable and downloaded Clef-Flash folder.");
20851
+ }
20852
+ this.change("loading");
20853
+ const child = spawn2(settings.pythonPath, ["-u", this.scriptPath, settings.modelPath], {
20854
+ stdio: ["pipe", "pipe", "pipe"],
20855
+ env: { ...process.env, HF_HUB_OFFLINE: "1", TRANSFORMERS_OFFLINE: "1", PYTHONDONTWRITEBYTECODE: "1" }
20856
+ });
20857
+ this.child = child;
20858
+ let buffer = "";
20859
+ let stderr = "";
20860
+ this.ready = new Promise((resolve4, reject) => {
20861
+ this.rejectReady = reject;
20862
+ this.loadTimeout = setTimeout(() => this.fail("Clef did not load within 60 seconds."), 6e4);
20863
+ child.stdout.on("data", (chunk) => {
20864
+ if (this.child !== child) return;
20865
+ buffer += String(chunk);
20866
+ if (buffer.length > 128e3) {
20867
+ this.fail("Clef response exceeded its output budget");
20868
+ return;
20869
+ }
20870
+ let newline;
20871
+ while ((newline = buffer.indexOf("\n")) >= 0) {
20872
+ const line = buffer.slice(0, newline);
20873
+ buffer = buffer.slice(newline + 1);
20874
+ let msg;
20875
+ try {
20876
+ msg = JSON.parse(line);
20877
+ } catch {
20878
+ continue;
20879
+ }
20880
+ if (msg.ready) {
20881
+ if (this.loadTimeout) clearTimeout(this.loadTimeout);
20882
+ this.rejectReady = null;
20883
+ this.change("ready");
20884
+ resolve4();
20885
+ } else if (msg.error) {
20886
+ this.fail(String(msg.error));
20887
+ } else if (msg.id === this.pending?.id) {
20888
+ if (this.requestTimeout) clearTimeout(this.requestTimeout);
20889
+ const pending = this.pending;
20890
+ this.pending = null;
20891
+ pending?.resolve(msg);
20892
+ }
20893
+ }
20894
+ });
20895
+ child.stderr.on("data", (chunk) => {
20896
+ stderr = (stderr + String(chunk)).slice(-1e3);
20897
+ });
20898
+ child.on("error", (err) => {
20899
+ if (this.child === child) this.fail(`Cannot start Clef: ${err.message}`);
20900
+ });
20901
+ child.on("exit", () => {
20902
+ if (this.child === child) this.fail(`Clef stopped unexpectedly. ${stderr.slice(-300)}`);
20903
+ });
20904
+ });
20905
+ return this.ready;
20906
+ }
20907
+ armIdle() {
20908
+ if (this.idle) clearTimeout(this.idle);
20909
+ this.idle = setTimeout(() => this.stop(), 6e4);
20910
+ this.idle.unref();
20911
+ }
20912
+ fail(message) {
20913
+ this.stop(message);
20914
+ this.change("error", message.slice(0, 600));
20915
+ }
20916
+ stop(reason = "Clef stopped") {
20917
+ ++this.generation;
20918
+ for (const timer of [this.idle, this.loadTimeout, this.requestTimeout]) if (timer) clearTimeout(timer);
20919
+ this.idle = this.loadTimeout = this.requestTimeout = null;
20920
+ this.rejectReady?.(new Error(reason));
20921
+ this.rejectReady = null;
20922
+ this.pending?.reject(new Error(reason));
20923
+ this.pending = null;
20924
+ this.ready = null;
20925
+ const child = this.child;
20926
+ this.child = null;
20927
+ if (child) {
20928
+ this.stopping = new Promise((resolve4) => child.once("close", () => resolve4()));
20929
+ child.kill("SIGKILL");
20930
+ }
20931
+ this.change("idle");
20932
+ }
20933
+ };
20934
+
20935
+ // src/main/workMap/normalize.ts
20936
+ import { createHash } from "crypto";
20937
+ import path11 from "path";
20938
+ var textOf = (value) => {
20939
+ if (typeof value === "string") return value;
20940
+ if (Array.isArray(value)) return value.map((b) => b?.text || "").filter(Boolean).join("\n");
20941
+ return "";
20942
+ };
20943
+ var compact = (value) => {
20944
+ if (typeof value === "string") return value.slice(0, 1800);
20945
+ try {
20946
+ return JSON.stringify(value ?? {}).slice(0, 1800);
20947
+ } catch {
20948
+ return "";
20949
+ }
20950
+ };
20951
+ var noise = (text) => /^\s*(?:<environment_context>|<user_instructions>|<permissions instructions>|<system-reminder>|<local-command|<command-|<task-notification>|<turn_aborted>|# AGENTS\.md)/i.test(text);
20952
+ var summaryText = (value) => {
20953
+ if (typeof value === "string") return value;
20954
+ if (!Array.isArray(value)) return "";
20955
+ return value.map((part) => typeof part === "string" ? part : part?.type === "summary_text" ? part.text || "" : "").filter(Boolean).join("\n\n");
20956
+ };
20957
+ function codexThinking(raw) {
20958
+ const p = raw?.payload;
20959
+ if (raw?.type === "response_item" && p?.type === "reasoning") {
20960
+ const text = summaryText(p.summary);
20961
+ return { text, key: p.id || text };
20962
+ }
20963
+ if (raw?.type === "event_msg" && p?.type === "agent_reasoning") {
20964
+ const text = typeof p.text === "string" ? p.text : "";
20965
+ return { text, key: p.id || text };
20966
+ }
20967
+ const item = raw?.type === "event_msg" && p?.type === "item_completed" ? p.item : raw?.method === "item/completed" ? raw.params?.item : null;
20968
+ if (item?.type === "Reasoning" || item?.type === "reasoning") {
20969
+ const text = summaryText(item.summary_text ?? item.summaryText ?? item.summary);
20970
+ return { text, key: item.id || text };
20971
+ }
20972
+ return null;
20973
+ }
20974
+ function mapThinkingStatus(raw, agent) {
20975
+ if (agent === "claude") {
20976
+ if (raw?.type !== "assistant" || !Array.isArray(raw.message?.content)) return null;
20977
+ const blocks = raw.message.content.filter((b) => b?.type === "thinking" || b?.type === "redacted_thinking");
20978
+ if (!blocks.length) return null;
20979
+ return blocks.some((b) => b.type === "thinking" && typeof b.thinking === "string" && b.thinking.trim()) ? "available" : "unavailable";
20980
+ }
20981
+ const thinking = codexThinking(raw);
20982
+ return thinking ? thinking.text.trim() ? "available" : "unavailable" : null;
20983
+ }
20984
+ function normalizeMapEvents(raw, file, agent, includeFullSource = false) {
20985
+ if (!raw || typeof raw !== "object" || raw.isSidechain || raw.isMeta) return [];
20986
+ const ts = typeof raw.timestamp === "string" ? raw.timestamp : (/* @__PURE__ */ new Date()).toISOString();
20987
+ const source = path11.basename(file);
20988
+ const events = [];
20989
+ const add = (kind, text, key, extra = {}) => {
20990
+ if (!text.trim() || (kind === "prompt" || kind === "message") && noise(text)) return;
20991
+ const hash = createHash("sha256").update(`${file}:${key}:${kind}`).digest("hex").slice(0, 20);
20992
+ const bounded = kind === "thinking" && text.length > 1800 ? `${text.slice(0, 300)}
20993
+ \u2026
20994
+ ${text.slice(-1490)}` : text.trim().slice(0, 1800);
20995
+ const segments = kind === "thinking" || kind === "message" ? decisionCandidates(text) : void 0;
20996
+ events.push({
20997
+ id: hash,
20998
+ ts,
20999
+ kind,
21000
+ text: bounded,
21001
+ source,
21002
+ ...extra,
21003
+ ...segments?.length ? { segments } : {},
21004
+ ...includeFullSource && (kind === "thinking" || kind === "message") ? { fullText: text.trim() } : {}
21005
+ });
21006
+ };
21007
+ if (agent === "claude") {
21008
+ if (raw.type !== "user" && raw.type !== "assistant") return [];
21009
+ const blocks = raw.message?.content;
21010
+ const key = raw.uuid || raw.message?.id || `${ts}:${compact(blocks)}`;
21011
+ if (typeof blocks === "string") add(raw.type === "user" ? "prompt" : "message", blocks, key);
21012
+ else if (Array.isArray(blocks)) blocks.forEach((b, i) => {
21013
+ if (b.type === "text") add(raw.type === "user" ? "prompt" : "message", b.text || "", `${key}:${i}`);
21014
+ if (raw.type === "assistant" && b.type === "thinking" && typeof b.thinking === "string") add("thinking", b.thinking, `${key}:${i}`);
21015
+ if (b.type === "tool_use") add("tool", compact(b.input?.command ?? b.input?.file_path ?? b.input), b.id, { tool: b.name, toolId: b.id, status: "running" });
21016
+ if (b.type === "tool_result") add("result", textOf(b.content) || "Tool completed", b.tool_use_id, {
21017
+ toolId: b.tool_use_id,
21018
+ status: b.is_error === true ? "failed" : "succeeded"
21019
+ });
21020
+ });
21021
+ return events;
21022
+ }
21023
+ const thinking = codexThinking(raw);
21024
+ if (thinking) {
21025
+ add("thinking", thinking.text, `reasoning:${thinking.key}`);
21026
+ return events;
21027
+ }
21028
+ const p = raw.payload;
21029
+ if (!p) return [];
21030
+ if (raw.type === "event_msg") {
21031
+ if (p.type === "user_message" || p.type === "agent_message") {
21032
+ add(p.type === "user_message" ? "prompt" : "message", textOf(p.message), `${ts}:${p.type}:${textOf(p.message)}`);
21033
+ }
21034
+ const item = p.type === "item_completed" ? p.item : null;
21035
+ if (item?.type === "CommandExecution") {
21036
+ const status = item.status === "failed" || typeof item.exit_code === "number" && item.exit_code !== 0 ? "failed" : item.status === "completed" && item.exit_code === 0 ? "succeeded" : "unknown";
21037
+ const command = Array.isArray(item.command) ? item.command.length >= 3 && /^-(?:l?c|cl)$/.test(item.command[1]) ? item.command.slice(2).join(" ") : item.command.join(" ") : compact(item.command);
21038
+ add("tool", command, item.id, { tool: "shell", toolId: item.id, status: "running" });
21039
+ add("result", item.aggregated_output || `Command ended (${item.exit_code ?? item.status})`, item.id, { toolId: item.id, status });
21040
+ }
21041
+ if (item?.type === "FileChange") {
21042
+ add("tool", Object.keys(item.changes || {}).join("\n"), item.id, { tool: "apply_patch", toolId: item.id, status: "unknown" });
21043
+ }
21044
+ }
21045
+ if (raw.type !== "response_item") return events;
21046
+ if (p.type === "message" && (p.role === "user" || p.role === "assistant")) {
21047
+ const text = Array.isArray(p.content) ? p.content.filter((b) => ["input_text", "output_text"].includes(b.type)).map((b) => b.text).join("\n") : "";
21048
+ add(p.role === "user" ? "prompt" : "message", text, p.id || `${ts}:${p.role}:${text}`);
21049
+ }
21050
+ if (p.type === "function_call" || p.type === "custom_tool_call") {
21051
+ if (/^(?:functions\.)?exec$/.test(p.name)) return events;
21052
+ let input = p.arguments ?? p.input;
21053
+ try {
21054
+ const obj = JSON.parse(input);
21055
+ input = obj.cmd ?? obj.command ?? obj.file_path ?? obj;
21056
+ } catch {
21057
+ }
21058
+ add("tool", compact(input), p.call_id, { tool: p.name, toolId: p.call_id, status: "running" });
21059
+ }
21060
+ if (p.type === "function_call_output" || p.type === "custom_tool_call_output") {
21061
+ const output = textOf(p.output) || compact(p.output);
21062
+ const exit = output.match(/(?:Process exited with code|exit_code["']?\s*:)\s*(-?\d+)/i);
21063
+ const status = p.is_error === true ? "failed" : exit ? Number(exit[1]) === 0 ? "succeeded" : "failed" : "unknown";
21064
+ add("result", output, p.call_id, { toolId: p.call_id, status });
21065
+ }
21066
+ return events;
21067
+ }
21068
+ function activityFor(e) {
21069
+ if (e.kind === "thinking") return "thinking";
21070
+ if (e.kind === "prompt") return "planning";
21071
+ if (e.kind === "message") return /\b(will|next|plan|investigat|checking)\b/i.test(e.text) ? "planning" : "reporting";
21072
+ if (/edit|write|apply_patch|filechange/i.test(e.tool || "")) return "editing";
21073
+ if (/\b(?:pytest|vitest|jest|tsc|unittest|npm (?:run )?(?:test|build)|cargo test|go test|node\s+\S*test[-_.])\b/i.test(e.text)) return "testing";
21074
+ return "investigating";
21075
+ }
21076
+ function shortLabel(text, limit2 = 72) {
21077
+ const line = text.replace(/```[\s\S]*?```/g, "").replace(/^[\s#>*-]+/gm, "").replace(/\s+/g, " ").trim();
21078
+ return line.length > limit2 ? `${line.slice(0, limit2 - 1).trimEnd()}\u2026` : line || "Current work";
21079
+ }
21080
+ function topicFor(e) {
21081
+ if (e.kind === "thinking") return "Reasoning & decisions";
21082
+ const paths = e.text.match(/(?:[\w.@-]+\/)+[\w.@-]+\.(?:tsx?|jsx?|py|json|css|md|rs|go|sh|cjs|mjs)\b/g);
21083
+ if (paths?.length) return shortLabel(paths[0].split("/").slice(-2).join("/"), 48);
21084
+ if (activityFor(e) === "testing") return "Build & tests";
21085
+ if (e.kind === "message") return "Approach & findings";
21086
+ return shortLabel(e.tool || "Investigation", 48);
21087
+ }
21088
+ function decisionCandidates(text) {
21089
+ const parts = text.split(/\n+|(?<=[.!?])\s+|,\s+(?=(?:so|because|since|rather|instead)\b)/i).map((s) => s.replace(/^[\s#>*-]+/, "").replace(/\*\*/g, "").trim()).filter((s) => s.length >= 15);
21090
+ const score = (s) => (intentFor(s) !== "context" ? 10 : 0) + (/\b(?:choose|decid|instead|suspect|likely|next|prefer)\w*\b/i.test(s) ? 5 : 0) + (/\b(?:because|since|so|avoid|tradeoff|due to|constraint|means)\b/i.test(s) ? 8 : 0);
21091
+ return [...new Set(parts)].map((text2, index) => ({ text: text2.slice(0, 320), index, score: score(text2) })).sort((a, b) => b.score - a.score || a.index - b.index).slice(0, 6).map((p) => p.text);
21092
+ }
21093
+ function intentFor(text) {
21094
+ if (/\b(?:suspect|hypothesis|likely|probably|perhaps|maybe|might|could be|seems)\b/i.test(text)) return "hypothesis";
21095
+ if (/\b(?:alternative|option|versus|weigh|either|could (?:use|try))\b/i.test(text)) return "alternative";
21096
+ if (/\b(?:choose|decided?|prefer|instead|use .+ rather than|let['’]s use)\b/i.test(text)) return "decision";
21097
+ if (/\b(?:building|implementing|keeping) (?:it |this )?(?:as|with|in)\b/i.test(text)) return "decision";
21098
+ if (/\b(?:I['’]ll|I will|we should|need to|next|going to|plan to|first (?:check|test|inspect|read))\b/i.test(text)) return "next_step";
21099
+ return "context";
21100
+ }
21101
+
21102
+ // src/main/workMap/tree.ts
21103
+ var ACTIVITIES = {
21104
+ investigating: "Reading files, searching, inspecting or diagnosing",
21105
+ editing: "Changing files, code, dependencies or configuration",
21106
+ testing: "Running tests, builds or validation",
21107
+ planning: "Discussing the approach or deciding what to do next",
21108
+ reporting: "Explaining findings or summarizing completed work"
21109
+ };
21110
+ var INTENTS = {
21111
+ decision: "A stated choice of approach or rejection of another approach",
21112
+ hypothesis: "An unverified explanation or suspicion to investigate",
21113
+ alternative: "Weighing different possible approaches without choosing yet",
21114
+ next_step: "A stated next action or check to perform",
21115
+ context: "General narration with no clear choice, hypothesis or next step"
21116
+ };
21117
+ var MAP_NODE_LIMIT = 240;
21118
+ var WorkMapTree = class {
21119
+ nodes = [];
21120
+ dropped = 0;
21121
+ goal = null;
21122
+ seq = 0;
21123
+ seen = /* @__PURE__ */ new Set();
21124
+ tools = /* @__PURE__ */ new Map();
21125
+ lastText = null;
21126
+ contextId;
21127
+ ingest(e) {
21128
+ if (this.seen.has(e.id)) return null;
21129
+ this.seen.add(e.id);
21130
+ if (this.seen.size > 1200) this.seen.delete(this.seen.values().next().value);
21131
+ if (e.kind === "result") {
21132
+ const id = this.tools.get(`${e.source}:${e.toolId}`);
21133
+ const node2 = this.nodes.find((n) => n.id === id);
21134
+ if (node2) {
21135
+ node2.status = e.status || "unknown";
21136
+ node2.evidence = [node2.evidence[0], e];
21137
+ }
21138
+ return null;
21139
+ }
21140
+ if (e.kind === "prompt" || e.kind === "message" || e.kind === "thinking") {
21141
+ const key = `${e.source}:${e.kind}:${e.text}`;
21142
+ const time = Date.parse(e.ts);
21143
+ if (this.lastText?.key === key && Math.abs(time - this.lastText.time) < 3e3) return null;
21144
+ this.lastText = { key, time };
21145
+ }
21146
+ if (e.kind === "prompt") {
21147
+ this.contextId = void 0;
21148
+ this.goal = this.add({ parentId: null, kind: "goal", title: shortLabel(e.text, 110), activity: "planning", status: "unknown", ts: e.ts, evidence: [e] }).id;
21149
+ this.trim();
21150
+ return null;
21151
+ }
21152
+ if (!this.goal) this.goal = this.add({ parentId: null, kind: "goal", title: "Session work", activity: "planning", status: "unknown", ts: e.ts, evidence: [] }).id;
21153
+ const topic = topicFor(e);
21154
+ const branch = this.branch(this.goal, topic, e.ts);
21155
+ const activity = activityFor(e);
21156
+ const statement = e.kind === "thinking" || e.kind === "message" ? e.segments?.[0] || decisionCandidates(e.text)[0] || e.text : e.text;
21157
+ const title = e.kind === "tool" ? `${e.tool || "Tool"} \xB7 ${shortLabel(e.text, 65)}` : shortLabel(statement, 110);
21158
+ const intent = e.kind === "thinking" || e.kind === "message" ? intentFor(statement) : void 0;
21159
+ const node = this.add({
21160
+ parentId: branch.id,
21161
+ kind: "step",
21162
+ title,
21163
+ activity,
21164
+ status: e.status || "unknown",
21165
+ ts: e.ts,
21166
+ evidence: [e],
21167
+ placement: "rules",
21168
+ intent,
21169
+ ...intent && intent !== "context" ? { focus: { text: statement } } : {},
21170
+ ...e.kind === "tool" && this.contextId ? { contextId: this.contextId } : {}
21171
+ });
21172
+ if (e.kind === "thinking" || e.kind === "message") this.contextId = node.id;
21173
+ if (e.toolId) this.tools.set(`${e.source}:${e.toolId}`, node.id);
21174
+ this.trim();
21175
+ return node.id;
21176
+ }
21177
+ end() {
21178
+ for (const n of this.nodes) if (n.status === "running") n.status = "interrupted";
21179
+ }
21180
+ request(ids) {
21181
+ const nodes = ids.map((id) => this.nodes.find((n) => n.id === id && n.kind === "step")).filter((n) => !!n);
21182
+ if (!nodes.length) return null;
21183
+ const parent = this.nodes.find((n) => n.id === nodes[0].parentId);
21184
+ if (!parent?.parentId) return null;
21185
+ const goalId = parent.parentId;
21186
+ const sameGoal = nodes.filter((n) => this.nodes.find((b) => b.id === n.parentId)?.parentId === goalId);
21187
+ const isIntent = (n) => n?.evidence[0]?.kind === "thinking" || n?.evidence[0]?.kind === "message";
21188
+ const selected = sameGoal.slice(0, isIntent(sameGoal[0]) || isIntent(sameGoal[1]) ? 1 : 2);
21189
+ const goal = this.nodes.find((n) => n.id === goalId);
21190
+ const branches = this.nodes.filter((n) => n.kind === "branch" && n.parentId === goalId).slice(-4);
21191
+ const criteria = Object.fromEntries(branches.map((n) => [n.id, n.title.slice(0, 48)]));
21192
+ criteria.new_topic = "A different work topic; create a new branch";
21193
+ const questions = {};
21194
+ const statements = {};
21195
+ const reasons = {};
21196
+ selected.forEach((node, i) => {
21197
+ questions[`branch_${i}`] = { type: "choice", instructions: `Which work topic does event_${i} belong to? Use the goal and stated reasoning, not incidental file paths.`, criteria };
21198
+ if (isIntent(node)) {
21199
+ const candidates = node.evidence[0].segments || decisionCandidates(node.evidence[0].text);
21200
+ statements[node.id] = candidates.length ? candidates : [node.evidence[0].text.slice(0, 220)];
21201
+ questions[`statement_${i}`] = {
21202
+ type: "choice",
21203
+ instructions: `Which excerpt best captures the agent's choice, hypothesis or next check in event_${i}?`,
21204
+ criteria: Object.fromEntries(statements[node.id].map((s, j) => [`s${j}`, s]))
21205
+ };
21206
+ questions[`intent_${i}`] = { type: "choice", instructions: `What does the selected excerpt express? A tentative explanation is not an established decision.`, criteria: INTENTS };
21207
+ reasons[node.id] = candidates.filter((s) => /\b(?:because|since|so|avoid|tradeoff|due to|constraint|rather|instead)\b/i.test(s)).slice(0, 3);
21208
+ if (reasons[node.id].length) questions[`reason_${i}`] = {
21209
+ type: "choice",
21210
+ instructions: "Which excerpt states why the agent chose its approach? Choose none if no supporting reason is stated.",
21211
+ criteria: { ...Object.fromEntries(reasons[node.id].map((s, j) => [`r${j}`, s])), none: "No supporting reason stated" }
21212
+ };
21213
+ } else {
21214
+ questions[`activity_${i}`] = { type: "choice", instructions: `What activity does event_${i} show?`, criteria: ACTIVITIES };
21215
+ }
21216
+ });
21217
+ return {
21218
+ ids: selected.map((n) => n.id),
21219
+ goalId,
21220
+ statements,
21221
+ reasons,
21222
+ request: {
21223
+ model: "clef-flash",
21224
+ state: JSON.stringify({ goal: goal.title, events: selected.map((n, i) => ({
21225
+ id: `event_${i}`,
21226
+ kind: n.evidence[0]?.kind,
21227
+ tool: n.evidence[0]?.tool,
21228
+ text: n.evidence[0]?.text.slice(0, 450),
21229
+ preceding_intent: this.nodes.find((c) => c.id === n.contextId)?.evidence[0]?.text.slice(-400),
21230
+ current_topic: this.nodes.find((b) => b.id === n.parentId)?.title
21231
+ })) }),
21232
+ questions
21233
+ }
21234
+ };
21235
+ }
21236
+ apply(job, answers) {
21237
+ job.ids.forEach((id, i) => {
21238
+ const node = this.nodes.find((n) => n.id === id);
21239
+ if (!node || !this.nodes.some((n) => n.id === job.goalId)) return;
21240
+ const decision = answers[`branch_${i}`];
21241
+ const textSource = node.evidence[0]?.kind === "thinking" || node.evidence[0]?.kind === "message";
21242
+ if (textSource) {
21243
+ const choice = answers[`statement_${i}`]?.choice;
21244
+ const statement = job.statements[node.id]?.[Number(choice?.slice(1))];
21245
+ if (statement) node.title = shortLabel(statement, 110);
21246
+ const statedIntent = intentFor(statement || "");
21247
+ node.intent = statedIntent !== "context" ? statedIntent : answers[`intent_${i}`]?.choice;
21248
+ const reasonChoice = answers[`reason_${i}`]?.choice;
21249
+ const reason = reasonChoice && reasonChoice !== "none" ? job.reasons[node.id]?.[Number(reasonChoice.slice(1))] : void 0;
21250
+ node.focus = statement ? { text: statement, ...reason && reason !== statement ? { reason } : {} } : void 0;
21251
+ }
21252
+ const topic = topicFor(node.evidence[0]);
21253
+ const newTitle = shortLabel(node.evidence[0].kind === "thinking" ? node.title : node.evidence[0].text, 48);
21254
+ const target = decision.choice === "new_topic" ? this.branch(job.goalId, newTitle === topic ? `${node.activity} \xB7 ${topic}` : newTitle, node.ts) : this.nodes.find((n) => n.id === decision.choice && n.kind === "branch" && n.parentId === job.goalId);
21255
+ if (!target) return;
21256
+ node.parentId = target.id;
21257
+ node.activity = node.evidence[0]?.kind === "thinking" ? "thinking" : textSource ? node.intent === "context" ? "reporting" : "planning" : answers[`activity_${i}`].choice;
21258
+ node.placement = "clef-flash";
21259
+ node.confidence = decision.probabilities[decision.choice];
21260
+ });
21261
+ this.removeEmptyBranches();
21262
+ this.trim();
21263
+ }
21264
+ add(node) {
21265
+ const result = { ...node, id: `map_${++this.seq}` };
21266
+ this.nodes.push(result);
21267
+ return result;
21268
+ }
21269
+ branch(goal, title, ts) {
21270
+ return this.nodes.find((n) => n.kind === "branch" && n.parentId === goal && n.title === title) || this.add({ parentId: goal, kind: "branch", title, activity: "planning", status: "unknown", ts, evidence: [] });
21271
+ }
21272
+ removeEmptyBranches() {
21273
+ const parents = new Set(this.nodes.map((n) => n.parentId));
21274
+ this.nodes = this.nodes.filter((n) => n.kind !== "branch" || parents.has(n.id));
21275
+ }
21276
+ trim() {
21277
+ while (this.nodes.length > MAP_NODE_LIMIT) {
21278
+ const oldGoal = this.nodes.find((n) => n.kind === "goal" && n.id !== this.goal);
21279
+ if (oldGoal) {
21280
+ const removed = /* @__PURE__ */ new Set([oldGoal.id, ...this.nodes.filter((n) => n.parentId === oldGoal.id).map((n) => n.id)]);
21281
+ const before = this.nodes.length;
21282
+ this.nodes = this.nodes.filter((n) => !removed.has(n.id) && !removed.has(n.parentId || ""));
21283
+ this.dropped += before - this.nodes.length;
21284
+ } else {
21285
+ const oldest = this.nodes.findIndex((n) => n.kind === "step");
21286
+ if (oldest < 0) break;
21287
+ this.nodes.splice(oldest, 1);
21288
+ this.dropped++;
21289
+ this.removeEmptyBranches();
21290
+ }
21291
+ }
21292
+ const retained = new Set(this.nodes.map((n) => n.id));
21293
+ if (this.contextId && !retained.has(this.contextId)) this.contextId = void 0;
21294
+ for (const [key, id] of this.tools) if (!retained.has(id)) this.tools.delete(key);
21295
+ }
21296
+ };
21297
+
21298
+ // src/main/workMap/source.ts
21299
+ import fs8 from "fs";
21300
+ import path12 from "path";
21301
+ import { StringDecoder as StringDecoder2 } from "string_decoder";
21302
+ async function readMapSource(file, agent, eventId) {
21303
+ const decoder = new StringDecoder2("utf8");
21304
+ let remainder = "";
21305
+ let discard = false;
21306
+ const stream = fs8.createReadStream(file, { highWaterMark: 64 * 1024 });
21307
+ for await (const chunk of stream) {
21308
+ remainder += decoder.write(chunk);
21309
+ const lines = remainder.split("\n");
21310
+ remainder = lines.pop() || "";
21311
+ for (const line of lines) {
21312
+ if (discard) {
21313
+ discard = false;
21314
+ continue;
21315
+ }
21316
+ if (line.length > 1024 * 1024) continue;
21317
+ let raw;
21318
+ try {
21319
+ raw = JSON.parse(line);
21320
+ } catch {
21321
+ continue;
21322
+ }
21323
+ const event = normalizeMapEvents(raw, file, agent, true).find((e) => e.id === eventId);
21324
+ if (event?.fullText !== void 0) return { text: event.fullText, source: path12.basename(file) };
21325
+ }
21326
+ if (remainder.length > 1024 * 1024) {
21327
+ remainder = "";
21328
+ discard = true;
21329
+ }
21330
+ }
21331
+ return null;
21332
+ }
21333
+
21334
+ // src/main/workMap/workMap.ts
21335
+ var WorkMap = class {
21336
+ constructor(appRoot, onUpdate, roots = {}, capability = (0, import_check_work_map_gpu.initialCapability)()) {
21337
+ this.onUpdate = onUpdate;
21338
+ this.roots = roots;
21339
+ this.capability = capability;
21340
+ const cache = path13.join(appRoot, "experiments/live-map/.cache");
21341
+ const prepared = path13.join(os4.homedir(), ".ctlsurf/clef-flash");
21342
+ const pilotPython = path13.join(cache, "envs/clef-flash/bin/python");
21343
+ this.settings = {
21344
+ enabled: false,
21345
+ engine: "clef-flash",
21346
+ pythonPath: process.env.CTLSURF_CLEF_PYTHON || (fs9.existsSync(pilotPython) ? pilotPython : path13.join(prepared, "env/bin/python")),
21347
+ modelPath: process.env.CTLSURF_CLEF_MODEL || (fs9.existsSync(pilotPython) ? path13.join(cache, "models/clef-flash") : path13.join(prepared, "model"))
21348
+ };
21349
+ this.clef = new ClefWorker(path13.join(appRoot, "scripts/work-map-clef.py"), () => this.publish());
21350
+ }
21351
+ tabs = /* @__PURE__ */ new Map();
21352
+ owners = /* @__PURE__ */ new Map();
21353
+ settings;
21354
+ clef;
21355
+ revision = 0;
21356
+ epoch = 0;
21357
+ timer = null;
21358
+ publishing = null;
21359
+ working = false;
21360
+ round = 0;
21361
+ configure(value) {
21362
+ ++this.epoch;
21363
+ const previous = this.settings;
21364
+ this.settings = {
21365
+ enabled: this.capability.state === "available" && (typeof value.enabled === "boolean" ? value.enabled : previous.enabled),
21366
+ engine: value.engine === "rules" || value.engine === "clef-flash" ? value.engine : previous.engine,
21367
+ pythonPath: typeof value.pythonPath === "string" && value.pythonPath.trim() ? value.pythonPath.trim() : previous.pythonPath,
21368
+ modelPath: typeof value.modelPath === "string" && value.modelPath.trim() ? value.modelPath.trim() : previous.modelPath
21369
+ };
21370
+ this.clef.stop();
21371
+ if (this.timer) clearTimeout(this.timer);
21372
+ this.timer = null;
21373
+ for (const tab of this.tabs.values()) {
21374
+ tab.pending.clear();
21375
+ if (this.settings.enabled && !tab.ended) this.start(tab);
21376
+ else {
21377
+ tab.tailer?.stop();
21378
+ tab.tailer = null;
21379
+ tab.tree.end();
21380
+ }
21381
+ if (this.settings.enabled && this.settings.engine === "clef-flash") {
21382
+ tab.tree.nodes.filter((n) => n.kind === "step" && n.placement !== "clef-flash").slice(-24).forEach((n) => tab.pending.add(n.id));
21383
+ }
21384
+ }
21385
+ this.publish();
21386
+ this.schedule();
21387
+ return { ...this.settings };
21388
+ }
21389
+ attach(tabId, agentId, agentName, cwd) {
21390
+ this.remove(tabId);
21391
+ const tab = { agentId, agentName, cwd, tree: new WorkMapTree(), tailer: null, ended: false, state: "idle", source: null, ignored: /* @__PURE__ */ new Set(), pending: /* @__PURE__ */ new Set(), thinkingStatus: "waiting", sources: /* @__PURE__ */ new Map() };
21392
+ this.tabs.set(tabId, tab);
21393
+ if (this.settings.enabled) this.start(tab);
21394
+ this.publish();
21395
+ }
21396
+ getCapability() {
21397
+ return { ...this.capability };
21398
+ }
21399
+ setCapability(capability) {
21400
+ this.capability = { ...capability };
21401
+ if (capability.state !== "available") this.configure({ enabled: false });
21402
+ this.publish();
21403
+ }
21404
+ end(tabId) {
21405
+ const tab = this.tabs.get(tabId);
21406
+ if (!tab) return;
21407
+ tab.ended = true;
21408
+ tab.tailer?.stop();
21409
+ tab.tailer = null;
21410
+ tab.pending.clear();
21411
+ tab.tree.end();
21412
+ for (const [source, owner] of this.owners) if (owner === tabId) this.owners.delete(source);
21413
+ if (![...this.tabs.values()].some((t) => !t.ended)) this.clef.stop();
21414
+ this.publish();
21415
+ }
21416
+ remove(tabId) {
21417
+ this.end(tabId);
21418
+ this.tabs.delete(tabId);
21419
+ for (const [source, owner] of this.owners) if (owner === tabId) this.owners.delete(source);
21420
+ }
21421
+ clear(tabId) {
21422
+ const tab = this.tabs.get(tabId);
21423
+ if (tab) {
21424
+ tab.tree = new WorkMapTree();
21425
+ tab.pending.clear();
21426
+ }
21427
+ this.publish();
21428
+ }
21429
+ noteState(tabId, state) {
21430
+ const tab = this.tabs.get(tabId);
21431
+ if (tab && tab.state !== state) {
21432
+ tab.state = state;
21433
+ this.publish();
21434
+ }
21435
+ }
21436
+ snapshot(tabId) {
21437
+ const tab = this.tabs.get(tabId);
21438
+ return {
21439
+ revision: ++this.revision,
21440
+ tabId,
21441
+ agentName: tab?.agentName || null,
21442
+ supported: !!tab && supportsTranscriptLogging(tab.agentId),
21443
+ ended: !!tab?.ended,
21444
+ state: tab?.state || "idle",
21445
+ settings: { ...this.settings },
21446
+ runtime: !this.settings.enabled ? "off" : this.settings.engine === "rules" ? "ready" : this.clef.state,
21447
+ error: this.settings.engine === "clef-flash" ? this.clef.error : null,
21448
+ nodes: tab?.tree.nodes || [],
21449
+ dropped: tab?.tree.dropped || 0,
21450
+ thinkingStatus: tab?.thinkingStatus || "waiting",
21451
+ capability: this.getCapability()
21452
+ };
21453
+ }
21454
+ async getSource(tabId, eventId) {
21455
+ const tab = this.tabs.get(tabId);
21456
+ const event = tab?.tree.nodes.flatMap((n) => n.evidence).find((e) => e.id === eventId && (e.kind === "thinking" || e.kind === "message"));
21457
+ const file = event && tab?.sources.get(event.source);
21458
+ if (!event || !file || !tab) return null;
21459
+ return readMapSource(file, tab.agentId, event.id);
21460
+ }
21461
+ start(tab) {
21462
+ if (tab.tailer || !supportsTranscriptLogging(tab.agentId)) return;
21463
+ tab.tailer = new TranscriptTailer({
21464
+ ...this.roots,
21465
+ agentId: tab.agentId,
21466
+ cwd: tab.cwd,
21467
+ sink: () => {
21468
+ },
21469
+ rawSink: (raw, source) => {
21470
+ if (!source || !this.settings.enabled || tab.ended) return;
21471
+ const file = source.filePath;
21472
+ if (tab.ignored.has(file)) return;
21473
+ if (raw.type === "session_meta") {
21474
+ const meta = raw.payload || {};
21475
+ if (meta.thread_source && meta.thread_source !== "user" || meta.source && typeof meta.source === "object" || meta.agent_path && meta.agent_path !== "/root") {
21476
+ tab.ignored.add(file);
21477
+ return;
21478
+ }
21479
+ }
21480
+ const tabId = [...this.tabs].find(([, candidate]) => candidate === tab)?.[0];
21481
+ if (!tabId) return;
21482
+ if (this.owners.has(file) && this.owners.get(file) !== tabId) return;
21483
+ if (tab.source && tab.source !== file) {
21484
+ if (raw.type !== "session_meta" || Date.parse(raw.payload?.timestamp || raw.timestamp) < source.sinceMs) return;
21485
+ this.owners.delete(tab.source);
21486
+ }
21487
+ tab.source = file;
21488
+ this.owners.set(file, tabId);
21489
+ const thinking = mapThinkingStatus(raw, tab.agentId);
21490
+ const statusChanged = thinking !== null && thinking !== tab.thinkingStatus && (thinking === "available" || tab.thinkingStatus === "waiting");
21491
+ if (statusChanged) tab.thinkingStatus = thinking;
21492
+ const events = normalizeMapEvents(raw, file, tab.agentId);
21493
+ for (const e of events) {
21494
+ tab.sources.set(e.source, file);
21495
+ const id = tab.tree.ingest(e);
21496
+ if (id && this.settings.engine === "clef-flash") {
21497
+ tab.pending.add(id);
21498
+ if (tab.pending.size > 24) tab.pending.delete(tab.pending.values().next().value);
21499
+ }
21500
+ }
21501
+ const retainedSources = new Set(tab.tree.nodes.flatMap((n) => n.evidence.map((e) => e.source)));
21502
+ for (const name of tab.sources.keys()) if (!retainedSources.has(name)) tab.sources.delete(name);
21503
+ if (events.length || statusChanged) {
21504
+ this.publish();
21505
+ this.schedule();
21506
+ }
21507
+ }
21508
+ });
21509
+ tab.tailer.start();
21510
+ }
21511
+ schedule() {
21512
+ if (this.timer || this.working || !this.settings.enabled || this.settings.engine !== "clef-flash" || this.clef.state === "error") return;
21513
+ if (![...this.tabs.values()].some((t) => t.pending.size)) return;
21514
+ this.timer = setTimeout(() => {
21515
+ this.timer = null;
21516
+ void this.infer();
21517
+ }, 1e3);
21518
+ }
21519
+ async infer() {
21520
+ const candidates = [...this.tabs].filter(([, t]) => t.pending.size && !t.ended);
21521
+ const candidate = candidates[this.round++ % candidates.length];
21522
+ if (!candidate || !this.settings.enabled || this.settings.engine !== "clef-flash") return;
21523
+ const [tabId, tab] = candidate;
21524
+ const tree = tab.tree;
21525
+ const ids = [...tab.pending].slice(0, 2);
21526
+ const job = tree.request(ids);
21527
+ const consumed = job?.ids || ids;
21528
+ consumed.forEach((id) => tab.pending.delete(id));
21529
+ if (!job) {
21530
+ this.schedule();
21531
+ return;
21532
+ }
21533
+ const epoch = this.epoch;
21534
+ this.working = true;
21535
+ try {
21536
+ const answers = await this.clef.predict(this.settings, job.request);
21537
+ if (epoch === this.epoch && this.tabs.get(tabId) === tab && !tab.ended && tab.tree === tree) tree.apply(job, answers);
21538
+ } catch {
21539
+ } finally {
21540
+ this.working = false;
21541
+ this.publish();
21542
+ this.schedule();
21543
+ }
21544
+ }
21545
+ publish() {
21546
+ if (this.publishing) return;
21547
+ this.publishing = setTimeout(() => {
21548
+ this.publishing = null;
21549
+ for (const tabId of this.tabs.keys()) this.onUpdate(this.snapshot(tabId));
21550
+ }, 120);
21551
+ }
21552
+ shutdown() {
21553
+ this.settings.enabled = false;
21554
+ ++this.epoch;
21555
+ for (const tab of this.tabs.values()) tab.tailer?.stop();
21556
+ this.clef.stop();
21557
+ if (this.timer) clearTimeout(this.timer);
21558
+ if (this.publishing) clearTimeout(this.publishing);
21559
+ this.timer = this.publishing = null;
21560
+ this.tabs.clear();
21561
+ this.owners.clear();
21562
+ }
21563
+ };
21564
+
20685
21565
  // src/main/orchestrator.ts
21566
+ var import_check_work_map_gpu2 = __toESM(require_check_work_map_gpu());
20686
21567
  var DEFAULT_IDLE_TIMEOUT_MIN = 15;
21568
+ var OBSERVER_ON_HOLD = true;
20687
21569
  var DEFAULT_PROFILES = {
20688
21570
  production: {
20689
21571
  name: "Production",
@@ -20706,6 +21588,7 @@ var Orchestrator = class {
20706
21588
  timeTracker = new TimeTracker(this.ctlsurfApi);
20707
21589
  ticketStore = new TicketStore(this.ctlsurfApi);
20708
21590
  observer;
21591
+ workMap;
20709
21592
  // State
20710
21593
  tabs = /* @__PURE__ */ new Map();
20711
21594
  activeTabId = null;
@@ -20725,19 +21608,24 @@ var Orchestrator = class {
20725
21608
  // until the next remote spawn for that target consumes them — never persisted.
20726
21609
  pendingSshPasswords = /* @__PURE__ */ new Map();
20727
21610
  pendingSshPasswordTimers = /* @__PURE__ */ new Map();
20728
- constructor(settingsDir, events) {
21611
+ constructor(settingsDir, events, options) {
20729
21612
  this.settingsDir = settingsDir;
20730
21613
  this.events = events;
21614
+ this.workMap = new WorkMap(options?.appRoot || process.cwd(), (snapshot) => this.events.onWorkMapUpdate?.(snapshot), {}, (0, import_check_work_map_gpu2.initialCapability)({ desktop: options?.desktop === true }));
20731
21615
  this.observer = new Observer({
20732
21616
  settingsDir,
20733
21617
  api: this.ctlsurfApi,
20734
- getSettings: () => this.settings.observer || {},
21618
+ getSettings: () => ({
21619
+ ...this.settings.observer,
21620
+ enabled: !OBSERVER_ON_HOLD && !!this.settings.observer?.enabled
21621
+ }),
20735
21622
  onUpdate: (item) => this.events.onObserverUpdate?.(item),
20736
21623
  onActivity: (reviewing) => this.events.onObserverActivity?.(reviewing)
20737
21624
  });
20738
21625
  this.stateMonitor = new AgentStateMonitor(({ tabId, state, anyAwaiting }) => {
20739
21626
  this.events.onAgentStateChange?.(tabId, state, anyAwaiting);
20740
21627
  this.observer.noteAgentState(tabId, state);
21628
+ this.workMap.noteState(tabId, state);
20741
21629
  });
20742
21630
  this.stateMonitor.start();
20743
21631
  this.workerWs = new WorkerWsClient({
@@ -20809,13 +21697,24 @@ var Orchestrator = class {
20809
21697
  this.saveSettings();
20810
21698
  this.restartActiveChatLogging();
20811
21699
  }
21700
+ configureWorkMap(data) {
21701
+ const capability = this.workMap.getCapability();
21702
+ if (data.enabled && capability.state !== "available") throw new Error(capability.reason || "Work map is unavailable on this machine.");
21703
+ this.settings.workMap = this.workMap.configure(data);
21704
+ this.saveSettings();
21705
+ }
21706
+ setWorkMapCapability(capability) {
21707
+ this.workMap.setCapability(capability);
21708
+ this.workMap.configure({ ...this.settings.workMap, enabled: capability.state === "available" && !!this.settings.workMap?.enabled });
21709
+ this.events.onWorkMapCapability?.(capability);
21710
+ }
20812
21711
  // ─── Observer settings ──────────────────────────
20813
21712
  /** Summary for the settings UI — never echoes the API key back. */
20814
21713
  getObserverSettingsSummary() {
20815
21714
  const o = this.settings.observer || {};
20816
21715
  const keySource = o.anthropicApiKey ? "settings" : process.env.ANTHROPIC_API_KEY ? "env" : null;
20817
21716
  return {
20818
- enabled: !!o.enabled,
21717
+ enabled: !OBSERVER_ON_HOLD && !!o.enabled,
20819
21718
  hasApiKey: keySource !== null,
20820
21719
  keySource,
20821
21720
  dailyCapUsd: o.dailyCapUsd ?? OBSERVER_DEFAULTS.dailyCapUsd
@@ -20934,13 +21833,13 @@ var Orchestrator = class {
20934
21833
  }
20935
21834
  loadSettings() {
20936
21835
  try {
20937
- fs7.mkdirSync(this.settingsDir, { recursive: true });
21836
+ fs10.mkdirSync(this.settingsDir, { recursive: true });
20938
21837
  } catch {
20939
21838
  }
20940
- const settingsPath = path10.join(this.settingsDir, "settings.json");
21839
+ const settingsPath = path14.join(this.settingsDir, "settings.json");
20941
21840
  try {
20942
- if (fs7.existsSync(settingsPath)) {
20943
- const raw = JSON.parse(fs7.readFileSync(settingsPath, "utf-8"));
21841
+ if (fs10.existsSync(settingsPath)) {
21842
+ const raw = JSON.parse(fs10.readFileSync(settingsPath, "utf-8"));
20944
21843
  if (!raw.profiles) {
20945
21844
  this.settings = {
20946
21845
  activeProfile: "production",
@@ -20975,12 +21874,13 @@ var Orchestrator = class {
20975
21874
  }
20976
21875
  this.applyProfile(this.getActiveProfile());
20977
21876
  this.bridge.setLoggingEnabled(!!this.settings.logChat);
21877
+ this.workMap.configure({ ...this.settings.workMap, enabled: !!this.events.onWorkMapUpdate && !!this.settings.workMap?.enabled });
20978
21878
  }
20979
21879
  saveSettings() {
20980
- const settingsPath = path10.join(this.settingsDir, "settings.json");
21880
+ const settingsPath = path14.join(this.settingsDir, "settings.json");
20981
21881
  try {
20982
- fs7.mkdirSync(this.settingsDir, { recursive: true });
20983
- fs7.writeFileSync(settingsPath, JSON.stringify(this.settings, null, 2));
21882
+ fs10.mkdirSync(this.settingsDir, { recursive: true });
21883
+ fs10.writeFileSync(settingsPath, JSON.stringify(this.settings, null, 2));
20984
21884
  } catch (err) {
20985
21885
  log("[settings] Failed to save:", err.message);
20986
21886
  }
@@ -21121,6 +22021,7 @@ var Orchestrator = class {
21121
22021
  this.tabs.delete(tabId);
21122
22022
  this.stateMonitor.removeTab(tabId);
21123
22023
  void this.observer.endTab(tabId, existing.projectRootPath);
22024
+ this.workMap.remove(tabId);
21124
22025
  existing.ptyManager.kill();
21125
22026
  await this.timeTracker.endSession(tabId);
21126
22027
  }
@@ -21135,6 +22036,7 @@ var Orchestrator = class {
21135
22036
  const tab = { ptyManager, agent, cwd, termStreamBuffer: "", termStreamTimer: null };
21136
22037
  this.tabs.set(tabId, tab);
21137
22038
  this.stateMonitor.trackTab(tabId, agent.id, cwd);
22039
+ this.workMap.attach(tabId, agent.id, agent.name, cwd);
21138
22040
  if (isRemoteAgent(agent)) {
21139
22041
  const target = agent.args[1];
21140
22042
  const pw = target ? this.consumePendingSshPassword(target) : void 0;
@@ -21156,6 +22058,7 @@ var Orchestrator = class {
21156
22058
  if (this.tabs.get(tabId) !== tab) return;
21157
22059
  this.events.onPtyExit(tabId, exitCode);
21158
22060
  const observerEnd = this.observer.endTab(tabId, tab.projectRootPath);
22061
+ this.workMap.end(tabId);
21159
22062
  await this.timeTracker.endSession(tabId);
21160
22063
  void observerEnd;
21161
22064
  if (this.tabs.get(tabId) !== tab) return;
@@ -21207,6 +22110,7 @@ var Orchestrator = class {
21207
22110
  }
21208
22111
  async killTab(tabId) {
21209
22112
  const tab = this.tabs.get(tabId);
22113
+ this.workMap.remove(tabId);
21210
22114
  if (!tab) return;
21211
22115
  if (tab.termStreamTimer) clearTimeout(tab.termStreamTimer);
21212
22116
  await this.timeTracker.endSession(tabId);
@@ -21338,7 +22242,7 @@ var Orchestrator = class {
21338
22242
  }
21339
22243
  this.stopNoProjectPolling();
21340
22244
  this.workerWs.connect({
21341
- machine: os4.hostname(),
22245
+ machine: os5.hostname(),
21342
22246
  cwd,
21343
22247
  agent: agent.name
21344
22248
  });
@@ -21407,6 +22311,7 @@ var Orchestrator = class {
21407
22311
  }
21408
22312
  // ─── Shutdown ───────────────────────────────────
21409
22313
  async shutdown() {
22314
+ this.workMap.shutdown();
21410
22315
  this.stopNoProjectPolling();
21411
22316
  this.stopChatLogging();
21412
22317
  this.stateMonitor.stop();
@@ -21422,18 +22327,18 @@ var Orchestrator = class {
21422
22327
  };
21423
22328
 
21424
22329
  // src/main/settingsDir.ts
21425
- import path11 from "path";
21426
- import os5 from "os";
22330
+ import path15 from "path";
22331
+ import os6 from "os";
21427
22332
  function getSettingsDir(useElectron) {
21428
22333
  if (useElectron) {
21429
22334
  const { app } = require_electron();
21430
22335
  return app.getPath("userData");
21431
22336
  }
21432
22337
  if (process.platform === "darwin") {
21433
- return path11.join(os5.homedir(), "Library", "Application Support", "ctlsurf-worker");
22338
+ return path15.join(os6.homedir(), "Library", "Application Support", "ctlsurf-worker");
21434
22339
  }
21435
- return path11.join(
21436
- process.env.XDG_CONFIG_HOME || path11.join(os5.homedir(), ".config"),
22340
+ return path15.join(
22341
+ process.env.XDG_CONFIG_HOME || path15.join(os6.homedir(), ".config"),
21437
22342
  "ctlsurf-worker"
21438
22343
  );
21439
22344
  }
@@ -21737,9 +22642,9 @@ var Tui = class {
21737
22642
 
21738
22643
  // src/main/monitor.ts
21739
22644
  import { execFile as execFile2 } from "child_process";
21740
- import fs8 from "fs";
21741
- import os6 from "os";
21742
- import path12 from "path";
22645
+ import fs11 from "fs";
22646
+ import os7 from "os";
22647
+ import path16 from "path";
21743
22648
  var FAST_MS = 3e3;
21744
22649
  var SLOW_MS = 1e4;
21745
22650
  var IDLE_STOP_MS = 12e4;
@@ -21764,7 +22669,7 @@ function run(cmd, args, opts = {}) {
21764
22669
  });
21765
22670
  }
21766
22671
  function serviceFor(agent) {
21767
- const cmd = isRemoteAgent(agent) ? agent.args.slice(2).join(" ") : path12.basename(agent.command);
22672
+ const cmd = isRemoteAgent(agent) ? agent.args.slice(2).join(" ") : path16.basename(agent.command);
21768
22673
  if (/\bcodex\b/.test(cmd)) return "codex";
21769
22674
  if (/\bclaude\b/.test(cmd)) return "claude";
21770
22675
  return null;
@@ -21772,7 +22677,7 @@ function serviceFor(agent) {
21772
22677
  function cpuTimes() {
21773
22678
  let idle = 0;
21774
22679
  let total = 0;
21775
- for (const c of os6.cpus()) {
22680
+ for (const c of os7.cpus()) {
21776
22681
  const t = c.times;
21777
22682
  idle += t.idle;
21778
22683
  total += t.user + t.nice + t.sys + t.idle + t.irq;
@@ -21780,8 +22685,8 @@ function cpuTimes() {
21780
22685
  return { idle, total };
21781
22686
  }
21782
22687
  async function memory() {
21783
- const total = os6.totalmem();
21784
- let avail = os6.freemem();
22688
+ const total = os7.totalmem();
22689
+ let avail = os7.freemem();
21785
22690
  try {
21786
22691
  if (process.platform === "darwin") {
21787
22692
  const out = await run("vm_stat", []);
@@ -21789,7 +22694,7 @@ async function memory() {
21789
22694
  const pages = (name) => Number(new RegExp(`Pages ${name}:\\s+(\\d+)`).exec(out)?.[1] ?? 0);
21790
22695
  avail = (pages("free") + pages("inactive") + pages("speculative")) * page;
21791
22696
  } else if (process.platform === "linux") {
21792
- const m = /MemAvailable:\s+(\d+) kB/.exec(await fs8.promises.readFile("/proc/meminfo", "utf-8"));
22697
+ const m = /MemAvailable:\s+(\d+) kB/.exec(await fs11.promises.readFile("/proc/meminfo", "utf-8"));
21793
22698
  if (m) avail = Number(m[1]) * 1024;
21794
22699
  }
21795
22700
  } catch {
@@ -21798,9 +22703,9 @@ async function memory() {
21798
22703
  return { total, used: total - avail, pct: round(100 * (total - avail) / total) };
21799
22704
  }
21800
22705
  async function diskUsage() {
21801
- if (typeof fs8.promises.statfs !== "function") return null;
22706
+ if (typeof fs11.promises.statfs !== "function") return null;
21802
22707
  try {
21803
- const s = await fs8.promises.statfs(os6.homedir());
22708
+ const s = await fs11.promises.statfs(os7.homedir());
21804
22709
  return { total: s.blocks * s.bsize, free: s.bavail * s.bsize };
21805
22710
  } catch {
21806
22711
  return null;
@@ -21888,7 +22793,7 @@ async function claudeUsage() {
21888
22793
  const out = await run(
21889
22794
  "claude",
21890
22795
  ["-p", "/usage", "--output-format", "json", "--no-session-persistence"],
21891
- { cwd: os6.tmpdir(), timeout: 4e4 }
22796
+ { cwd: os7.tmpdir(), timeout: 4e4 }
21892
22797
  );
21893
22798
  text = String(JSON.parse(out || "{}").result ?? "");
21894
22799
  } catch (err) {
@@ -21924,7 +22829,7 @@ function codexWindow(minutes) {
21924
22829
  return { label: s, short: s };
21925
22830
  }
21926
22831
  async function readTail(file, bytes) {
21927
- const fh = await fs8.promises.open(file, "r");
22832
+ const fh = await fs11.promises.open(file, "r");
21928
22833
  try {
21929
22834
  const { size } = await fh.stat();
21930
22835
  const start = Math.max(0, size - bytes);
@@ -21936,7 +22841,7 @@ async function readTail(file, bytes) {
21936
22841
  }
21937
22842
  }
21938
22843
  async function codexSessionFiles(root, limit2) {
21939
- const sortedDirs = async (dir) => (await fs8.promises.readdir(dir, { withFileTypes: true }).catch(() => [])).filter((d) => d.isDirectory()).map((d) => path12.join(dir, d.name)).sort().reverse();
22844
+ const sortedDirs = async (dir) => (await fs11.promises.readdir(dir, { withFileTypes: true }).catch(() => [])).filter((d) => d.isDirectory()).map((d) => path16.join(dir, d.name)).sort().reverse();
21940
22845
  const days = [];
21941
22846
  for (const y of await sortedDirs(root)) {
21942
22847
  for (const m of await sortedDirs(y)) {
@@ -21947,20 +22852,20 @@ async function codexSessionFiles(root, limit2) {
21947
22852
  }
21948
22853
  const files = [];
21949
22854
  for (const day of days.slice(0, 14)) {
21950
- for (const name of await fs8.promises.readdir(day).catch(() => [])) {
22855
+ for (const name of await fs11.promises.readdir(day).catch(() => [])) {
21951
22856
  if (!name.startsWith("rollout-") || !name.endsWith(".jsonl")) continue;
21952
- const file = path12.join(day, name);
22857
+ const file = path16.join(day, name);
21953
22858
  try {
21954
- files.push({ file, mtime: (await fs8.promises.stat(file)).mtimeMs });
22859
+ files.push({ file, mtime: (await fs11.promises.stat(file)).mtimeMs });
21955
22860
  } catch {
21956
22861
  }
21957
22862
  }
21958
22863
  }
21959
22864
  return files.sort((a, b) => b.mtime - a.mtime).slice(0, limit2).map((f) => f.file);
21960
22865
  }
21961
- async function codexUsage(home = os6.homedir()) {
22866
+ async function codexUsage(home = os7.homedir()) {
21962
22867
  const source = "your most recent Codex session";
21963
- for (const file of await codexSessionFiles(path12.join(home, ".codex", "sessions"), 5)) {
22868
+ for (const file of await codexSessionFiles(path16.join(home, ".codex", "sessions"), 5)) {
21964
22869
  let lines;
21965
22870
  try {
21966
22871
  lines = (await readTail(file, CODEX_TAIL_BYTES)).split("\n");
@@ -21985,7 +22890,7 @@ async function codexUsage(home = os6.homedir()) {
21985
22890
  windows.push({ label, short, pct: Number(w.used_percent), resets });
21986
22891
  }
21987
22892
  if (windows.length) {
21988
- const ts = new Date((await fs8.promises.stat(file)).mtimeMs).toISOString();
22893
+ const ts = new Date((await fs11.promises.stat(file)).mtimeMs).toISOString();
21989
22894
  return { ok: true, windows, plan: rl.plan_type ?? null, source, ts };
21990
22895
  }
21991
22896
  }
@@ -22055,7 +22960,7 @@ var ResourceMonitor = class {
22055
22960
  this.machine = {
22056
22961
  ok: true,
22057
22962
  ts: now(),
22058
- cpu: { pct: cpuPct, cores: os6.cpus().length, load: os6.loadavg().map((x) => round(x, 2)) },
22963
+ cpu: { pct: cpuPct, cores: os7.cpus().length, load: os7.loadavg().map((x) => round(x, 2)) },
22059
22964
  mem,
22060
22965
  disk,
22061
22966
  gpu
@@ -22093,7 +22998,7 @@ var ResourceMonitor = class {
22093
22998
  return {
22094
22999
  machine: {
22095
23000
  ...this.machine,
22096
- label: process.platform === "darwin" ? "This Mac" : os6.hostname(),
23001
+ label: process.platform === "darwin" ? "This Mac" : os7.hostname(),
22097
23002
  history: [...this.history]
22098
23003
  },
22099
23004
  agents: this.agents,