runwork 0.26.0 → 0.27.1

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/index.js CHANGED
@@ -427,6 +427,124 @@ function safeRm(path) {
427
427
  var MAX_REDIRECTS = 10, transportOverride = "auto";
428
428
  var init_http = () => {};
429
429
 
430
+ // ../../shared/utils/integration-body.ts
431
+ function findHeader(headers, name) {
432
+ if (!headers)
433
+ return;
434
+ const wanted = name.toLowerCase();
435
+ for (const [key, value] of Object.entries(headers)) {
436
+ if (key.toLowerCase() === wanted)
437
+ return value;
438
+ }
439
+ return;
440
+ }
441
+ function setHeader(headers, name, value) {
442
+ const wanted = name.toLowerCase();
443
+ const next = {};
444
+ for (const [key, existing] of Object.entries(headers)) {
445
+ if (key.toLowerCase() !== wanted)
446
+ next[key] = existing;
447
+ }
448
+ next[name] = value;
449
+ return next;
450
+ }
451
+ function mediaType(contentType) {
452
+ return (contentType ?? "").split(";")[0].trim().toLowerCase();
453
+ }
454
+ function isJsonContentType(contentType) {
455
+ const type = mediaType(contentType);
456
+ return type === JSON_CONTENT_TYPE || type.endsWith("+json");
457
+ }
458
+ function isFormContentType(contentType) {
459
+ return mediaType(contentType) === FORM_CONTENT_TYPE;
460
+ }
461
+ function isMultipartContentType(contentType) {
462
+ return mediaType(contentType) === "multipart/form-data";
463
+ }
464
+ function appendFormValue(out, key, value) {
465
+ if (value === undefined)
466
+ return;
467
+ if (value === null) {
468
+ out.append(key, "");
469
+ return;
470
+ }
471
+ if (Array.isArray(value)) {
472
+ value.forEach((item, index) => appendFormValue(out, `${key}[${index}]`, item));
473
+ return;
474
+ }
475
+ if (typeof value === "object") {
476
+ for (const [childKey, childValue] of Object.entries(value)) {
477
+ appendFormValue(out, `${key}[${childKey}]`, childValue);
478
+ }
479
+ return;
480
+ }
481
+ out.append(key, String(value));
482
+ }
483
+ function encodeFormBody(value) {
484
+ if (typeof value === "string")
485
+ return value;
486
+ if (value === undefined || value === null)
487
+ return "";
488
+ const out = new URLSearchParams;
489
+ if (Array.isArray(value) || typeof value === "object") {
490
+ for (const [key, child] of Object.entries(value)) {
491
+ appendFormValue(out, key, child);
492
+ }
493
+ } else {
494
+ out.append("value", String(value));
495
+ }
496
+ return out.toString();
497
+ }
498
+ function looksLikeJson(text) {
499
+ const trimmed = text.trim();
500
+ if (!(trimmed.startsWith("{") || trimmed.startsWith("[")))
501
+ return false;
502
+ try {
503
+ JSON.parse(trimmed);
504
+ return true;
505
+ } catch {
506
+ return false;
507
+ }
508
+ }
509
+ function encodeIntegrationBody(body, contentType) {
510
+ if (body === undefined || body === null) {
511
+ return { body: undefined, contentType };
512
+ }
513
+ if (isMultipartContentType(contentType)) {
514
+ throw new Error("multipart/form-data bodies are not supported by the integrations proxy. Send application/x-www-form-urlencoded or JSON instead.");
515
+ }
516
+ if (typeof body === "string") {
517
+ if (contentType)
518
+ return { body, contentType };
519
+ return { body, contentType: looksLikeJson(body) ? JSON_CONTENT_TYPE : TEXT_CONTENT_TYPE };
520
+ }
521
+ if (isFormContentType(contentType)) {
522
+ return { body: encodeFormBody(body), contentType };
523
+ }
524
+ return { body: JSON.stringify(body), contentType: contentType ?? JSON_CONTENT_TYPE };
525
+ }
526
+ function encodeIntegrationRequest(body, headers = {}) {
527
+ const encoded = encodeIntegrationBody(body, findHeader(headers, "Content-Type"));
528
+ if (encoded.body === undefined) {
529
+ return { body: undefined, headers };
530
+ }
531
+ return {
532
+ body: encoded.body,
533
+ headers: setHeader(headers, "Content-Type", encoded.contentType ?? JSON_CONTENT_TYPE)
534
+ };
535
+ }
536
+ function parseBodyArgument(text, contentType) {
537
+ try {
538
+ return JSON.parse(text);
539
+ } catch {
540
+ if (contentType && !isJsonContentType(contentType)) {
541
+ return text;
542
+ }
543
+ throw new Error('Body is not valid JSON. To send a raw or form-encoded body, set a matching Content-Type header (for example --header "Content-Type: application/x-www-form-urlencoded").');
544
+ }
545
+ }
546
+ var JSON_CONTENT_TYPE = "application/json", FORM_CONTENT_TYPE = "application/x-www-form-urlencoded", TEXT_CONTENT_TYPE = "text/plain; charset=utf-8";
547
+
430
548
  // src/api/client.ts
431
549
  class ApiClient {
432
550
  baseUrl;
@@ -868,22 +986,22 @@ class ApiClient {
868
986
  return res.data;
869
987
  }
870
988
  async callIntegrationProxy(integrationDbId, method, path, opts) {
871
- const targetPath = opts?.query ? `${path}?${opts.query}` : path;
989
+ const targetPath = opts?.query ? `${path}${path.includes("?") ? "&" : "?"}${opts.query}` : path;
872
990
  const url = `${this.baseUrl}/api/proxy/integrations${targetPath}`;
873
- const headers = {
991
+ const upperMethod = method.toUpperCase();
992
+ const hasBody = opts?.body !== undefined && opts?.body !== null && upperMethod !== "GET" && upperMethod !== "HEAD";
993
+ const encoded = encodeIntegrationRequest(hasBody ? opts?.body : undefined, {
874
994
  "X-Workspace-Integration-Id": integrationDbId,
875
- ...Object.fromEntries(Object.entries(opts?.headers || {}))
876
- };
995
+ ...opts?.headers || {}
996
+ });
997
+ const headers = encoded.headers;
877
998
  if (this.apiKey) {
878
999
  headers["Authorization"] = `Bearer ${this.apiKey}`;
879
1000
  }
880
- if (opts?.body) {
881
- headers["Content-Type"] = "application/json";
882
- }
883
1001
  const response = await httpFetch(url, {
884
- method,
1002
+ method: upperMethod,
885
1003
  headers,
886
- body: opts?.body ? JSON.stringify(opts.body) : undefined
1004
+ body: encoded.body
887
1005
  });
888
1006
  if (!response.ok) {
889
1007
  const body = await response.text();
@@ -6212,6 +6330,16 @@ export declare class WorkflowInstanceDO extends DurableObject<Env> {
6212
6330
  * - Creates WorkflowInstance DOs
6213
6331
  * - Maintains an index for querying workflows
6214
6332
  * - Routes signals to correct instances
6333
+ *
6334
+ * Index storage: one storage key per instance entry (\`index:<instanceId>\`),
6335
+ * read back with a prefix list. A single-value index hits the 2 MB per-value
6336
+ * limit of SQLite-backed DO storage at roughly 11,000 entries, after which every
6337
+ * write fails with SQLITE_TOOBIG. Apps deployed before the per-key layout still
6338
+ * hold the legacy \`workflow_index\` value; it is migrated on first load.
6339
+ *
6340
+ * Retention: terminal entries older than the retention window are pruned from
6341
+ * a self-armed alarm, and the index is trimmed inline when a write pushes it
6342
+ * past the entry cap, so the index stays bounded without an external caller.
6215
6343
  */
6216
6344
  import { DurableObject } from 'cloudflare:workers';
6217
6345
  import type { NativeWorkflowStatus, NativeWorkflowConfig, ListWorkflowsOptions, WorkflowInstanceInfo, WorkflowInstanceStub } from './core-workflow-types';
@@ -6225,8 +6353,14 @@ import { type Env } from './core-utils';
6225
6353
  */
6226
6354
  export declare class WorkflowCoordinator extends DurableObject<Env> {
6227
6355
  private index;
6356
+ /** Entry cap applied inline on writes and by the retention alarm. */
6357
+ readonly retentionMaxEntries = 10000;
6228
6358
  /**
6229
- * Create a new workflow instance
6359
+ * Create a new workflow instance.
6360
+ *
6361
+ * The index entry and stored params are written before the instance starts,
6362
+ * so a completion notification from a fast workflow can never race ahead of
6363
+ * its own pending entry, and an index failure surfaces before any work runs.
6230
6364
  */
6231
6365
  create(workflowName: string, params: Record<string, unknown>, config?: Partial<NativeWorkflowConfig>, metadata?: Record<string, unknown>): Promise<string>;
6232
6366
  /**
@@ -6271,16 +6405,38 @@ export declare class WorkflowCoordinator extends DurableObject<Env> {
6271
6405
  byWorkflow: Record<string, number>;
6272
6406
  }>;
6273
6407
  /**
6274
- * Clean up completed/old workflow entries
6275
- * Should be called periodically to prevent index bloat
6408
+ * Clean up completed/old workflow entries.
6409
+ *
6410
+ * Removes terminal entries older than \`olderThanMs\`, every completed entry
6411
+ * unless \`keepCompleted\` is set, and then the oldest terminal entries until
6412
+ * the index fits within \`maxEntries\`. Active entries (pending, running,
6413
+ * sleeping, waiting, paused) are never removed. Runs from the retention alarm
6414
+ * and inline on writes; explicit calls remain supported.
6276
6415
  */
6277
6416
  cleanup(options?: {
6278
6417
  olderThanMs?: number;
6279
6418
  keepCompleted?: boolean;
6280
6419
  maxEntries?: number;
6281
6420
  }): Promise<number>;
6421
+ /**
6422
+ * Retention alarm: prune old terminal entries and re-arm while the index
6423
+ * still holds anything.
6424
+ */
6425
+ alarm(): Promise<void>;
6282
6426
  private ensureIndexLoaded;
6283
- private persistIndex;
6427
+ /**
6428
+ * Move a legacy single-value index into per-entry keys. Per-entry values
6429
+ * already present win, since they were written after the legacy value.
6430
+ * An unreadable legacy value is dropped: the workflow instances themselves
6431
+ * still hold their state, only the listing loses history.
6432
+ */
6433
+ private migrateLegacyIndex;
6434
+ private deleteLegacyIndexKey;
6435
+ /**
6436
+ * Remove index entries and their stored params, in storage batches.
6437
+ */
6438
+ private removeEntries;
6439
+ private ensureRetentionAlarm;
6284
6440
  }
6285
6441
  `,
6286
6442
  "core-integration-entities.d.ts": `/**
@@ -7962,14 +8118,17 @@ export declare const integrationApiSchema: z.ZodObject<{
7962
8118
  method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
7963
8119
  endpoint: z.ZodString;
7964
8120
  data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
8121
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
7965
8122
  }, "strip", z.ZodTypeAny, {
7966
8123
  endpoint: string;
7967
8124
  method: "POST" | "GET" | "PUT" | "PATCH" | "DELETE";
7968
8125
  data?: Record<string, unknown> | undefined;
8126
+ headers?: Record<string, string> | undefined;
7969
8127
  }, {
7970
8128
  endpoint: string;
7971
8129
  data?: Record<string, unknown> | undefined;
7972
8130
  method?: "POST" | "GET" | "PUT" | "PATCH" | "DELETE" | undefined;
8131
+ headers?: Record<string, string> | undefined;
7973
8132
  }>;
7974
8133
  /**
7975
8134
  * Get tool definitions for integration access
@@ -8205,7 +8364,7 @@ function createKeyboardListener() {
8205
8364
  }
8206
8365
 
8207
8366
  // src/generated/version.ts
8208
- var VERSION = "0.26.0";
8367
+ var VERSION = "0.27.1";
8209
8368
 
8210
8369
  // src/commands/dev.ts
8211
8370
  var exports_dev = {};
@@ -9184,6 +9343,14 @@ function expandWindowsPathTemplate(path2, resolved) {
9184
9343
  }
9185
9344
  return { path: path2, needsHomeJoin: !/^([A-Za-z]:[\\/]|\\\\|\/)/.test(path2) };
9186
9345
  }
9346
+ function parseConfigDeclaredPath(text2, key) {
9347
+ const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9348
+ const match = new RegExp(`^\\s*${escapedKey}\\s*=\\s*"((?:[^"\\\\]|\\\\.)*)"`, "m").exec(text2);
9349
+ if (!match)
9350
+ return null;
9351
+ const path2 = match[1].replace(/\\(.)/g, "$1");
9352
+ return path2 || null;
9353
+ }
9187
9354
  var PATH_REFRESH_FAILED_MARKER = "__runwork_path_refresh_failed__", WINDOWS_PATH_REFRESH, COMMAND_NOT_FOUND_EXIT_CODES, WINDOWS_PATH_PLACEHOLDERS;
9188
9355
  var init_detection_probes = __esm(() => {
9189
9356
  WINDOWS_PATH_REFRESH = "try { $env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + " + "[Environment]::GetEnvironmentVariable('Path','User') + ';' + $env:Path } " + `catch { Write-Output '${PATH_REFRESH_FAILED_MARKER}' }; `;
@@ -9605,6 +9772,9 @@ function getAgent(slug) {
9605
9772
  function getAgents() {
9606
9773
  return AGENT_REGISTRY;
9607
9774
  }
9775
+ function getDetectableAgents() {
9776
+ return AGENT_REGISTRY.filter((a) => a.detection);
9777
+ }
9608
9778
  function isConnectOnlyAgent(agent) {
9609
9779
  if (!agent)
9610
9780
  return false;
@@ -9633,11 +9803,15 @@ function resolveAgentCli(agent) {
9633
9803
  return;
9634
9804
  return detectionBinaryTarget(agent.detection);
9635
9805
  }
9636
- var CLAUDE_CODE_NATIVE_INSTALL_PATHS, CHATGPT_SECURITY_SETTINGS_URL = "https://chatgpt.com/plugins#settings/Security", CHATGPT_CREATE_CONNECTOR_URL = "https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins", AGENT_REGISTRY, slugIndex, nameIndex, CUSTOM_ADAPTER_SLUGS, getRegistryAgent, getRegistryAgents;
9806
+ var CLAUDE_CODE_NATIVE_INSTALL_PATHS, CODEX_CONFIG_FILE = ".codex/config.toml", CODEX_BUNDLED_CLI_PATHS, CHATGPT_SECURITY_SETTINGS_URL = "https://chatgpt.com/plugins#settings/Security", CHATGPT_CREATE_CONNECTOR_URL = "https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins", AGENT_REGISTRY, slugIndex, nameIndex, CUSTOM_ADAPTER_SLUGS, getRegistryAgent, getRegistryAgents;
9637
9807
  var init_registry_data = __esm(() => {
9638
9808
  CLAUDE_CODE_NATIVE_INSTALL_PATHS = [
9639
9809
  { macos: ".local/bin/claude", linux: ".local/bin/claude", windows: ".local/bin/claude.exe" }
9640
9810
  ];
9811
+ CODEX_BUNDLED_CLI_PATHS = [
9812
+ { macos: "/Applications/ChatGPT.app/Contents/Resources/codex" },
9813
+ { macos: "/Applications/Codex.app/Contents/Resources/codex" }
9814
+ ];
9641
9815
  AGENT_REGISTRY = [
9642
9816
  {
9643
9817
  slug: "claude-code",
@@ -9869,8 +10043,18 @@ var init_registry_data = __esm(() => {
9869
10043
  name: "Codex CLI",
9870
10044
  description: "AI in your terminal by OpenAI, great for coding, debugging, and automating dev tasks",
9871
10045
  category: "cli",
9872
- detection: { method: "binary", target: "codex" },
9873
- launch: { cli: "codex", cliAcceptsPrompt: true },
10046
+ detection: {
10047
+ method: "any",
10048
+ target: [
10049
+ { method: "binary", target: "codex" },
10050
+ {
10051
+ method: "config-value",
10052
+ target: { file: CODEX_CONFIG_FILE, key: "CODEX_CLI_PATH" }
10053
+ },
10054
+ ...CODEX_BUNDLED_CLI_PATHS.map((target) => ({ method: "path", target }))
10055
+ ]
10056
+ },
10057
+ launch: { cli: "codex", cliAcceptsPrompt: true, cliWellKnownPaths: CODEX_BUNDLED_CLI_PATHS },
9874
10058
  logo: "codex",
9875
10059
  downloadUrl: "https://learn.chatgpt.com/docs/codex/cli",
9876
10060
  install: {
@@ -9907,6 +10091,7 @@ var init_registry_data = __esm(() => {
9907
10091
  launch: { url: "https://chatgpt.com/?prompt={prompt}" },
9908
10092
  logo: "openai",
9909
10093
  downloadUrl: "https://chatgpt.com",
10094
+ suggestsCli: "codex",
9910
10095
  firstClass: true,
9911
10096
  resumeCapability: {
9912
10097
  mode: "url-prompt",
@@ -9963,6 +10148,7 @@ var init_registry_data = __esm(() => {
9963
10148
  ]
9964
10149
  },
9965
10150
  launch: { app: { macos: "ChatGPT Classic", windows: "ChatGPT Classic" }, bundleId: { macos: "com.openai.chat" }, appxPackage: "OpenAI.ChatGPT", url: "https://chatgpt.com/?prompt={prompt}" },
10151
+ suggestsCli: "codex",
9966
10152
  logo: "openai",
9967
10153
  downloadUrl: "https://chatgpt.com/download",
9968
10154
  downloadUrls: {
@@ -10208,12 +10394,145 @@ var init_registry_data = __esm(() => {
10208
10394
  getRegistryAgents = getAgents;
10209
10395
  });
10210
10396
 
10397
+ // src/agents/detection.ts
10398
+ import { execFile } from "child_process";
10399
+ import { existsSync as existsSync26, readFileSync as readFileSync23 } from "fs";
10400
+ import { homedir as homedir6, platform as platform2 } from "os";
10401
+ import { join as join22 } from "path";
10402
+ import { promisify } from "util";
10403
+ function isWindows() {
10404
+ return platform2() === "win32";
10405
+ }
10406
+ function toList(value) {
10407
+ return Array.isArray(value) ? value : [value];
10408
+ }
10409
+ async function runPowerShell(script) {
10410
+ const execFileAsync = promisify(execFile);
10411
+ try {
10412
+ await execFileAsync("powershell", ["-NoProfile", "-Command", script]);
10413
+ return true;
10414
+ } catch {
10415
+ return false;
10416
+ }
10417
+ }
10418
+ function resolveDetectionPath(target) {
10419
+ const resolved = resolvePlatformString(target);
10420
+ if (!resolved)
10421
+ return null;
10422
+ const expanded = expandWindowsPathTemplate(resolved, {
10423
+ "%APPDATA%": process.env.APPDATA,
10424
+ "%LOCALAPPDATA%": process.env.LOCALAPPDATA,
10425
+ "%ProgramFiles%": process.env.ProgramFiles
10426
+ });
10427
+ return expanded.needsHomeJoin ? join22(homedir6(), expanded.path) : expanded.path;
10428
+ }
10429
+ function checkPath(target) {
10430
+ const absolute = resolveDetectionPath(target);
10431
+ if (!absolute)
10432
+ return null;
10433
+ return existsSync26(absolute) ? absolute : null;
10434
+ }
10435
+ function checkConfigDeclaredPath(target) {
10436
+ const configPath = resolveDetectionPath(target.file);
10437
+ if (!configPath)
10438
+ return null;
10439
+ let text2;
10440
+ try {
10441
+ if (!existsSync26(configPath))
10442
+ return null;
10443
+ text2 = readFileSync23(configPath, "utf-8");
10444
+ } catch {
10445
+ return null;
10446
+ }
10447
+ const declared = parseConfigDeclaredPath(text2, target.key);
10448
+ return declared && existsSync26(declared) ? declared : null;
10449
+ }
10450
+ async function checkMacosBundleId(target) {
10451
+ if (platform2() !== "darwin")
10452
+ return false;
10453
+ const execFileAsync = promisify(execFile);
10454
+ for (const id of toList(target)) {
10455
+ if (!isValidBundleId(id))
10456
+ continue;
10457
+ try {
10458
+ await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
10459
+ return true;
10460
+ } catch {}
10461
+ }
10462
+ return false;
10463
+ }
10464
+ async function checkWindowsAppxPackage(target) {
10465
+ if (!isWindows())
10466
+ return false;
10467
+ const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
10468
+ const results = await Promise.all(probes);
10469
+ return results.some(Boolean);
10470
+ }
10471
+ async function checkWindowsStartApp(target) {
10472
+ if (!isWindows())
10473
+ return false;
10474
+ const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
10475
+ const results = await Promise.all(probes);
10476
+ return results.some(Boolean);
10477
+ }
10478
+ async function runAgentDetectionDetailed(detection) {
10479
+ switch (detection.method) {
10480
+ case "binary": {
10481
+ const target = resolvePlatformString(detection.target);
10482
+ const resolved = target ? whichBinary(target) : null;
10483
+ return resolved ? { detected: true, via: "binary", resolvedPath: resolved } : NOT_DETECTED;
10484
+ }
10485
+ case "path": {
10486
+ const resolved = checkPath(detection.target);
10487
+ return resolved ? { detected: true, via: "path", resolvedPath: resolved } : NOT_DETECTED;
10488
+ }
10489
+ case "config-value": {
10490
+ const resolved = checkConfigDeclaredPath(detection.target);
10491
+ return resolved ? { detected: true, via: "config-value", resolvedPath: resolved } : NOT_DETECTED;
10492
+ }
10493
+ case "windows-appx":
10494
+ return await checkWindowsAppxPackage(detection.target) ? { detected: true, via: "windows-appx" } : NOT_DETECTED;
10495
+ case "windows-start-app":
10496
+ return await checkWindowsStartApp(detection.target) ? { detected: true, via: "windows-start-app" } : NOT_DETECTED;
10497
+ case "macos-bundle-id":
10498
+ return await checkMacosBundleId(detection.target) ? { detected: true, via: "macos-bundle-id" } : NOT_DETECTED;
10499
+ case "any": {
10500
+ const probes = await Promise.all(detection.target.map((p) => runAgentDetectionDetailed(p)));
10501
+ return probes.find((p) => p.detected) ?? NOT_DETECTED;
10502
+ }
10503
+ case "always":
10504
+ return { detected: true, via: "always" };
10505
+ default:
10506
+ return NOT_DETECTED;
10507
+ }
10508
+ }
10509
+ async function runAgentDetection(detection) {
10510
+ return (await runAgentDetectionDetailed(detection)).detected;
10511
+ }
10512
+
10513
+ class RegistryDetectedAdapter {
10514
+ async detect() {
10515
+ const def = getRegistryAgent(this.slug);
10516
+ if (!def)
10517
+ return false;
10518
+ return runAgentDetection(def.detection);
10519
+ }
10520
+ }
10521
+ var NOT_DETECTED;
10522
+ var init_detection = __esm(() => {
10523
+ init_which();
10524
+ init_registry_data();
10525
+ init_registry();
10526
+ init_detection_probes();
10527
+ NOT_DETECTED = { detected: false };
10528
+ });
10529
+
10211
10530
  // src/agents/registry.ts
10212
- import { platform as platform2, homedir as homedir6 } from "os";
10213
- import { isAbsolute as isAbsolute2, join as join22 } from "path";
10214
- import { existsSync as existsSync26 } from "fs";
10531
+ import { platform as platform3, homedir as homedir7 } from "os";
10532
+ import { isAbsolute as isAbsolute3, join as join23 } from "path";
10533
+ import { existsSync as existsSync27 } from "fs";
10215
10534
  function getNodePlatform() {
10216
- const p = platform2();
10535
+ const p = platform3();
10217
10536
  if (p === "darwin")
10218
10537
  return "macos";
10219
10538
  if (p === "win32")
@@ -10230,7 +10549,7 @@ function resolveToAbsolute(ps, scope) {
10230
10549
  const resolved = resolvePlatformString(ps);
10231
10550
  if (!resolved)
10232
10551
  return;
10233
- return scope === "global" ? join22(homedir6(), resolved) : join22(process.cwd(), resolved);
10552
+ return scope === "global" ? join23(homedir7(), resolved) : join23(process.cwd(), resolved);
10234
10553
  }
10235
10554
  function resolveAgentCliCommand(slug) {
10236
10555
  const agent = getAgent(slug);
@@ -10239,19 +10558,40 @@ function resolveAgentCliCommand(slug) {
10239
10558
  return null;
10240
10559
  if (whichBinary(cli))
10241
10560
  return cli;
10561
+ const declared = vendorDeclaredCliPath(slug);
10562
+ if (declared)
10563
+ return declared;
10242
10564
  for (const candidate of agent?.launch?.cliWellKnownPaths ?? []) {
10243
10565
  const resolved = resolvePlatformString(candidate);
10244
10566
  if (!resolved)
10245
10567
  continue;
10246
- const absolute = isAbsolute2(resolved) ? resolved : join22(homedir6(), resolved);
10247
- if (existsSync26(absolute))
10568
+ const absolute = isAbsolute3(resolved) ? resolved : join23(homedir7(), resolved);
10569
+ if (existsSync27(absolute))
10248
10570
  return absolute;
10249
10571
  }
10250
10572
  return null;
10251
10573
  }
10574
+ function configValueMatchers(detection) {
10575
+ if (!detection)
10576
+ return [];
10577
+ if (detection.method === "config-value")
10578
+ return [detection.target];
10579
+ if (detection.method === "any")
10580
+ return detection.target.flatMap(configValueMatchers);
10581
+ return [];
10582
+ }
10583
+ function vendorDeclaredCliPath(slug) {
10584
+ for (const matcher of configValueMatchers(getAgent(slug)?.detection)) {
10585
+ const resolved = checkConfigDeclaredPath(matcher);
10586
+ if (resolved)
10587
+ return resolved;
10588
+ }
10589
+ return null;
10590
+ }
10252
10591
  var init_registry = __esm(() => {
10253
10592
  init_which();
10254
10593
  init_registry_data();
10594
+ init_detection();
10255
10595
  init_registry_data();
10256
10596
  });
10257
10597
 
@@ -11092,6 +11432,8 @@ function scanClaudeJsonlHead(head) {
11092
11432
  result.firstTimestamp = o.timestamp;
11093
11433
  if (!result.cwd && typeof o.cwd === "string")
11094
11434
  result.cwd = o.cwd;
11435
+ if (!result.surface && typeof o.entrypoint === "string")
11436
+ result.surface = o.entrypoint;
11095
11437
  if (!result.title && o.type === "ai-title" && typeof o.aiTitle === "string") {
11096
11438
  result.title = titleFromText(o.aiTitle);
11097
11439
  }
@@ -11117,7 +11459,7 @@ function scanClaudeJsonlHead(head) {
11117
11459
  }
11118
11460
  }
11119
11461
  }
11120
- if (result.title && result.firstTimestamp && result.cwd)
11462
+ if (result.title && result.firstTimestamp && result.cwd && result.surface)
11121
11463
  break;
11122
11464
  }
11123
11465
  if (!result.title && firstUserText)
@@ -11146,6 +11488,8 @@ function scanCodexRolloutHead(head) {
11146
11488
  result.cwd = p.cwd;
11147
11489
  if (typeof p.id === "string" && !result.sessionId)
11148
11490
  result.sessionId = p.id;
11491
+ if (typeof p.originator === "string" && !result.surface)
11492
+ result.surface = p.originator;
11149
11493
  }
11150
11494
  if (!result.title && o.type === "response_item" && p.type === "message" && p.role === "user" && Array.isArray(p.content)) {
11151
11495
  for (const item of p.content) {
@@ -11245,23 +11589,23 @@ function skillNameFromPath(path2) {
11245
11589
  }
11246
11590
 
11247
11591
  // src/utils/trash.ts
11248
- import { cpSync, existsSync as existsSync27, mkdirSync as mkdirSync13, readdirSync as readdirSync5, renameSync as renameSync3, rmSync as rmSync4, statSync as statSync3 } from "fs";
11249
- import { basename as basename2, dirname as dirname6, join as join23 } from "path";
11250
- import { homedir as homedir7 } from "os";
11592
+ import { cpSync, existsSync as existsSync28, mkdirSync as mkdirSync13, readdirSync as readdirSync5, renameSync as renameSync3, rmSync as rmSync4, statSync as statSync3 } from "fs";
11593
+ import { basename as basename2, dirname as dirname6, join as join24 } from "path";
11594
+ import { homedir as homedir8 } from "os";
11251
11595
  function trashRoot() {
11252
- return join23(homedir7(), ".runwork", "trash");
11596
+ return join24(homedir8(), ".runwork", "trash");
11253
11597
  }
11254
11598
  function batchDir(now) {
11255
11599
  const stamp = now.toISOString().replace(/[:.]/g, "-");
11256
- return join23(trashRoot(), `${stamp}-${process.pid}`);
11600
+ return join24(trashRoot(), `${stamp}-${process.pid}`);
11257
11601
  }
11258
11602
  function pruneTrash(now = new Date) {
11259
11603
  const root = trashRoot();
11260
- if (!existsSync27(root))
11604
+ if (!existsSync28(root))
11261
11605
  return;
11262
11606
  const cutoff = now.getTime() - TRASH_RETENTION_DAYS * 24 * 60 * 60 * 1000;
11263
11607
  for (const entry of readdirSync5(root)) {
11264
- const dir = join23(root, entry);
11608
+ const dir = join24(root, entry);
11265
11609
  try {
11266
11610
  if (statSync3(dir).mtimeMs < cutoff)
11267
11611
  rmSync4(dir, { recursive: true, force: true });
@@ -11269,7 +11613,7 @@ function pruneTrash(now = new Date) {
11269
11613
  }
11270
11614
  }
11271
11615
  function moveToTrash(sourcePath, reason, now = new Date) {
11272
- if (!existsSync27(sourcePath))
11616
+ if (!existsSync28(sourcePath))
11273
11617
  return null;
11274
11618
  if (!activeBatch || !activeBatch.startsWith(trashRoot())) {
11275
11619
  activeBatch = batchDir(now);
@@ -11277,8 +11621,8 @@ function moveToTrash(sourcePath, reason, now = new Date) {
11277
11621
  }
11278
11622
  const parent = basename2(dirname6(sourcePath));
11279
11623
  const grandparent = basename2(dirname6(dirname6(sourcePath)));
11280
- const destDir = join23(activeBatch, `${grandparent}__${parent}`.replace(/[^a-zA-Z0-9._-]/g, "-"));
11281
- const dest = join23(destDir, basename2(sourcePath));
11624
+ const destDir = join24(activeBatch, `${grandparent}__${parent}`.replace(/[^a-zA-Z0-9._-]/g, "-"));
11625
+ const dest = join24(destDir, basename2(sourcePath));
11282
11626
  try {
11283
11627
  mkdirSync13(destDir, { recursive: true });
11284
11628
  try {
@@ -11290,7 +11634,7 @@ function moveToTrash(sourcePath, reason, now = new Date) {
11290
11634
  } catch {
11291
11635
  return null;
11292
11636
  }
11293
- const manifestPath = join23(activeBatch, "manifest.json");
11637
+ const manifestPath = join24(activeBatch, "manifest.json");
11294
11638
  const manifest = readJsonOrNull(manifestPath) ?? { entries: [] };
11295
11639
  manifest.entries.push({ from: sourcePath, to: dest, reason, at: now.toISOString() });
11296
11640
  try {
@@ -11333,27 +11677,27 @@ function configHash(value) {
11333
11677
  var init_hash = () => {};
11334
11678
 
11335
11679
  // src/agents/utils/json-config.ts
11336
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14, existsSync as existsSync28 } from "fs";
11680
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14, existsSync as existsSync29 } from "fs";
11337
11681
  import { dirname as dirname7 } from "path";
11338
11682
  function isRunworkManagedKey(key) {
11339
11683
  return key === RUNWORK_WORKSPACE_MCP_NAME || key.startsWith(RUNWORK_MCP_PREFIX) || key.startsWith(RUNWORK_MCP_PREFIX_LEGACY);
11340
11684
  }
11341
11685
  function readJsonConfig(filePath) {
11342
- if (!existsSync28(filePath))
11686
+ if (!existsSync29(filePath))
11343
11687
  return {};
11344
11688
  try {
11345
- return JSON.parse(readFileSync23(filePath, "utf-8"));
11689
+ return JSON.parse(readFileSync24(filePath, "utf-8"));
11346
11690
  } catch (err) {
11347
11691
  console.warn(` [config] ${filePath} is not valid JSON: ${err instanceof Error ? err.message : err}`);
11348
11692
  return {};
11349
11693
  }
11350
11694
  }
11351
11695
  function existingContentIsUnparseable(filePath) {
11352
- if (!existsSync28(filePath))
11696
+ if (!existsSync29(filePath))
11353
11697
  return { bad: false };
11354
11698
  let raw;
11355
11699
  try {
11356
- raw = readFileSync23(filePath, "utf-8");
11700
+ raw = readFileSync24(filePath, "utf-8");
11357
11701
  } catch {
11358
11702
  return { bad: false };
11359
11703
  }
@@ -11375,7 +11719,7 @@ function writeJsonConfig(filePath, config) {
11375
11719
  `);
11376
11720
  }
11377
11721
  function removeRunworkMcpServers(filePath, topKey) {
11378
- if (!existsSync28(filePath))
11722
+ if (!existsSync29(filePath))
11379
11723
  return false;
11380
11724
  const config = readJsonConfig(filePath);
11381
11725
  const existing = config[topKey] || {};
@@ -11430,25 +11774,25 @@ var init_json_config = __esm(() => {
11430
11774
  });
11431
11775
 
11432
11776
  // src/agents/utils/skill-removal.ts
11433
- import { existsSync as existsSync29, readdirSync as readdirSync6 } from "fs";
11434
- import { join as join24 } from "path";
11777
+ import { existsSync as existsSync30, readdirSync as readdirSync6 } from "fs";
11778
+ import { join as join25 } from "path";
11435
11779
  function removeMatchingSkillDirs(dir, allowed, reason = "skill removed") {
11436
- if (!allowed.size || !existsSync29(dir))
11780
+ if (!allowed.size || !existsSync30(dir))
11437
11781
  return;
11438
11782
  for (const entry of readdirSync6(dir)) {
11439
11783
  if (!allowed.has(entry))
11440
11784
  continue;
11441
- moveToTrash(join24(dir, entry), reason);
11785
+ moveToTrash(join25(dir, entry), reason);
11442
11786
  }
11443
11787
  }
11444
11788
  function removeMatchingSkillFiles(dir, allowed, suffix, reason = "skill removed") {
11445
- if (!allowed.size || !existsSync29(dir))
11789
+ if (!allowed.size || !existsSync30(dir))
11446
11790
  return;
11447
11791
  const names = new Set([...allowed].map((slug) => `${slug}${suffix}`));
11448
11792
  for (const entry of readdirSync6(dir)) {
11449
11793
  if (!names.has(entry))
11450
11794
  continue;
11451
- moveToTrash(join24(dir, entry), reason);
11795
+ moveToTrash(join25(dir, entry), reason);
11452
11796
  }
11453
11797
  }
11454
11798
  var init_skill_removal = __esm(() => {
@@ -11456,7 +11800,7 @@ var init_skill_removal = __esm(() => {
11456
11800
  });
11457
11801
 
11458
11802
  // src/agents/utils/instruction-hint.ts
11459
- import { existsSync as existsSync30, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "fs";
11803
+ import { existsSync as existsSync31, readFileSync as readFileSync25, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "fs";
11460
11804
  import { dirname as dirname8 } from "path";
11461
11805
  function writeHintToFile(filePath, hint) {
11462
11806
  mkdirSync15(dirname8(filePath), { recursive: true });
@@ -11466,8 +11810,8 @@ ${hint}
11466
11810
  ${END_MARKER}`;
11467
11811
  }
11468
11812
  let content = "";
11469
- if (existsSync30(filePath)) {
11470
- content = readFileSync24(filePath, "utf-8");
11813
+ if (existsSync31(filePath)) {
11814
+ content = readFileSync25(filePath, "utf-8");
11471
11815
  }
11472
11816
  const startIdx = content.indexOf(START_MARKER);
11473
11817
  const endIdx = content.indexOf(END_MARKER);
@@ -11489,9 +11833,9 @@ ${END_MARKER}`;
11489
11833
  writeFileSync15(filePath, content);
11490
11834
  }
11491
11835
  function removeHintFromFile(filePath) {
11492
- if (!existsSync30(filePath))
11836
+ if (!existsSync31(filePath))
11493
11837
  return false;
11494
- let content = readFileSync24(filePath, "utf-8");
11838
+ let content = readFileSync25(filePath, "utf-8");
11495
11839
  const startIdx = content.indexOf(START_MARKER);
11496
11840
  const endIdx = content.indexOf(END_MARKER);
11497
11841
  if (startIdx < 0 || endIdx < 0)
@@ -11509,9 +11853,9 @@ function removeHintFromFile(filePath) {
11509
11853
  return true;
11510
11854
  }
11511
11855
  function removeTeamInstructionsFromFile(filePath) {
11512
- if (!existsSync30(filePath))
11856
+ if (!existsSync31(filePath))
11513
11857
  return false;
11514
- let content = readFileSync24(filePath, "utf-8");
11858
+ let content = readFileSync25(filePath, "utf-8");
11515
11859
  const startIdx = content.indexOf(TEAM_START_MARKER);
11516
11860
  const endIdx = content.indexOf(TEAM_END_MARKER);
11517
11861
  if (startIdx < 0 || endIdx < 0)
@@ -11531,8 +11875,8 @@ function removeTeamInstructionsFromFile(filePath) {
11531
11875
  function writeTeamInstructionsToFile(filePath, instructions) {
11532
11876
  mkdirSync15(dirname8(filePath), { recursive: true });
11533
11877
  let content = "";
11534
- if (existsSync30(filePath)) {
11535
- content = readFileSync24(filePath, "utf-8");
11878
+ if (existsSync31(filePath)) {
11879
+ content = readFileSync25(filePath, "utf-8");
11536
11880
  }
11537
11881
  const block = `${TEAM_START_MARKER}
11538
11882
  ${instructions}
@@ -11981,120 +12325,6 @@ function vlog(...args) {
11981
12325
  }
11982
12326
  var verbose = false;
11983
12327
 
11984
- // src/agents/detection.ts
11985
- import { execFile } from "child_process";
11986
- import { existsSync as existsSync31 } from "fs";
11987
- import { homedir as homedir8, platform as platform3 } from "os";
11988
- import { join as join25 } from "path";
11989
- import { promisify } from "util";
11990
- function isWindows() {
11991
- return platform3() === "win32";
11992
- }
11993
- function toList(value) {
11994
- return Array.isArray(value) ? value : [value];
11995
- }
11996
- async function runPowerShell(script) {
11997
- const execFileAsync = promisify(execFile);
11998
- try {
11999
- await execFileAsync("powershell", ["-NoProfile", "-Command", script]);
12000
- return true;
12001
- } catch {
12002
- return false;
12003
- }
12004
- }
12005
- function resolveDetectionPath(target) {
12006
- const resolved = resolvePlatformString(target);
12007
- if (!resolved)
12008
- return null;
12009
- const expanded = expandWindowsPathTemplate(resolved, {
12010
- "%APPDATA%": process.env.APPDATA,
12011
- "%LOCALAPPDATA%": process.env.LOCALAPPDATA,
12012
- "%ProgramFiles%": process.env.ProgramFiles
12013
- });
12014
- return expanded.needsHomeJoin ? join25(homedir8(), expanded.path) : expanded.path;
12015
- }
12016
- function checkPath(target) {
12017
- const absolute = resolveDetectionPath(target);
12018
- if (!absolute)
12019
- return null;
12020
- return existsSync31(absolute) ? absolute : null;
12021
- }
12022
- async function checkMacosBundleId(target) {
12023
- if (platform3() !== "darwin")
12024
- return false;
12025
- const execFileAsync = promisify(execFile);
12026
- for (const id of toList(target)) {
12027
- if (!isValidBundleId(id))
12028
- continue;
12029
- try {
12030
- await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
12031
- return true;
12032
- } catch {}
12033
- }
12034
- return false;
12035
- }
12036
- async function checkWindowsAppxPackage(target) {
12037
- if (!isWindows())
12038
- return false;
12039
- const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
12040
- const results = await Promise.all(probes);
12041
- return results.some(Boolean);
12042
- }
12043
- async function checkWindowsStartApp(target) {
12044
- if (!isWindows())
12045
- return false;
12046
- const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
12047
- const results = await Promise.all(probes);
12048
- return results.some(Boolean);
12049
- }
12050
- async function runAgentDetectionDetailed(detection) {
12051
- switch (detection.method) {
12052
- case "binary": {
12053
- const target = resolvePlatformString(detection.target);
12054
- const resolved = target ? whichBinary(target) : null;
12055
- return resolved ? { detected: true, via: "binary", resolvedPath: resolved } : NOT_DETECTED;
12056
- }
12057
- case "path": {
12058
- const resolved = checkPath(detection.target);
12059
- return resolved ? { detected: true, via: "path", resolvedPath: resolved } : NOT_DETECTED;
12060
- }
12061
- case "windows-appx":
12062
- return await checkWindowsAppxPackage(detection.target) ? { detected: true, via: "windows-appx" } : NOT_DETECTED;
12063
- case "windows-start-app":
12064
- return await checkWindowsStartApp(detection.target) ? { detected: true, via: "windows-start-app" } : NOT_DETECTED;
12065
- case "macos-bundle-id":
12066
- return await checkMacosBundleId(detection.target) ? { detected: true, via: "macos-bundle-id" } : NOT_DETECTED;
12067
- case "any": {
12068
- const probes = await Promise.all(detection.target.map((p) => runAgentDetectionDetailed(p)));
12069
- return probes.find((p) => p.detected) ?? NOT_DETECTED;
12070
- }
12071
- case "always":
12072
- return { detected: true, via: "always" };
12073
- default:
12074
- return NOT_DETECTED;
12075
- }
12076
- }
12077
- async function runAgentDetection(detection) {
12078
- return (await runAgentDetectionDetailed(detection)).detected;
12079
- }
12080
-
12081
- class RegistryDetectedAdapter {
12082
- async detect() {
12083
- const def = getRegistryAgent(this.slug);
12084
- if (!def)
12085
- return false;
12086
- return runAgentDetection(def.detection);
12087
- }
12088
- }
12089
- var NOT_DETECTED;
12090
- var init_detection = __esm(() => {
12091
- init_which();
12092
- init_registry_data();
12093
- init_registry();
12094
- init_detection_probes();
12095
- NOT_DETECTED = { detected: false };
12096
- });
12097
-
12098
12328
  // src/agents/transcript-sources.ts
12099
12329
  import { accessSync, constants, statSync as statSync4 } from "fs";
12100
12330
  function classifyFsErrorCode(code) {
@@ -12158,7 +12388,7 @@ function summarizeTranscriptSources(sources) {
12158
12388
  var init_transcript_sources = () => {};
12159
12389
 
12160
12390
  // src/agents/claude-code.ts
12161
- import { chmodSync, existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as readFileSync25, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync16 } from "fs";
12391
+ import { chmodSync, existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as readFileSync26, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync16 } from "fs";
12162
12392
  import { join as join26 } from "path";
12163
12393
  import { homedir as homedir9 } from "os";
12164
12394
  function getPluginJson() {
@@ -12349,7 +12579,7 @@ ${instructions}`;
12349
12579
  let settings = {};
12350
12580
  if (hadFile) {
12351
12581
  try {
12352
- settings = JSON.parse(readFileSync25(settingsPath, "utf-8"));
12582
+ settings = JSON.parse(readFileSync26(settingsPath, "utf-8"));
12353
12583
  } catch {}
12354
12584
  }
12355
12585
  if (settings.permissions && typeof settings.permissions === "object") {
@@ -12410,7 +12640,7 @@ ${instructions}`;
12410
12640
  const settingsPath = join26(homedir9(), ".claude", "settings.json");
12411
12641
  if (existsSync32(settingsPath)) {
12412
12642
  try {
12413
- const settings = JSON.parse(readFileSync25(settingsPath, "utf-8"));
12643
+ const settings = JSON.parse(readFileSync26(settingsPath, "utf-8"));
12414
12644
  if (settings.permissions) {
12415
12645
  for (const key of ["allow", "deny"]) {
12416
12646
  const arr = settings.permissions[key];
@@ -12508,7 +12738,7 @@ ${instructions}`;
12508
12738
  continue;
12509
12739
  let content;
12510
12740
  try {
12511
- content = readFileSync25(filePath, "utf-8");
12741
+ content = readFileSync26(filePath, "utf-8");
12512
12742
  } catch {
12513
12743
  continue;
12514
12744
  }
@@ -12633,7 +12863,7 @@ ${instructions}`;
12633
12863
  continue;
12634
12864
  let content;
12635
12865
  try {
12636
- content = readFileSync25(filePath, "utf-8");
12866
+ content = readFileSync26(filePath, "utf-8");
12637
12867
  } catch {
12638
12868
  continue;
12639
12869
  }
@@ -12689,7 +12919,7 @@ ${instructions}`;
12689
12919
  const sessionId = file.slice(0, -".jsonl".length);
12690
12920
  let endedAt = null;
12691
12921
  try {
12692
- const stamp = JSON.parse(readFileSync25(join26(homedir9(), ".runwork", "sessions", `${sessionId}.ended.json`), "utf-8"));
12922
+ const stamp = JSON.parse(readFileSync26(join26(homedir9(), ".runwork", "sessions", `${sessionId}.ended.json`), "utf-8"));
12693
12923
  if (stamp && typeof stamp.endedAt === "string")
12694
12924
  endedAt = stamp.endedAt;
12695
12925
  } catch {}
@@ -12701,7 +12931,8 @@ ${instructions}`;
12701
12931
  startedAt: scanned.firstTimestamp,
12702
12932
  lastActivityAt: resolveLastActivity(filePath, stat.mtimeMs),
12703
12933
  endedAt,
12704
- transcriptPath: filePath
12934
+ transcriptPath: filePath,
12935
+ surface: scanned.surface ?? null
12705
12936
  });
12706
12937
  }
12707
12938
  }
@@ -12755,7 +12986,7 @@ ${instructions}`;
12755
12986
  continue;
12756
12987
  let content;
12757
12988
  try {
12758
- content = readFileSync25(filePath, "utf-8");
12989
+ content = readFileSync26(filePath, "utf-8");
12759
12990
  } catch {
12760
12991
  continue;
12761
12992
  }
@@ -13003,7 +13234,7 @@ var init_claude_desktop_plugin_tree = __esm(() => {
13003
13234
  });
13004
13235
 
13005
13236
  // src/agents/claude-desktop.ts
13006
- import { existsSync as existsSync34, mkdtempSync as mkdtempSync3, readdirSync as readdirSync8, readFileSync as readFileSync26, rmSync as rmSync7, statSync as statSync6, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18 } from "fs";
13237
+ import { existsSync as existsSync34, mkdtempSync as mkdtempSync3, readdirSync as readdirSync8, readFileSync as readFileSync27, rmSync as rmSync7, statSync as statSync6, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18 } from "fs";
13007
13238
  import { dirname as dirname9, join as join28 } from "path";
13008
13239
  import { homedir as homedir10, platform as platform4, tmpdir as tmpdir3 } from "os";
13009
13240
  function isRunworkRpmPluginName(name) {
@@ -13122,7 +13353,7 @@ function findRpmPluginByName(pluginName) {
13122
13353
  if (!existsSync34(manifestPath))
13123
13354
  return null;
13124
13355
  try {
13125
- const manifest = JSON.parse(readFileSync26(manifestPath, "utf-8"));
13356
+ const manifest = JSON.parse(readFileSync27(manifestPath, "utf-8"));
13126
13357
  const entry = manifest.plugins?.find((p) => p.name === pluginName);
13127
13358
  if (!entry?.id)
13128
13359
  return null;
@@ -13303,7 +13534,7 @@ var init_claude_desktop = __esm(() => {
13303
13534
  let desktopConfig = {};
13304
13535
  if (existsSync34(configPath)) {
13305
13536
  try {
13306
- desktopConfig = JSON.parse(readFileSync26(configPath, "utf-8"));
13537
+ desktopConfig = JSON.parse(readFileSync27(configPath, "utf-8"));
13307
13538
  } catch {}
13308
13539
  }
13309
13540
  if (!desktopConfig.preferences)
@@ -13342,7 +13573,7 @@ var init_claude_desktop = __esm(() => {
13342
13573
  if (!existsSync34(manifestPath))
13343
13574
  continue;
13344
13575
  try {
13345
- const manifest = JSON.parse(readFileSync26(manifestPath, "utf-8"));
13576
+ const manifest = JSON.parse(readFileSync27(manifestPath, "utf-8"));
13346
13577
  if (!Array.isArray(manifest.plugins))
13347
13578
  continue;
13348
13579
  const ours = manifest.plugins.filter((p) => isRunworkRpmPluginName(p.name));
@@ -13444,7 +13675,7 @@ var init_claude_desktop = __esm(() => {
13444
13675
  continue;
13445
13676
  let content;
13446
13677
  try {
13447
- content = readFileSync26(filePath, "utf-8");
13678
+ content = readFileSync27(filePath, "utf-8");
13448
13679
  } catch {
13449
13680
  continue;
13450
13681
  }
@@ -13484,7 +13715,7 @@ var init_claude_desktop = __esm(() => {
13484
13715
  const metaPath = join28(orgPath, entry);
13485
13716
  let meta;
13486
13717
  try {
13487
- meta = JSON.parse(readFileSync26(metaPath, "utf-8"));
13718
+ meta = JSON.parse(readFileSync27(metaPath, "utf-8"));
13488
13719
  } catch {
13489
13720
  continue;
13490
13721
  }
@@ -13520,7 +13751,8 @@ var init_claude_desktop = __esm(() => {
13520
13751
  title: typeof meta.title === "string" && meta.title ? meta.title : null,
13521
13752
  startedAt: typeof meta.createdAt === "number" ? new Date(meta.createdAt).toISOString() : null,
13522
13753
  lastActivityAt: new Date(lastActivityMs).toISOString(),
13523
- transcriptPath
13754
+ transcriptPath,
13755
+ surface: "local-agent"
13524
13756
  });
13525
13757
  }
13526
13758
  }
@@ -13586,7 +13818,7 @@ var init_claude_desktop = __esm(() => {
13586
13818
  const scheduledTasksPath = join28(claudeAppDir, "scheduled-tasks.json");
13587
13819
  if (existsSync34(scheduledTasksPath)) {
13588
13820
  try {
13589
- const raw = readFileSync26(scheduledTasksPath, "utf-8");
13821
+ const raw = readFileSync27(scheduledTasksPath, "utf-8");
13590
13822
  const parsed = JSON.parse(raw);
13591
13823
  const tasks = Array.isArray(parsed) ? parsed : Object.values(parsed);
13592
13824
  for (const task of tasks) {
@@ -13630,7 +13862,7 @@ var init_claude_desktop = __esm(() => {
13630
13862
  }
13631
13863
  const versionPath = join28(claudeAppDir, "claude-code", "sdk-version");
13632
13864
  if (existsSync34(versionPath)) {
13633
- return readFileSync26(versionPath, "utf-8").trim();
13865
+ return readFileSync27(versionPath, "utf-8").trim();
13634
13866
  }
13635
13867
  return null;
13636
13868
  } catch {
@@ -13663,7 +13895,7 @@ var init_claude_desktop = __esm(() => {
13663
13895
  if (!file.endsWith(".json"))
13664
13896
  continue;
13665
13897
  try {
13666
- const session = JSON.parse(readFileSync26(join28(userPath, file), "utf-8"));
13898
+ const session = JSON.parse(readFileSync27(join28(userPath, file), "utf-8"));
13667
13899
  onSession(session);
13668
13900
  } catch {
13669
13901
  continue;
@@ -14207,7 +14439,7 @@ ${hint}`;
14207
14439
  });
14208
14440
 
14209
14441
  // src/agents/codex.ts
14210
- import { existsSync as existsSync37, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as readFileSync27, statSync as statSync7, writeFileSync as writeFileSync21 } from "fs";
14442
+ import { existsSync as existsSync37, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as readFileSync28, statSync as statSync7, writeFileSync as writeFileSync21 } from "fs";
14211
14443
  import { basename as basename3, join as join31 } from "path";
14212
14444
  import { homedir as homedir13 } from "os";
14213
14445
  import { parse, stringify } from "smol-toml";
@@ -14240,7 +14472,7 @@ var init_codex = __esm(async () => {
14240
14472
  const configPath = join31(homedir13(), ".codex", "config.toml");
14241
14473
  let parsed = {};
14242
14474
  if (existsSync37(configPath)) {
14243
- parsed = parse(readFileSync27(configPath, "utf-8"));
14475
+ parsed = parse(readFileSync28(configPath, "utf-8"));
14244
14476
  }
14245
14477
  if (!parsed.mcp_servers || typeof parsed.mcp_servers !== "object") {
14246
14478
  parsed.mcp_servers = {};
@@ -14295,7 +14527,7 @@ var init_codex = __esm(async () => {
14295
14527
  const configPath = scope === "project" ? join31(process.cwd(), ".codex", "config.toml") : join31(homedir13(), ".codex", "config.toml");
14296
14528
  let parsed = {};
14297
14529
  if (existsSync37(configPath)) {
14298
- parsed = parse(readFileSync27(configPath, "utf-8"));
14530
+ parsed = parse(readFileSync28(configPath, "utf-8"));
14299
14531
  }
14300
14532
  if (config.modelPreference) {
14301
14533
  parsed.model = config.modelPreference;
@@ -14354,7 +14586,7 @@ var init_codex = __esm(async () => {
14354
14586
  const configPath = join31(homedir13(), ".codex", "config.toml");
14355
14587
  if (existsSync37(configPath)) {
14356
14588
  try {
14357
- const parsed = parse(readFileSync27(configPath, "utf-8"));
14589
+ const parsed = parse(readFileSync28(configPath, "utf-8"));
14358
14590
  if (parsed.mcp_servers && typeof parsed.mcp_servers === "object") {
14359
14591
  const mcpServers = parsed.mcp_servers;
14360
14592
  for (const key of Object.keys(mcpServers)) {
@@ -14403,7 +14635,7 @@ var init_codex = __esm(async () => {
14403
14635
  if (messageCount === 0) {
14404
14636
  const historyPath = join31(codexDir, "history.jsonl");
14405
14637
  if (existsSync37(historyPath)) {
14406
- const content = readFileSync27(historyPath, "utf-8").trim();
14638
+ const content = readFileSync28(historyPath, "utf-8").trim();
14407
14639
  if (content) {
14408
14640
  for (const line of content.split(/[\r\n]+/)) {
14409
14641
  try {
@@ -14483,7 +14715,7 @@ var init_codex = __esm(async () => {
14483
14715
  continue;
14484
14716
  let content;
14485
14717
  try {
14486
- content = readFileSync27(file, "utf-8");
14718
+ content = readFileSync28(file, "utf-8");
14487
14719
  } catch {
14488
14720
  continue;
14489
14721
  }
@@ -14575,7 +14807,7 @@ var init_codex = __esm(async () => {
14575
14807
  continue;
14576
14808
  let content;
14577
14809
  try {
14578
- content = readFileSync27(file, "utf-8");
14810
+ content = readFileSync28(file, "utf-8");
14579
14811
  } catch {
14580
14812
  continue;
14581
14813
  }
@@ -14634,7 +14866,8 @@ var init_codex = __esm(async () => {
14634
14866
  title: scanned.title,
14635
14867
  startedAt: scanned.firstTimestamp,
14636
14868
  lastActivityAt: resolveLastActivity(file, stat.mtimeMs),
14637
- transcriptPath: file
14869
+ transcriptPath: file,
14870
+ surface: scanned.surface ?? null
14638
14871
  });
14639
14872
  }
14640
14873
  return sessions;
@@ -14646,7 +14879,7 @@ var init_codex = __esm(async () => {
14646
14879
  try {
14647
14880
  const versionPath = join31(homedir13(), ".codex", "version.json");
14648
14881
  if (existsSync37(versionPath)) {
14649
- const data = JSON.parse(readFileSync27(versionPath, "utf-8"));
14882
+ const data = JSON.parse(readFileSync28(versionPath, "utf-8"));
14650
14883
  return data.latest_version ?? null;
14651
14884
  }
14652
14885
  } catch {}
@@ -14707,7 +14940,7 @@ var init_codex = __esm(async () => {
14707
14940
  parseRolloutForSkills(filePath, sinceMs, skillCounts) {
14708
14941
  let content;
14709
14942
  try {
14710
- content = readFileSync27(filePath, "utf-8");
14943
+ content = readFileSync28(filePath, "utf-8");
14711
14944
  } catch {
14712
14945
  return;
14713
14946
  }
@@ -14760,7 +14993,7 @@ var init_codex = __esm(async () => {
14760
14993
  let state = {};
14761
14994
  if (existsSync37(statePath)) {
14762
14995
  try {
14763
- state = JSON.parse(readFileSync27(statePath, "utf-8"));
14996
+ state = JSON.parse(readFileSync28(statePath, "utf-8"));
14764
14997
  } catch {
14765
14998
  return "app_running";
14766
14999
  }
@@ -14795,23 +15028,11 @@ var init_codex = __esm(async () => {
14795
15028
  CodexDesktopAdapter = class CodexDesktopAdapter extends CodexAdapter {
14796
15029
  name = "Codex";
14797
15030
  slug = "codex-app";
14798
- async readUsageStats() {
14799
- return null;
14800
- }
14801
- async listSessions() {
14802
- return null;
14803
- }
14804
- async readSessionDigests() {
14805
- return null;
14806
- }
14807
- transcriptSources() {
14808
- return [];
14809
- }
14810
15031
  };
14811
15032
  });
14812
15033
 
14813
15034
  // src/agents/cline.ts
14814
- import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as readFileSync28, readdirSync as readdirSync12, rmSync as rmSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
15035
+ import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as readFileSync29, readdirSync as readdirSync12, rmSync as rmSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
14815
15036
  import { join as join32 } from "path";
14816
15037
  import { homedir as homedir14 } from "os";
14817
15038
  var ClineAdapter;
@@ -14872,7 +15093,7 @@ var init_cline = __esm(() => {
14872
15093
  let state = {};
14873
15094
  if (existsSync38(globalStatePath)) {
14874
15095
  try {
14875
- state = JSON.parse(readFileSync28(globalStatePath, "utf-8"));
15096
+ state = JSON.parse(readFileSync29(globalStatePath, "utf-8"));
14876
15097
  } catch {}
14877
15098
  }
14878
15099
  if (config.modelPreference) {
@@ -14929,7 +15150,7 @@ var init_cline = __esm(() => {
14929
15150
  });
14930
15151
 
14931
15152
  // src/agents/gemini.ts
14932
- import { existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync13, readFileSync as readFileSync29, statSync as statSync8, writeFileSync as writeFileSync23 } from "fs";
15153
+ import { existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync13, readFileSync as readFileSync30, statSync as statSync8, writeFileSync as writeFileSync23 } from "fs";
14933
15154
  import { basename as basename4, join as join33 } from "path";
14934
15155
  import { homedir as homedir15 } from "os";
14935
15156
  var GeminiAdapter;
@@ -14989,7 +15210,7 @@ var init_gemini = __esm(() => {
14989
15210
  let settings = {};
14990
15211
  if (existsSync39(settingsPath)) {
14991
15212
  try {
14992
- settings = JSON.parse(readFileSync29(settingsPath, "utf-8"));
15213
+ settings = JSON.parse(readFileSync30(settingsPath, "utf-8"));
14993
15214
  } catch {}
14994
15215
  }
14995
15216
  if (config.modelPreference) {
@@ -15050,7 +15271,7 @@ var init_gemini = __esm(() => {
15050
15271
  continue;
15051
15272
  let session;
15052
15273
  try {
15053
- session = JSON.parse(readFileSync29(filePath, "utf-8"));
15274
+ session = JSON.parse(readFileSync30(filePath, "utf-8"));
15054
15275
  } catch {
15055
15276
  continue;
15056
15277
  }
@@ -15141,7 +15362,7 @@ var init_gemini = __esm(() => {
15141
15362
  for (const { filePath, project, mtimeMs } of this.chatFiles(sinceMs)) {
15142
15363
  let session;
15143
15364
  try {
15144
- session = JSON.parse(readFileSync29(filePath, "utf-8"));
15365
+ session = JSON.parse(readFileSync30(filePath, "utf-8"));
15145
15366
  } catch {
15146
15367
  continue;
15147
15368
  }
@@ -15182,7 +15403,7 @@ var init_gemini = __esm(() => {
15182
15403
  for (const { filePath, project } of this.chatFiles(sinceMs)) {
15183
15404
  let content;
15184
15405
  try {
15185
- content = readFileSync29(filePath, "utf-8");
15406
+ content = readFileSync30(filePath, "utf-8");
15186
15407
  } catch {
15187
15408
  continue;
15188
15409
  }
@@ -15425,6 +15646,23 @@ function describeScanOutcome(outcome) {
15425
15646
  function scanOutcomeNeedsAttention(outcome) {
15426
15647
  return outcome.status === "permission-denied" || outcome.status === "error";
15427
15648
  }
15649
+ function describeStoreOutcome(outcome) {
15650
+ if (outcome.status === "orphaned") {
15651
+ return `not read: nothing on this machine was detected as ${outcome.members.join(" or ")}`;
15652
+ }
15653
+ if (outcome.status === "ok")
15654
+ return null;
15655
+ return describeScanOutcome({
15656
+ agentSlug: outcome.storeId,
15657
+ status: outcome.status,
15658
+ sessions: outcome.sessions,
15659
+ path: outcome.path,
15660
+ ...outcome.detail ? { detail: outcome.detail } : {}
15661
+ });
15662
+ }
15663
+ function storeOutcomeNeedsAttention(outcome) {
15664
+ return outcome.status === "orphaned" || outcome.status === "permission-denied" || outcome.status === "error";
15665
+ }
15428
15666
 
15429
15667
  // src/utils/insight-id.ts
15430
15668
  import { createHash as createHash3 } from "node:crypto";
@@ -15437,7 +15675,7 @@ function insightLocalKey(teaches, slug) {
15437
15675
  var init_insight_id = () => {};
15438
15676
 
15439
15677
  // src/reflect/insight-store.ts
15440
- import { existsSync as existsSync41, readFileSync as readFileSync30 } from "fs";
15678
+ import { existsSync as existsSync41, readFileSync as readFileSync31 } from "fs";
15441
15679
  import { join as join35 } from "path";
15442
15680
  import { homedir as homedir17 } from "os";
15443
15681
  function storePath2() {
@@ -15448,7 +15686,7 @@ function readAll() {
15448
15686
  if (!existsSync41(path2))
15449
15687
  return {};
15450
15688
  try {
15451
- const parsed = JSON.parse(readFileSync30(path2, "utf-8"));
15689
+ const parsed = JSON.parse(readFileSync31(path2, "utf-8"));
15452
15690
  return parsed && typeof parsed === "object" ? parsed : {};
15453
15691
  } catch {
15454
15692
  return {};
@@ -15493,7 +15731,7 @@ var init_insight_store = __esm(() => {
15493
15731
  var DEFAULT_DAILY_TIER2_BUDGET = 3;
15494
15732
 
15495
15733
  // src/reflect/cadence.ts
15496
- import { existsSync as existsSync42, readFileSync as readFileSync31 } from "fs";
15734
+ import { existsSync as existsSync42, readFileSync as readFileSync32 } from "fs";
15497
15735
  import { join as join36 } from "path";
15498
15736
  import { homedir as homedir18 } from "os";
15499
15737
  function remainingDailyAnalyses(state, now = new Date, budget = DEFAULT_DAILY_TIER2_BUDGET) {
@@ -15515,7 +15753,7 @@ function loadCadenceState() {
15515
15753
  const p = statePath();
15516
15754
  if (!existsSync42(p))
15517
15755
  return { ...DEFAULT_STATE };
15518
- const parsed = JSON.parse(readFileSync31(p, "utf-8"));
15756
+ const parsed = JSON.parse(readFileSync32(p, "utf-8"));
15519
15757
  const state = { ...DEFAULT_STATE, ...parsed && typeof parsed === "object" ? parsed : {} };
15520
15758
  if (state.enabled === false && state.disabledByUser !== true) {
15521
15759
  state.enabled = true;
@@ -15576,7 +15814,7 @@ __export(exports_run_log, {
15576
15814
  RUN_LOG_CAP: () => RUN_LOG_CAP,
15577
15815
  ANALYST_ERROR_MAX_CHARS: () => ANALYST_ERROR_MAX_CHARS
15578
15816
  });
15579
- import { existsSync as existsSync43, mkdirSync as mkdirSync25, readFileSync as readFileSync32, readdirSync as readdirSync15, statSync as statSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync25 } from "fs";
15817
+ import { existsSync as existsSync43, mkdirSync as mkdirSync25, readFileSync as readFileSync33, readdirSync as readdirSync15, statSync as statSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync25 } from "fs";
15580
15818
  import { dirname as dirname10, join as join37 } from "path";
15581
15819
  import { homedir as homedir19 } from "os";
15582
15820
  function runLogPath() {
@@ -15587,7 +15825,7 @@ function loadRunLog() {
15587
15825
  const p = runLogPath();
15588
15826
  if (!existsSync43(p))
15589
15827
  return [];
15590
- const parsed = JSON.parse(readFileSync32(p, "utf-8"));
15828
+ const parsed = JSON.parse(readFileSync33(p, "utf-8"));
15591
15829
  return Array.isArray(parsed) ? parsed : [];
15592
15830
  } catch {
15593
15831
  return [];
@@ -15755,7 +15993,7 @@ var init_run_log = __esm(() => {
15755
15993
  });
15756
15994
 
15757
15995
  // src/reflect/conversation-queue.ts
15758
- import { existsSync as existsSync44, readFileSync as readFileSync33 } from "fs";
15996
+ import { existsSync as existsSync44, readFileSync as readFileSync34 } from "fs";
15759
15997
  import { join as join38 } from "path";
15760
15998
  import { homedir as homedir20 } from "os";
15761
15999
  function conversationKey(c) {
@@ -15769,7 +16007,7 @@ function loadQueueState() {
15769
16007
  const p = queuePath();
15770
16008
  if (!existsSync44(p))
15771
16009
  return { entries: {} };
15772
- const parsed = JSON.parse(readFileSync33(p, "utf-8"));
16010
+ const parsed = JSON.parse(readFileSync34(p, "utf-8"));
15773
16011
  if (parsed && typeof parsed === "object" && parsed.entries && typeof parsed.entries === "object") {
15774
16012
  return { entries: parsed.entries };
15775
16013
  }
@@ -15977,7 +16215,7 @@ function parseHandoffResult(kind, text2) {
15977
16215
  }
15978
16216
 
15979
16217
  // src/reflect/model-repair.ts
15980
- import { existsSync as existsSync45, readFileSync as readFileSync34, writeFileSync as writeFileSync26 } from "fs";
16218
+ import { existsSync as existsSync45, readFileSync as readFileSync35, writeFileSync as writeFileSync26 } from "fs";
15981
16219
  import { homedir as homedir21 } from "os";
15982
16220
  import { join as join39 } from "path";
15983
16221
  function codexConfigPath() {
@@ -16014,7 +16252,7 @@ function repairCodexModelPin() {
16014
16252
  const path2 = codexConfigPath();
16015
16253
  if (!existsSync45(path2))
16016
16254
  return null;
16017
- const current = readFileSync34(path2, "utf-8");
16255
+ const current = readFileSync35(path2, "utf-8");
16018
16256
  const stripped = stripModelPin(current);
16019
16257
  if (!stripped)
16020
16258
  return null;
@@ -16837,7 +17075,214 @@ ${all.length} insight(s) from your recent work:
16837
17075
  });
16838
17076
  });
16839
17077
 
17078
+ // src/agents/transcript-stores.ts
17079
+ function joiner(input) {
17080
+ const sep4 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
17081
+ return (...parts) => parts.join(sep4);
17082
+ }
17083
+ function home(input) {
17084
+ return input.homeDir.replace(/[/\\]+$/, "");
17085
+ }
17086
+ function appDataRoot(input) {
17087
+ const join41 = joiner(input);
17088
+ if (input.platform === "darwin")
17089
+ return join41(home(input), "Library", "Application Support");
17090
+ if (input.platform === "win32") {
17091
+ return input.appData ?? join41(home(input), "AppData", "Roaming");
17092
+ }
17093
+ return join41(home(input), ".config");
17094
+ }
17095
+ function localAppDataRoot(input) {
17096
+ const join41 = joiner(input);
17097
+ return input.localAppData ?? join41(home(input), "AppData", "Local");
17098
+ }
17099
+ function codexOriginator(head) {
17100
+ for (const line of head.split(`
17101
+ `)) {
17102
+ if (!line.trim())
17103
+ continue;
17104
+ let o;
17105
+ try {
17106
+ o = JSON.parse(line);
17107
+ } catch {
17108
+ continue;
17109
+ }
17110
+ if (o.type !== "session_meta")
17111
+ continue;
17112
+ const payload = o.payload;
17113
+ return typeof payload?.originator === "string" ? payload.originator : null;
17114
+ }
17115
+ return null;
17116
+ }
17117
+ function claudeEntrypoint(head) {
17118
+ for (const line of head.split(`
17119
+ `)) {
17120
+ if (!line.trim())
17121
+ continue;
17122
+ let o;
17123
+ try {
17124
+ o = JSON.parse(line);
17125
+ } catch {
17126
+ continue;
17127
+ }
17128
+ if (typeof o.entrypoint === "string")
17129
+ return o.entrypoint;
17130
+ }
17131
+ return null;
17132
+ }
17133
+ function attributeCodexOriginator(marker) {
17134
+ switch (marker) {
17135
+ case "Codex Desktop":
17136
+ case "codex_work_desktop":
17137
+ return "codex-app";
17138
+ case "codex-tui":
17139
+ case "codex_exec":
17140
+ case "Claude Code":
17141
+ return "codex";
17142
+ default:
17143
+ return null;
17144
+ }
17145
+ }
17146
+ function attributeClaudeEntrypoint(marker) {
17147
+ switch (marker) {
17148
+ case "cli":
17149
+ case "sdk-cli":
17150
+ return "claude-code";
17151
+ case "claude-desktop":
17152
+ case "local-agent":
17153
+ return "claude-desktop";
17154
+ default:
17155
+ return null;
17156
+ }
17157
+ }
17158
+ function resolveTranscriptStores(input) {
17159
+ const resolved = [];
17160
+ for (const def of TRANSCRIPT_STORES) {
17161
+ const path2 = def.path(input);
17162
+ if (path2 === null)
17163
+ continue;
17164
+ resolved.push({ def, path: path2, altPaths: def.altPaths?.(input) ?? [] });
17165
+ }
17166
+ return resolved;
17167
+ }
17168
+ function familyMembers(family, table = TRANSCRIPT_STORES) {
17169
+ const slugs = new Set;
17170
+ for (const store of table) {
17171
+ if (store.family !== family)
17172
+ continue;
17173
+ for (const member of store.members)
17174
+ slugs.add(member);
17175
+ }
17176
+ return [...slugs];
17177
+ }
17178
+ function isStoreUnlocked(def, detectedSlugs, table = TRANSCRIPT_STORES) {
17179
+ const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
17180
+ return familyMembers(def.family, table).some((m) => detected.has(m));
17181
+ }
17182
+ function telemetryOwner(def, detectedSlugs) {
17183
+ const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
17184
+ if (detected.has(def.readerSlug))
17185
+ return def.readerSlug;
17186
+ return def.members.find((m) => detected.has(m)) ?? null;
17187
+ }
17188
+ function suppressedStoreReaders(detectedSlugs, sharesImplementation, table = TRANSCRIPT_STORES) {
17189
+ const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
17190
+ const suppressed = new Set;
17191
+ for (const store of table) {
17192
+ const owner = telemetryOwner(store, detected);
17193
+ if (owner === null)
17194
+ continue;
17195
+ for (const member of store.members) {
17196
+ if (member === owner || !detected.has(member))
17197
+ continue;
17198
+ if (sharesImplementation(member, owner))
17199
+ suppressed.add(member);
17200
+ }
17201
+ }
17202
+ return suppressed;
17203
+ }
17204
+ function attributeTranscript(def, head) {
17205
+ if (head === null || !def.marker) {
17206
+ return { agentSlug: def.defaultMember, marker: null, recognised: false };
17207
+ }
17208
+ const marker = def.marker(head);
17209
+ if (marker === null)
17210
+ return { agentSlug: def.defaultMember, marker: null, recognised: false };
17211
+ const slug = def.attribute?.(marker) ?? null;
17212
+ return slug === null ? { agentSlug: def.defaultMember, marker, recognised: false } : { agentSlug: slug, marker, recognised: true };
17213
+ }
17214
+ var CODEX_HEAD, CLAUDE_HEAD, TRANSCRIPT_STORES;
17215
+ var init_transcript_stores = __esm(() => {
17216
+ CODEX_HEAD = 256 * 1024;
17217
+ CLAUDE_HEAD = 64 * 1024;
17218
+ TRANSCRIPT_STORES = [
17219
+ {
17220
+ id: "codex/sessions",
17221
+ readerSlug: "codex",
17222
+ family: "codex",
17223
+ members: ["codex", "codex-app"],
17224
+ defaultMember: "codex",
17225
+ kind: "dir",
17226
+ path: (i) => joiner(i)(home(i), ".codex", "sessions"),
17227
+ matches: (n) => n.startsWith("rollout-") && n.endsWith(".jsonl"),
17228
+ headBytes: CODEX_HEAD,
17229
+ marker: codexOriginator,
17230
+ attribute: attributeCodexOriginator
17231
+ },
17232
+ {
17233
+ id: "claude/projects",
17234
+ readerSlug: "claude-code",
17235
+ family: "claude",
17236
+ members: ["claude-code", "claude-desktop"],
17237
+ defaultMember: "claude-code",
17238
+ kind: "dir",
17239
+ path: (i) => joiner(i)(home(i), ".claude", "projects"),
17240
+ matches: (n) => n.endsWith(".jsonl"),
17241
+ subordinate: (rel) => rel.split(/[\\/]/).length > 2,
17242
+ headBytes: CLAUDE_HEAD,
17243
+ marker: claudeEntrypoint,
17244
+ attribute: attributeClaudeEntrypoint
17245
+ },
17246
+ {
17247
+ id: "claude/cowork",
17248
+ readerSlug: "claude-desktop",
17249
+ family: "claude",
17250
+ members: ["claude-desktop"],
17251
+ defaultMember: "claude-desktop",
17252
+ kind: "dir",
17253
+ path: (i) => joiner(i)(appDataRoot(i), "Claude", "local-agent-mode-sessions"),
17254
+ altPaths: (i) => i.platform === "win32" ? [joiner(i)(localAppDataRoot(i), "Packages", "Claude_pzs8sxrjxfjjc", "LocalCache", "Roaming", "Claude", "local-agent-mode-sessions")] : [],
17255
+ matches: (n) => n.endsWith(".jsonl"),
17256
+ headBytes: CLAUDE_HEAD,
17257
+ marker: claudeEntrypoint,
17258
+ attribute: attributeClaudeEntrypoint,
17259
+ note: "macOS TCC can refuse this while it still exists"
17260
+ },
17261
+ {
17262
+ id: "gemini/tmp",
17263
+ readerSlug: "gemini",
17264
+ family: "gemini",
17265
+ members: ["gemini"],
17266
+ defaultMember: "gemini",
17267
+ kind: "dir",
17268
+ path: (i) => joiner(i)(home(i), ".gemini", "tmp"),
17269
+ matches: (n) => n.endsWith(".json")
17270
+ },
17271
+ {
17272
+ id: "cursor/state",
17273
+ readerSlug: "cursor",
17274
+ family: "cursor",
17275
+ members: ["cursor"],
17276
+ defaultMember: "cursor",
17277
+ kind: "file",
17278
+ path: (i) => joiner(i)(appDataRoot(i), "Cursor", "User", "globalStorage", "state.vscdb"),
17279
+ tool: "sqlite"
17280
+ }
17281
+ ];
17282
+ });
17283
+
16840
17284
  // src/reflect/conversation-registry.ts
17285
+ import { homedir as homedir22, platform as platform7 } from "os";
16841
17286
  function computeStatus(lastActivityAt, nowMs, idleMinutes = DEFAULT_IDLE_MINUTES) {
16842
17287
  const lastMs = new Date(lastActivityAt).getTime();
16843
17288
  if (Number.isNaN(lastMs))
@@ -16868,44 +17313,114 @@ function mergeSessionListings(listings, opts) {
16868
17313
  status: isFreshEndStamp(s.endedAt, s.lastActivityAt) ? "finished" : computeStatus(s.lastActivityAt, opts.nowMs, opts.idleMinutes)
16869
17314
  }));
16870
17315
  }
17316
+ function machineStores(opts) {
17317
+ return opts.stores ?? resolveTranscriptStores({
17318
+ platform: platform7(),
17319
+ homeDir: homedir22(),
17320
+ appData: process.env.APPDATA ?? null,
17321
+ localAppData: process.env.LOCALAPPDATA ?? null
17322
+ });
17323
+ }
17324
+ function attributeListing(store, sessions) {
17325
+ if (!store.def.attribute)
17326
+ return sessions;
17327
+ return sessions.map((s) => {
17328
+ const surface = s.surface ?? null;
17329
+ const slug = surface === null ? null : store.def.attribute?.(surface) ?? null;
17330
+ return {
17331
+ ...s,
17332
+ agentSlug: slug ?? store.def.defaultMember,
17333
+ surface
17334
+ };
17335
+ });
17336
+ }
16871
17337
  async function listLocalConversations(opts = {}) {
16872
- const adapters = await detectAgents();
17338
+ const detected = opts.detected ?? (await detectAgents()).map((a) => a.slug);
17339
+ const detectedSet = new Set(detected);
16873
17340
  const sinceISO = opts.sinceISO ?? null;
17341
+ const maxPerStore = opts.maxPerStore ?? DEFAULT_MAX_PER_STORE;
16874
17342
  const listings = [];
16875
- const perAgent = [];
16876
- for (const adapter2 of adapters) {
16877
- if (!adapter2.listSessions) {
16878
- perAgent.push({ agentSlug: adapter2.slug, status: "no-reader", sessions: null });
17343
+ const perStore = [];
17344
+ const stores = machineStores(opts);
17345
+ const table = stores.map((s) => s.def);
17346
+ for (const store of stores) {
17347
+ const base = {
17348
+ storeId: store.def.id,
17349
+ family: store.def.family,
17350
+ members: [...familyMembers(store.def.family, table)],
17351
+ path: store.path
17352
+ };
17353
+ if (!isStoreUnlocked(store.def, detectedSet, table)) {
17354
+ perStore.push({ ...base, status: "orphaned", sessions: null });
17355
+ continue;
17356
+ }
17357
+ const reader = (opts.readerFor ?? getAdapterBySlug)(store.def.readerSlug);
17358
+ if (!reader?.listSessions) {
17359
+ perStore.push({ ...base, status: "no-reader", sessions: null });
16879
17360
  continue;
16880
17361
  }
16881
17362
  try {
16882
- const sessions = await adapter2.listSessions(sinceISO);
17363
+ const sessions = await reader.listSessions(sinceISO);
16883
17364
  if (sessions === null) {
16884
- perAgent.push(diagnoseTranscriptRead(adapter2));
17365
+ const outcome = diagnoseTranscriptRead(reader);
17366
+ perStore.push({ ...base, status: outcome.status, sessions: null, ...outcome.detail ? { detail: outcome.detail } : {} });
16885
17367
  continue;
16886
17368
  }
16887
- listings.push(sessions);
16888
- perAgent.push({ agentSlug: adapter2.slug, status: "ok", sessions: sessions.length });
17369
+ const attributed = attributeListing(store, sessions).sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt)).slice(0, maxPerStore);
17370
+ listings.push(attributed);
17371
+ perStore.push({
17372
+ ...base,
17373
+ status: "ok",
17374
+ sessions: attributed.length,
17375
+ ...sessions.length > attributed.length ? { truncated: sessions.length } : {}
17376
+ });
16889
17377
  } catch (err) {
16890
- perAgent.push(diagnoseTranscriptRead(adapter2, err));
17378
+ const outcome = diagnoseTranscriptRead(reader, err);
17379
+ perStore.push({ ...base, status: outcome.status, sessions: null, ...outcome.detail ? { detail: outcome.detail } : {} });
16891
17380
  }
16892
17381
  }
16893
17382
  const conversations = mergeSessionListings(listings, {
16894
17383
  nowMs: opts.nowMs ?? Date.now(),
16895
17384
  idleMinutes: opts.idleMinutes
16896
17385
  });
16897
- return { conversations, perAgent };
17386
+ return { conversations, perAgent: derivePerAgent(perStore, conversations), perStore };
16898
17387
  }
16899
- var DEFAULT_IDLE_MINUTES = 10;
17388
+ function derivePerAgent(perStore, conversations) {
17389
+ const counts = new Map;
17390
+ for (const c of conversations)
17391
+ counts.set(c.agentSlug, (counts.get(c.agentSlug) ?? 0) + 1);
17392
+ const rows = new Map;
17393
+ for (const store of perStore) {
17394
+ for (const slug of store.members) {
17395
+ const existing = rows.get(slug);
17396
+ if (store.status === "ok") {
17397
+ rows.set(slug, { agentSlug: slug, status: "ok", sessions: counts.get(slug) ?? 0 });
17398
+ continue;
17399
+ }
17400
+ if (!existing || existing.status !== "ok") {
17401
+ rows.set(slug, {
17402
+ agentSlug: slug,
17403
+ status: store.status === "orphaned" ? "missing-dir" : store.status,
17404
+ sessions: null,
17405
+ ...store.path ? { path: store.path } : {},
17406
+ ...store.detail ? { detail: store.detail } : {}
17407
+ });
17408
+ }
17409
+ }
17410
+ }
17411
+ return [...rows.values()];
17412
+ }
17413
+ var DEFAULT_IDLE_MINUTES = 10, DEFAULT_MAX_PER_STORE = 500;
16900
17414
  var init_conversation_registry = __esm(async () => {
16901
17415
  init_transcript_sources();
17416
+ init_transcript_stores();
16902
17417
  await init_detect();
16903
17418
  });
16904
17419
 
16905
17420
  // src/reflect/session-summary.ts
16906
17421
  import { createHash as createHash4 } from "crypto";
16907
17422
  import { execFileSync as execFileSync3 } from "child_process";
16908
- import { readFileSync as readFileSync35 } from "fs";
17423
+ import { readFileSync as readFileSync36 } from "fs";
16909
17424
  import { isAbsolute as isAbsolute4 } from "path";
16910
17425
  function validateAssetMarkers(markers, knownSkills) {
16911
17426
  if (!markers || markers.length === 0)
@@ -17007,7 +17522,7 @@ function digestForEntry(entry) {
17007
17522
  return null;
17008
17523
  let content;
17009
17524
  try {
17010
- content = readFileSync35(entry.transcriptPath, "utf-8");
17525
+ content = readFileSync36(entry.transcriptPath, "utf-8");
17011
17526
  } catch {
17012
17527
  return null;
17013
17528
  }
@@ -17135,18 +17650,18 @@ var init_session_summary = __esm(() => {
17135
17650
  });
17136
17651
 
17137
17652
  // src/reflect/telemetry-outbox.ts
17138
- import { existsSync as existsSync46, readFileSync as readFileSync36 } from "fs";
17139
- import { join as join41 } from "path";
17140
- import { homedir as homedir22 } from "os";
17653
+ import { existsSync as existsSync47, readFileSync as readFileSync37 } from "fs";
17654
+ import { join as join42 } from "path";
17655
+ import { homedir as homedir23 } from "os";
17141
17656
  function outboxPath() {
17142
- return join41(homedir22(), ".runwork", "telemetry-outbox.json");
17657
+ return join42(homedir23(), ".runwork", "telemetry-outbox.json");
17143
17658
  }
17144
17659
  function loadTelemetryOutbox() {
17145
17660
  try {
17146
17661
  const p = outboxPath();
17147
- if (!existsSync46(p))
17662
+ if (!existsSync47(p))
17148
17663
  return [];
17149
- const parsed = JSON.parse(readFileSync36(p, "utf-8"));
17664
+ const parsed = JSON.parse(readFileSync37(p, "utf-8"));
17150
17665
  if (!Array.isArray(parsed))
17151
17666
  return [];
17152
17667
  return parsed.filter((e) => !!e && typeof e === "object" && typeof e.dedupeKey === "string" && !!e.event && typeof e.event === "object");
@@ -17207,8 +17722,8 @@ var init_active_time = __esm(() => {
17207
17722
 
17208
17723
  // src/reflect/pattern-store.ts
17209
17724
  import { createHash as createHash5 } from "crypto";
17210
- import { join as join42 } from "path";
17211
- import { homedir as homedir23 } from "os";
17725
+ import { join as join43 } from "path";
17726
+ import { homedir as homedir24 } from "os";
17212
17727
  function addBuckets(a, b) {
17213
17728
  if (!a)
17214
17729
  return b ? { ...b } : null;
@@ -17369,7 +17884,7 @@ function buildPatternEvent(payload, nowISO) {
17369
17884
  };
17370
17885
  }
17371
17886
  function storePath3() {
17372
- return join42(homedir23(), ".runwork", "pattern-store.json");
17887
+ return join43(homedir24(), ".runwork", "pattern-store.json");
17373
17888
  }
17374
17889
  function loadPatternStore() {
17375
17890
  const parsed = readJsonOrNull(storePath3());
@@ -17579,7 +18094,7 @@ var init_triage = __esm(async () => {
17579
18094
  });
17580
18095
 
17581
18096
  // src/reflect/conversation-analysis.ts
17582
- import { existsSync as existsSync47 } from "fs";
18097
+ import { existsSync as existsSync48 } from "fs";
17583
18098
  import { basename as basename5 } from "path";
17584
18099
  function brokenAnalystBinaries() {
17585
18100
  return TIER2_ANALYSTS.filter((a) => {
@@ -17607,7 +18122,7 @@ function isPromptStillValid(key) {
17607
18122
  if (!standing?.promptPath || standing.promptConversationKey !== key)
17608
18123
  return false;
17609
18124
  try {
17610
- return existsSync47(standing.promptPath);
18125
+ return existsSync48(standing.promptPath);
17611
18126
  } catch {
17612
18127
  return false;
17613
18128
  }
@@ -19529,17 +20044,10 @@ async function parseCurlToRequest(curlStr) {
19529
20044
  try {
19530
20045
  body = JSON.parse(dataStr);
19531
20046
  } catch {
19532
- if (dataStr.includes("=") && !dataStr.includes("{")) {
19533
- const formData = {};
19534
- for (const pair of dataStr.split("&")) {
19535
- const eqIdx = pair.indexOf("=");
19536
- if (eqIdx > 0) {
19537
- formData[decodeURIComponent(pair.slice(0, eqIdx))] = decodeURIComponent(pair.slice(eqIdx + 1));
19538
- }
19539
- }
19540
- body = formData;
19541
- } else {
19542
- body = dataStr;
20047
+ body = dataStr;
20048
+ const hasContentType = Object.keys(filteredHeaders).some((k) => k.toLowerCase() === "content-type");
20049
+ if (!hasContentType) {
20050
+ filteredHeaders["Content-Type"] = "application/x-www-form-urlencoded";
19543
20051
  }
19544
20052
  }
19545
20053
  }
@@ -19665,16 +20173,19 @@ Used by your team (${teamOnly.length} more):
19665
20173
  process.exit(1);
19666
20174
  }
19667
20175
  });
19668
- var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <name-or-id>", "Workspace name or ID").option("--body <json>", "Request body JSON").option("--header <header>", "Request header (repeatable)", (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g., limit=10&offset=0)").option("--curl <command>", 'Parse a curl command (paste from Chrome DevTools "Copy as cURL")').option("--curl-file <file>", "Read curl command from a file").action(async (integration, method, path2, opts, command) => {
20176
+ var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <name-or-id>", "Workspace name or ID").option("--body <body>", "Request body: JSON, or a raw string when a non-JSON Content-Type header is set").option("--form", "Send the body as application/x-www-form-urlencoded (Stripe, Twilio, OAuth token endpoints). Accepts a JSON object (form-encoded, nested keys in bracket notation) or an already-encoded a=b&c=d string").option("--header <header>", "Request header (repeatable). Content-Type decides how --body is encoded", (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g., limit=10&offset=0)").option("--curl <command>", 'Parse a curl command (paste from Chrome DevTools "Copy as cURL")').option("--curl-file <file>", "Read curl command from a file").action(async (integration, method, path2, opts, command) => {
19669
20177
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
19670
20178
  const credentials = requireAuth();
19671
20179
  const client = new ApiClient(credentials);
19672
20180
  const { workspaceId } = await resolveWorkspace2(client, opts);
19673
20181
  let finalMethod;
19674
20182
  let finalPath;
19675
- const headers = {};
20183
+ let headers = {};
19676
20184
  let body;
19677
20185
  let query = opts.query;
20186
+ if (opts.form) {
20187
+ headers = setHeader(headers, "Content-Type", FORM_CONTENT_TYPE);
20188
+ }
19678
20189
  if (opts.curl || opts.curlFile) {
19679
20190
  let curlStr = opts.curl;
19680
20191
  if (opts.curlFile) {
@@ -19691,7 +20202,7 @@ var callCommand = new Command10("call").description("Make a proxy call to a conn
19691
20202
  finalPath = result.path;
19692
20203
  if (result.query)
19693
20204
  query = query || result.query;
19694
- Object.assign(headers, result.headers);
20205
+ headers = opts.form ? setHeader({ ...result.headers }, "Content-Type", FORM_CONTENT_TYPE) : { ...result.headers };
19695
20206
  body = result.body;
19696
20207
  } catch (err) {
19697
20208
  console.error("Failed to parse curl command:", err instanceof Error ? err.message : err);
@@ -19702,13 +20213,13 @@ var callCommand = new Command10("call").description("Make a proxy call to a conn
19702
20213
  finalPath = path2;
19703
20214
  for (const h of opts.header || []) {
19704
20215
  const [key, ...rest] = h.split(":");
19705
- headers[key.trim()] = rest.join(":").trim();
20216
+ headers = setHeader(headers, key.trim(), rest.join(":").trim());
19706
20217
  }
19707
20218
  if (opts.body) {
19708
20219
  try {
19709
- body = JSON.parse(opts.body);
19710
- } catch {
19711
- console.error("Invalid JSON in --body");
20220
+ body = parseBodyArgument(opts.body, findHeader(headers, "Content-Type"));
20221
+ } catch (err) {
20222
+ console.error(err instanceof Error ? err.message : "Invalid --body");
19712
20223
  process.exit(1);
19713
20224
  }
19714
20225
  }
@@ -20661,6 +21172,159 @@ var skillsCommand = new Command13("skills").description("Manage workspace skills
20661
21172
  // src/index.ts
20662
21173
  await init_reflect();
20663
21174
 
21175
+ // src/commands/conversations.ts
21176
+ init_transcript_stores();
21177
+ await init_detect();
21178
+ import { Command as Command15 } from "commander";
21179
+ import { join as join44 } from "path";
21180
+ import { homedir as homedir25, platform as platform8 } from "os";
21181
+
21182
+ // src/agents/store-census.ts
21183
+ init_transcript_stores();
21184
+ import { readdirSync as readdirSync16, statSync as statSync10, existsSync as existsSync46, openSync as openSync5, readSync as readSync3, closeSync as closeSync5 } from "fs";
21185
+ import { join as join41 } from "path";
21186
+ function sanitizeMarker(raw) {
21187
+ const cleaned = raw.replace(/[^\x20-\x7E]/g, "").trim();
21188
+ return cleaned.length > 64 ? `${cleaned.slice(0, 63)}…` : cleaned;
21189
+ }
21190
+ function readHead(path2, n) {
21191
+ let fd;
21192
+ try {
21193
+ fd = openSync5(path2, "r");
21194
+ const buf = Buffer.alloc(n);
21195
+ const read = readSync3(fd, buf, 0, n, 0);
21196
+ return buf.subarray(0, read).toString("utf-8");
21197
+ } catch {
21198
+ return null;
21199
+ } finally {
21200
+ if (fd !== undefined) {
21201
+ try {
21202
+ closeSync5(fd);
21203
+ } catch {}
21204
+ }
21205
+ }
21206
+ }
21207
+ function isPermissionError(err) {
21208
+ const code = err?.code;
21209
+ return code === "EACCES" || code === "EPERM";
21210
+ }
21211
+ function isMissingError(err) {
21212
+ const code = err?.code;
21213
+ return code === "ENOENT" || code === "ENOTDIR";
21214
+ }
21215
+ function collect(dir, def, out, budget) {
21216
+ if (budget.left <= 0)
21217
+ return;
21218
+ const entries = readdirSync16(dir, { withFileTypes: true });
21219
+ for (const e of entries) {
21220
+ if (budget.left <= 0)
21221
+ return;
21222
+ const full = join41(dir, e.name);
21223
+ if (e.isDirectory()) {
21224
+ try {
21225
+ collect(full, def, out, budget);
21226
+ } catch (err) {
21227
+ if (isPermissionError(err))
21228
+ throw err;
21229
+ }
21230
+ } else if (!def.matches || def.matches(e.name)) {
21231
+ out.push(full);
21232
+ budget.left--;
21233
+ }
21234
+ }
21235
+ }
21236
+ var DEFAULT_MAX_FILES = 2000;
21237
+ function censusStore(store, unlocked, opts = {}) {
21238
+ const { def, path: path2, altPaths } = store;
21239
+ const base = {
21240
+ storeId: def.id,
21241
+ family: def.family,
21242
+ members: def.members,
21243
+ path: path2,
21244
+ unlocked,
21245
+ status: "ok"
21246
+ };
21247
+ const altHits = altPaths.filter((p) => {
21248
+ try {
21249
+ return existsSync46(p);
21250
+ } catch {
21251
+ return false;
21252
+ }
21253
+ });
21254
+ if (altHits.length > 0)
21255
+ base.altHits = altHits;
21256
+ if (!existsSync46(path2))
21257
+ return { ...base, status: "missing" };
21258
+ if (def.kind === "file") {
21259
+ try {
21260
+ const s = statSync10(path2);
21261
+ return { ...base, files: 1, bytes: s.size, newestAt: new Date(s.mtimeMs).toISOString() };
21262
+ } catch (err) {
21263
+ return { ...base, status: isPermissionError(err) ? "permission-denied" : "error", detail: String(err) };
21264
+ }
21265
+ }
21266
+ const all = [];
21267
+ const budget = { left: opts.maxFiles ?? DEFAULT_MAX_FILES };
21268
+ try {
21269
+ collect(path2, def, all, budget);
21270
+ } catch (err) {
21271
+ if (isPermissionError(err))
21272
+ return { ...base, status: "permission-denied", detail: "EACCES" };
21273
+ if (isMissingError(err))
21274
+ return { ...base, status: "missing" };
21275
+ return { ...base, status: "error", detail: err instanceof Error ? err.message : String(err) };
21276
+ }
21277
+ const files = [];
21278
+ let nested = 0;
21279
+ for (const f of all) {
21280
+ const rel = f.slice(path2.length).replace(/^[\\/]+/, "");
21281
+ if (def.subordinate?.(rel))
21282
+ nested++;
21283
+ else
21284
+ files.push(f);
21285
+ }
21286
+ let bytes = 0;
21287
+ let newest = 0;
21288
+ for (const f of all) {
21289
+ try {
21290
+ const s = statSync10(f);
21291
+ bytes += s.size;
21292
+ if (s.mtimeMs > newest)
21293
+ newest = s.mtimeMs;
21294
+ } catch {}
21295
+ }
21296
+ const result = {
21297
+ ...base,
21298
+ files: files.length,
21299
+ ...nested > 0 ? { nested } : {},
21300
+ bytes,
21301
+ newestAt: newest > 0 ? new Date(newest).toISOString() : null
21302
+ };
21303
+ if (opts.skipMarkers || !def.marker)
21304
+ return result;
21305
+ const counts = new Map;
21306
+ for (const f of files) {
21307
+ const head = readHead(f, def.headBytes ?? 64 * 1024);
21308
+ const { agentSlug, marker, recognised } = attributeTranscript(def, head);
21309
+ const clean = marker === null ? null : sanitizeMarker(marker);
21310
+ const key = clean ?? "\x00none";
21311
+ const existing = counts.get(key);
21312
+ if (existing)
21313
+ existing.count++;
21314
+ else
21315
+ counts.set(key, { marker: clean, count: 1, agentSlug, recognised });
21316
+ }
21317
+ result.markers = [...counts.values()].sort((a, b) => b.count - a.count);
21318
+ return result;
21319
+ }
21320
+ function censusStores(stores, detectedSlugs, opts = {}) {
21321
+ const detected = new Set(detectedSlugs);
21322
+ return stores.map((store) => censusStore(store, isStoreUnlocked(store.def, detected), opts));
21323
+ }
21324
+ function orphanedStoresWithContent(censuses) {
21325
+ return censuses.filter((c) => !c.unlocked && c.status === "ok" && (c.files ?? 0) > 0);
21326
+ }
21327
+
20664
21328
  // src/commands/conversations.ts
20665
21329
  init_conversation_queue();
20666
21330
  init_session_summary();
@@ -20676,10 +21340,7 @@ await __promiseAll([
20676
21340
  init_conversation_registry(),
20677
21341
  init_conversation_analysis()
20678
21342
  ]);
20679
- import { Command as Command15 } from "commander";
20680
- import { join as join43 } from "path";
20681
- import { homedir as homedir24 } from "os";
20682
- var DEFAULT_LOOKBACK_DAYS = 30;
21343
+ var DEFAULT_LOOKBACK_DAYS = 0;
20683
21344
  function sinceFromDays(days) {
20684
21345
  if (days <= 0)
20685
21346
  return null;
@@ -20743,18 +21404,25 @@ function fit(text2, width) {
20743
21404
  return text2.length > width ? text2.slice(0, width - 1) + "…" : text2;
20744
21405
  }
20745
21406
  var conversationsCommand = new Command15("conversations").description("Local AI conversations across your agents (registry, end detection)");
20746
- conversationsCommand.command("list").description("List local conversations across all detected agents (metadata only)").option("--days <n>", "Look back this many days (0 = no limit)", String(DEFAULT_LOOKBACK_DAYS)).option("--idle-minutes <n>", "Idle threshold that marks a conversation finished", String(DEFAULT_IDLE_MINUTES)).action(async (opts, command) => {
21407
+ conversationsCommand.command("list").description("List local conversations across all detected agents (metadata only)").option("--days <n>", "Narrow to this many days (0 = no window, the default)", String(DEFAULT_LOOKBACK_DAYS)).option("--idle-minutes <n>", "Idle threshold that marks a conversation finished", String(DEFAULT_IDLE_MINUTES)).action(async (opts, command) => {
20747
21408
  const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
20748
21409
  const days = parseDays(opts.days);
20749
21410
  const idleMinutes = Math.max(1, Number(opts.idleMinutes) || DEFAULT_IDLE_MINUTES);
20750
21411
  const result = await listLocalConversations({ sinceISO: sinceFromDays(days), idleMinutes });
20751
21412
  if (json) {
20752
- jsonOut({ conversations: result.conversations, perAgent: result.perAgent });
21413
+ jsonOut({ conversations: result.conversations, perAgent: result.perAgent, perStore: result.perStore });
20753
21414
  return;
20754
21415
  }
20755
21416
  console.log(bold(days > 0 ? `
20756
21417
  Local conversations, last ${days} day(s)` : `
20757
21418
  Local conversations (all)`));
21419
+ for (const s of result.perStore) {
21420
+ const reason = describeStoreOutcome(s);
21421
+ if (reason === null)
21422
+ continue;
21423
+ const line = ` ${s.storeId}: ${reason}`;
21424
+ console.log(storeOutcomeNeedsAttention(s) ? yellow(line) : dim(line));
21425
+ }
20758
21426
  for (const a of result.perAgent) {
20759
21427
  if (a.status === "no-reader")
20760
21428
  continue;
@@ -20780,17 +21448,26 @@ Local conversations (all)`));
20780
21448
  if (result.conversations.length === 0)
20781
21449
  console.log(dim(" none"));
20782
21450
  });
20783
- conversationsCommand.command("status").description("Why each agent did or did not contribute conversations (no conversation data)").option("--days <n>", "Look back this many days (0 = no limit)", String(DEFAULT_LOOKBACK_DAYS)).action(async (opts, command) => {
21451
+ conversationsCommand.command("status").description("Why each agent did or did not contribute conversations (no conversation data)").option("--days <n>", "Narrow to this many days (0 = no window, the default)", String(DEFAULT_LOOKBACK_DAYS)).action(async (opts, command) => {
20784
21452
  const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
20785
21453
  const days = parseDays(opts.days);
20786
- const { perAgent } = await listLocalConversations({ sinceISO: sinceFromDays(days) });
21454
+ const { perAgent, perStore } = await listLocalConversations({ sinceISO: sinceFromDays(days) });
20787
21455
  if (json) {
20788
- jsonOut({ perAgent });
21456
+ jsonOut({ perAgent, perStore });
20789
21457
  return;
20790
21458
  }
20791
21459
  console.log(bold(days > 0 ? `
20792
21460
  Conversation sources, last ${days} day(s)` : `
20793
21461
  Conversation sources`));
21462
+ for (const s of perStore) {
21463
+ const reason = describeStoreOutcome(s);
21464
+ if (reason === null) {
21465
+ console.log(` ${cyan(s.storeId)}: ${s.sessions} conversation(s)`);
21466
+ } else {
21467
+ console.log(` ${cyan(s.storeId)}: ${storeOutcomeNeedsAttention(s) ? yellow(reason) : dim(reason)}`);
21468
+ }
21469
+ }
21470
+ console.log("");
20794
21471
  for (const a of perAgent) {
20795
21472
  const reason = describeScanOutcome(a);
20796
21473
  if (reason === null) {
@@ -20800,7 +21477,7 @@ Conversation sources`));
20800
21477
  }
20801
21478
  }
20802
21479
  });
20803
- conversationsCommand.command("scan").description("Detect finished conversations (idle threshold) and queue them for reflection").option("--days <n>", "Look back this many days (0 = no limit)", String(DEFAULT_LOOKBACK_DAYS)).option("--idle-minutes <n>", "Idle threshold that marks a conversation finished", String(DEFAULT_IDLE_MINUTES)).action(async (opts, command) => {
21480
+ conversationsCommand.command("scan").description("Detect finished conversations (idle threshold) and queue them for reflection").option("--days <n>", "Narrow to this many days (0 = no window, the default)", String(DEFAULT_LOOKBACK_DAYS)).option("--idle-minutes <n>", "Idle threshold that marks a conversation finished", String(DEFAULT_IDLE_MINUTES)).action(async (opts, command) => {
20804
21481
  const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
20805
21482
  const days = parseDays(opts.days);
20806
21483
  const idleMinutes = Math.max(1, Number(opts.idleMinutes) || DEFAULT_IDLE_MINUTES);
@@ -20864,9 +21541,10 @@ conversationsCommand.command("scan").description("Detect finished conversations
20864
21541
  generatedAt: new Date().toISOString(),
20865
21542
  idleMinutes,
20866
21543
  conversations: [...listed, ...rescued].sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt)),
20867
- perAgent: result.perAgent
21544
+ perAgent: result.perAgent,
21545
+ perStore: result.perStore
20868
21546
  };
20869
- writeJsonAtomic(join43(homedir24(), ".runwork", "conversations.json"), snapshot);
21547
+ writeJsonAtomic(join44(homedir25(), ".runwork", "conversations.json"), snapshot);
20870
21548
  if (json) {
20871
21549
  jsonOut({ queued: scan.queued, reopened: scan.reopened, pruned: scan.pruned, pending, finished: finished.length, perAgent: result.perAgent });
20872
21550
  return;
@@ -20889,15 +21567,71 @@ conversationsCommand.command("analyze").description("Analyze queued finished con
20889
21567
  }
20890
21568
  console.log(outcome.reason ? dim(describeAnalysisOutcome(outcome)) : green(describeAnalysisOutcome(outcome)));
20891
21569
  });
21570
+ conversationsCommand.command("stores").description("Every local transcript store: what is in it, who wrote it, and whether anything reads it").option("--max-files <n>", "Cap transcripts inspected per store", String(DEFAULT_MAX_FILES)).option("--no-markers", "Skip provenance reads; counts, sizes and mtimes only").action(async (opts, command) => {
21571
+ const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
21572
+ const maxFiles = Math.max(1, Number(opts.maxFiles) || DEFAULT_MAX_FILES);
21573
+ const detected = (await detectAgents()).map((a) => a.slug);
21574
+ const stores = resolveTranscriptStores({
21575
+ platform: platform8(),
21576
+ homeDir: homedir25(),
21577
+ appData: process.env.APPDATA ?? null,
21578
+ localAppData: process.env.LOCALAPPDATA ?? null
21579
+ });
21580
+ const censuses = censusStores(stores, detected, {
21581
+ maxFiles,
21582
+ skipMarkers: opts.markers === false
21583
+ });
21584
+ if (json) {
21585
+ jsonOut({ detected, stores: censuses });
21586
+ return;
21587
+ }
21588
+ console.log(bold(`
21589
+ Transcript stores`));
21590
+ console.log(dim(` detected agents: ${detected.length > 0 ? detected.join(", ") : "none"}
21591
+ `));
21592
+ for (const c of censuses) {
21593
+ const owner = c.unlocked ? green("read") : yellow("ORPHANED");
21594
+ console.log(`${bold(c.storeId)} ${owner} ${dim(`family ${c.family}: ${c.members.join(", ")}`)}`);
21595
+ console.log(dim(` ${c.path}`));
21596
+ if (c.status !== "ok") {
21597
+ console.log(` ${yellow(c.status)}${c.detail ? dim(` (${c.detail})`) : ""}`);
21598
+ } else {
21599
+ const mb = ((c.bytes ?? 0) / 1e6).toFixed(1);
21600
+ const newest = c.newestAt ? c.newestAt.slice(0, 16).replace("T", " ") : "-";
21601
+ const nested = c.nested ? `, plus ${c.nested} subagent transcript(s)` : "";
21602
+ console.log(dim(` ${c.files} conversation(s)${nested}, ${mb} MB, newest ${newest}`));
21603
+ for (const m of c.markers ?? []) {
21604
+ if (m.marker === null) {
21605
+ console.log(` ${String(m.count).padStart(5)} ${dim(`(no marker, pre-dates the field) -> ${m.agentSlug}`)}`);
21606
+ continue;
21607
+ }
21608
+ const flag = m.recognised ? dim(`-> ${m.agentSlug}`) : yellow(`-> ${m.agentSlug} (UNRECOGNISED surface)`);
21609
+ console.log(` ${String(m.count).padStart(5)} ${cyan(m.marker)} ${flag}`);
21610
+ }
21611
+ }
21612
+ for (const alt of c.altHits ?? []) {
21613
+ console.log(` ${yellow("also present:")} ${dim(alt)}`);
21614
+ }
21615
+ console.log("");
21616
+ }
21617
+ const orphans = orphanedStoresWithContent(censuses);
21618
+ if (orphans.length > 0) {
21619
+ console.log(yellow(`${orphans.length} store(s) hold transcripts that no detected agent reads:`));
21620
+ for (const o of orphans) {
21621
+ console.log(` ${o.path} ${dim(`(${o.files} transcripts; needs one of: ${o.members.join(", ")})`)}`);
21622
+ }
21623
+ console.log("");
21624
+ }
21625
+ });
20892
21626
 
20893
21627
  // src/commands/instructions.ts
20894
21628
  init_store();
20895
21629
  init_client();
20896
21630
  init_resolve();
20897
21631
  import { Command as Command16 } from "commander";
20898
- import { readFileSync as readFileSync37, existsSync as existsSync48 } from "fs";
20899
- import { join as join44 } from "path";
20900
- import { homedir as homedir25 } from "os";
21632
+ import { readFileSync as readFileSync38, existsSync as existsSync49 } from "fs";
21633
+ import { join as join45 } from "path";
21634
+ import { homedir as homedir26 } from "os";
20901
21635
 
20902
21636
  // ../../shared/agent-instructions/runwork-instructions.ts
20903
21637
  function formatList(items, max = 8) {
@@ -21240,7 +21974,7 @@ function generateIntroSkill(ctx) {
21240
21974
  lines.push("| `runwork entities list` | Browse data across apps |");
21241
21975
  lines.push("| `runwork entities records <name>` | Query entity records |");
21242
21976
  lines.push("| `runwork workflows trigger <name>` | Trigger a workflow |");
21243
- lines.push("| `runwork integrations call <id> <method> <path>` | Call an integration API |");
21977
+ lines.push("| `runwork integrations call <id> <method> <path>` | Call an integration API (`--body` JSON; `--form` for form-encoded APIs such as Stripe) |");
21244
21978
  lines.push("| `runwork integrations search <query>` | Search 3,200+ available integrations |");
21245
21979
  lines.push("| `runwork logs` | View app logs |");
21246
21980
  lines.push("| `runwork doctor` | Check system health (`--fix` auto-remediates git auth/remote; `--check <names>` scopes output) |");
@@ -21377,13 +22111,13 @@ async function buildInstructionContext(client, workspace) {
21377
22111
  // src/commands/instructions.ts
21378
22112
  function readSetupExtras(workspaceId) {
21379
22113
  for (const path2 of [
21380
- join44(process.cwd(), ".runwork", "setup.json"),
21381
- join44(homedir25(), ".runwork", "setup.json")
22114
+ join45(process.cwd(), ".runwork", "setup.json"),
22115
+ join45(homedir26(), ".runwork", "setup.json")
21382
22116
  ]) {
21383
- if (!existsSync48(path2))
22117
+ if (!existsSync49(path2))
21384
22118
  continue;
21385
22119
  try {
21386
- const state = JSON.parse(readFileSync37(path2, "utf-8"));
22120
+ const state = JSON.parse(readFileSync38(path2, "utf-8"));
21387
22121
  if (state.workspaceId === workspaceId) {
21388
22122
  return { workspaceSlug: state.workspaceSlug, persona: state.persona };
21389
22123
  }
@@ -21427,16 +22161,16 @@ import { Command as Command17 } from "commander";
21427
22161
  import * as path3 from "node:path";
21428
22162
 
21429
22163
  // src/utils/data-input.ts
21430
- import { readFileSync as readFileSync38, existsSync as existsSync49 } from "fs";
22164
+ import { readFileSync as readFileSync39, existsSync as existsSync50 } from "fs";
21431
22165
  async function parseDataInput(dataFlag) {
21432
22166
  if (dataFlag) {
21433
22167
  if (dataFlag.startsWith("@")) {
21434
22168
  const filePath = dataFlag.slice(1);
21435
- if (!existsSync49(filePath)) {
22169
+ if (!existsSync50(filePath)) {
21436
22170
  console.error(`File not found: ${filePath}`);
21437
22171
  process.exit(1);
21438
22172
  }
21439
- const content = readFileSync38(filePath, "utf-8");
22173
+ const content = readFileSync39(filePath, "utf-8");
21440
22174
  return parseJson(content, filePath);
21441
22175
  }
21442
22176
  return parseJson(dataFlag, "--data");
@@ -22490,7 +23224,7 @@ init_resolve();
22490
23224
  init_prompt();
22491
23225
  init_http();
22492
23226
  import { Command as Command21 } from "commander";
22493
- import { writeFileSync as writeFileSync29, readFileSync as readFileSync39 } from "fs";
23227
+ import { writeFileSync as writeFileSync29, readFileSync as readFileSync40 } from "fs";
22494
23228
  import { basename as basename6 } from "path";
22495
23229
  function formatSize(bytes) {
22496
23230
  if (bytes === undefined)
@@ -22600,7 +23334,7 @@ var uploadCommand = new Command21("upload").description("Upload a local file to
22600
23334
  const { workspaceId } = await resolveWorkspace2(client, opts);
22601
23335
  const objectKey = key || basename6(localPath);
22602
23336
  try {
22603
- const fileBuffer = readFileSync39(localPath);
23337
+ const fileBuffer = readFileSync40(localPath);
22604
23338
  const { url } = await client.getPresignedUrl(workspaceId, bucket, { action: "write", key: objectKey });
22605
23339
  const response = await httpFetch(url, { method: "PUT", body: fileBuffer });
22606
23340
  if (!response.ok) {
@@ -23117,8 +23851,8 @@ init_resolve();
23117
23851
  init_prompt();
23118
23852
  await init_detect();
23119
23853
  import { Command as Command27 } from "commander";
23120
- import { join as join49 } from "path";
23121
- import { homedir as homedir28 } from "os";
23854
+ import { join as join50 } from "path";
23855
+ import { homedir as homedir29 } from "os";
23122
23856
 
23123
23857
  // src/commands/sync.ts
23124
23858
  init_store();
@@ -23129,9 +23863,9 @@ await __promiseAll([
23129
23863
  init_codex()
23130
23864
  ]);
23131
23865
  import { Command as Command26 } from "commander";
23132
- import { readFileSync as readFileSync41, existsSync as existsSync52 } from "fs";
23133
- import { join as join48 } from "path";
23134
- import { homedir as homedir27 } from "os";
23866
+ import { readFileSync as readFileSync42, existsSync as existsSync53 } from "fs";
23867
+ import { join as join49 } from "path";
23868
+ import { homedir as homedir28 } from "os";
23135
23869
 
23136
23870
  // src/commands/mcp-entries.ts
23137
23871
  init_types();
@@ -23195,6 +23929,7 @@ var RUNWORK_AGENT_DEFAULTS = {
23195
23929
  };
23196
23930
  var AGENT_DEFAULTS_SCHEMA_VERSION = 1;
23197
23931
  // src/commands/sync-telemetry.ts
23932
+ init_transcript_stores();
23198
23933
  var TELEMETRY_BACKFILL_MS = 30 * 24 * 60 * 60 * 1000;
23199
23934
  function resolveTelemetrySince(state, nowMs = Date.now()) {
23200
23935
  if (state.lastTelemetryAt)
@@ -23205,11 +23940,20 @@ async function collectTelemetryEvents(params) {
23205
23940
  const now = params.now ?? new Date().toISOString();
23206
23941
  const events = [];
23207
23942
  const adapterResults = [];
23943
+ const bySlug = new Map(params.adapters.map((a) => [a.slug, a]));
23944
+ const suppressed = suppressedStoreReaders(params.adapters.map((a) => a.slug), (a, b) => {
23945
+ const left = bySlug.get(a);
23946
+ const right = bySlug.get(b);
23947
+ if (!left || !right)
23948
+ return false;
23949
+ return left.readUsageStats !== undefined && left.readUsageStats === right.readUsageStats || left.readSkillUsage !== undefined && left.readSkillUsage === right.readSkillUsage;
23950
+ });
23208
23951
  for (const adapter2 of params.adapters) {
23209
23952
  let stats = "unsupported";
23210
23953
  let skills = "unsupported";
23211
23954
  let error;
23212
- if (adapter2.readUsageStats) {
23955
+ const readsStore = !suppressed.has(adapter2.slug);
23956
+ if (adapter2.readUsageStats && readsStore) {
23213
23957
  try {
23214
23958
  stats = await adapter2.readUsageStats(params.since);
23215
23959
  if (stats && stats.hasNewActivity) {
@@ -23237,7 +23981,7 @@ async function collectTelemetryEvents(params) {
23237
23981
  stats = null;
23238
23982
  }
23239
23983
  }
23240
- if (adapter2.readSkillUsage) {
23984
+ if (adapter2.readSkillUsage && readsStore) {
23241
23985
  try {
23242
23986
  skills = await adapter2.readSkillUsage(params.since);
23243
23987
  if (skills && skills.length > 0) {
@@ -24013,10 +24757,10 @@ function sameStringSet(a, b) {
24013
24757
  }
24014
24758
 
24015
24759
  // src/utils/sync-lock.ts
24016
- import { existsSync as existsSync51, mkdirSync as mkdirSync28, readFileSync as readFileSync40, unlinkSync as unlinkSync8, writeFileSync as writeFileSync30 } from "fs";
24017
- import { join as join47 } from "path";
24018
- import { homedir as homedir26 } from "os";
24019
- var LOCK_PATH = join47(homedir26(), ".runwork", "sync.lock");
24760
+ import { existsSync as existsSync52, mkdirSync as mkdirSync28, readFileSync as readFileSync41, unlinkSync as unlinkSync8, writeFileSync as writeFileSync30 } from "fs";
24761
+ import { join as join48 } from "path";
24762
+ import { homedir as homedir27 } from "os";
24763
+ var LOCK_PATH = join48(homedir27(), ".runwork", "sync.lock");
24020
24764
  var STALE_LOCK_MS = 5 * 60 * 1000;
24021
24765
  var DEFAULT_WAIT_MS = 30000;
24022
24766
  var exitHandlerRegistered = false;
@@ -24036,15 +24780,15 @@ function isProcessAlive(pid) {
24036
24780
  }
24037
24781
  function readLock() {
24038
24782
  try {
24039
- return JSON.parse(readFileSync40(LOCK_PATH, "utf-8"));
24783
+ return JSON.parse(readFileSync41(LOCK_PATH, "utf-8"));
24040
24784
  } catch {
24041
24785
  return null;
24042
24786
  }
24043
24787
  }
24044
24788
  function writeLockExclusive() {
24045
24789
  try {
24046
- if (!existsSync51(join47(homedir26(), ".runwork"))) {
24047
- mkdirSync28(join47(homedir26(), ".runwork"), { recursive: true });
24790
+ if (!existsSync52(join48(homedir27(), ".runwork"))) {
24791
+ mkdirSync28(join48(homedir27(), ".runwork"), { recursive: true });
24048
24792
  }
24049
24793
  writeFileSync30(LOCK_PATH, JSON.stringify({ pid: process.pid, startedAt: Date.now() }), {
24050
24794
  flag: "wx"
@@ -24113,10 +24857,10 @@ Tip: ${hint.title}`);
24113
24857
  } catch {}
24114
24858
  }
24115
24859
  function loadSetupState(filePath) {
24116
- if (!existsSync52(filePath))
24860
+ if (!existsSync53(filePath))
24117
24861
  return null;
24118
24862
  try {
24119
- return JSON.parse(readFileSync41(filePath, "utf-8"));
24863
+ return JSON.parse(readFileSync42(filePath, "utf-8"));
24120
24864
  } catch {
24121
24865
  return null;
24122
24866
  }
@@ -24137,15 +24881,15 @@ function readLocalSkills(state) {
24137
24881
  if (!baseDir)
24138
24882
  continue;
24139
24883
  for (const skillName of state.skills) {
24140
- const skillMdPath = join48(baseDir, skillName, "SKILL.md");
24141
- if (existsSync52(skillMdPath)) {
24142
- results.push({ name: skillName, content: readFileSync41(skillMdPath, "utf-8") });
24884
+ const skillMdPath = join49(baseDir, skillName, "SKILL.md");
24885
+ if (existsSync53(skillMdPath)) {
24886
+ results.push({ name: skillName, content: readFileSync42(skillMdPath, "utf-8") });
24143
24887
  continue;
24144
24888
  }
24145
24889
  const filename = skillName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
24146
- const flatPath = join48(baseDir, `${filename}.md`);
24147
- if (existsSync52(flatPath)) {
24148
- results.push({ name: skillName, content: readFileSync41(flatPath, "utf-8") });
24890
+ const flatPath = join49(baseDir, `${filename}.md`);
24891
+ if (existsSync53(flatPath)) {
24892
+ results.push({ name: skillName, content: readFileSync42(flatPath, "utf-8") });
24149
24893
  }
24150
24894
  }
24151
24895
  if (results.length > 0)
@@ -24399,9 +25143,9 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
24399
25143
  persona: state.persona
24400
25144
  });
24401
25145
  let projectAppSkillFilter = null;
24402
- if (existsSync52(".runwork.json")) {
25146
+ if (existsSync53(".runwork.json")) {
24403
25147
  try {
24404
- const config = JSON.parse(readFileSync41(".runwork.json", "utf-8"));
25148
+ const config = JSON.parse(readFileSync42(".runwork.json", "utf-8"));
24405
25149
  if (config.appName) {
24406
25150
  projectAppSkillFilter = config.appName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
24407
25151
  }
@@ -24670,7 +25414,7 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
24670
25414
  }
24671
25415
  for (const adapter2 of adapters) {
24672
25416
  if (adapter2 instanceof CodexAdapter) {
24673
- const runworkDir = join48(homedir27(), ".runwork");
25417
+ const runworkDir = join49(homedir28(), ".runwork");
24674
25418
  const result = adapter2.registerDesktopWorkspace(runworkDir, "Runwork");
24675
25419
  if (result === "written") {
24676
25420
  vlog(` [${adapter2.name}] Registered workspace in Codex desktop app`);
@@ -24830,8 +25574,8 @@ var syncCommand = new Command26("sync").description("Sync skills bidirectionally
24830
25574
  verbose: !!opts.verbose,
24831
25575
  redetect: !!opts.redetect
24832
25576
  };
24833
- const projectStatePath = join48(process.cwd(), ".runwork", "setup.json");
24834
- const userStatePath = join48(homedir27(), ".runwork", "setup.json");
25577
+ const projectStatePath = join49(process.cwd(), ".runwork", "setup.json");
25578
+ const userStatePath = join49(homedir28(), ".runwork", "setup.json");
24835
25579
  const projectState = loadSetupState(projectStatePath);
24836
25580
  const userState = loadSetupState(userStatePath);
24837
25581
  if (!projectState && !userState) {
@@ -24900,7 +25644,7 @@ function toSkillFilename(name) {
24900
25644
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
24901
25645
  }
24902
25646
  function loadSetupStateForScope(scope) {
24903
- const path4 = scope === "project" ? join49(process.cwd(), ".runwork", "setup.json") : join49(homedir28(), ".runwork", "setup.json");
25647
+ const path4 = scope === "project" ? join50(process.cwd(), ".runwork", "setup.json") : join50(homedir29(), ".runwork", "setup.json");
24904
25648
  return readJsonOrNull(path4);
24905
25649
  }
24906
25650
  async function parkAndTeardownWorkspace(previous, scopes) {
@@ -25069,8 +25813,8 @@ Re-run without --dry-run to sync workspace data.`);
25069
25813
  }
25070
25814
  persistDefaultWorkspace(workspaceId, workspaceName);
25071
25815
  for (const s of scopes) {
25072
- const dir = s === "project" ? ".runwork" : join49(homedir28(), ".runwork");
25073
- writeJsonAtomic(join49(dir, "setup.json"), state);
25816
+ const dir = s === "project" ? ".runwork" : join50(homedir29(), ".runwork");
25817
+ writeJsonAtomic(join50(dir, "setup.json"), state);
25074
25818
  }
25075
25819
  if (restored)
25076
25820
  clearParkedState(workspaceId);
@@ -25078,7 +25822,7 @@ Re-run without --dry-run to sync workspace data.`);
25078
25822
  Syncing workspace data...
25079
25823
  `);
25080
25824
  for (const s of scopes) {
25081
- const statePath2 = s === "project" ? join49(process.cwd(), ".runwork", "setup.json") : join49(homedir28(), ".runwork", "setup.json");
25825
+ const statePath2 = s === "project" ? join50(process.cwd(), ".runwork", "setup.json") : join50(homedir29(), ".runwork", "setup.json");
25082
25826
  await syncFromState(state, statePath2, credentials, {
25083
25827
  dryRun: false,
25084
25828
  pullOnly: true,
@@ -25098,16 +25842,16 @@ init_client();
25098
25842
  import { Command as Command28 } from "commander";
25099
25843
 
25100
25844
  // src/utils/setup-state.ts
25101
- import { existsSync as existsSync53, readFileSync as readFileSync42 } from "fs";
25102
- import { join as join50 } from "path";
25103
- import { homedir as homedir29 } from "os";
25845
+ import { existsSync as existsSync54, readFileSync as readFileSync43 } from "fs";
25846
+ import { join as join51 } from "path";
25847
+ import { homedir as homedir30 } from "os";
25104
25848
  function loadSetupState2() {
25105
- const projectPath = join50(process.cwd(), ".runwork", "setup.json");
25106
- const userPath = join50(homedir29(), ".runwork", "setup.json");
25849
+ const projectPath = join51(process.cwd(), ".runwork", "setup.json");
25850
+ const userPath = join51(homedir30(), ".runwork", "setup.json");
25107
25851
  for (const p of [projectPath, userPath]) {
25108
- if (existsSync53(p)) {
25852
+ if (existsSync54(p)) {
25109
25853
  try {
25110
- return JSON.parse(readFileSync42(p, "utf-8"));
25854
+ return JSON.parse(readFileSync43(p, "utf-8"));
25111
25855
  } catch {
25112
25856
  continue;
25113
25857
  }
@@ -25166,14 +25910,14 @@ init_client();
25166
25910
  init_types();
25167
25911
  await init_detect();
25168
25912
  import { Command as Command29 } from "commander";
25169
- import { existsSync as existsSync54, readFileSync as readFileSync43 } from "fs";
25170
- import { resolve as resolve3, join as join51 } from "path";
25171
- import { homedir as homedir30 } from "os";
25913
+ import { existsSync as existsSync55, readFileSync as readFileSync44 } from "fs";
25914
+ import { resolve as resolve3, join as join52 } from "path";
25915
+ import { homedir as homedir31 } from "os";
25172
25916
  function loadSetupState3(filePath) {
25173
- if (!existsSync54(filePath))
25917
+ if (!existsSync55(filePath))
25174
25918
  return null;
25175
25919
  try {
25176
- return JSON.parse(readFileSync43(filePath, "utf-8"));
25920
+ return JSON.parse(readFileSync44(filePath, "utf-8"));
25177
25921
  } catch {
25178
25922
  return null;
25179
25923
  }
@@ -25189,8 +25933,8 @@ var buildPluginCommand = new Command29("build-plugin").description("Build an ins
25189
25933
  process.exit(1);
25190
25934
  }
25191
25935
  const credentials = requireAuth();
25192
- const projectStatePath = join51(process.cwd(), ".runwork", "setup.json");
25193
- const userStatePath = join51(homedir30(), ".runwork", "setup.json");
25936
+ const projectStatePath = join52(process.cwd(), ".runwork", "setup.json");
25937
+ const userStatePath = join52(homedir31(), ".runwork", "setup.json");
25194
25938
  const state = loadSetupState3(projectStatePath) ?? loadSetupState3(userStatePath);
25195
25939
  if (!state) {
25196
25940
  console.error("No setup state found. Run `runwork setup` first.");
@@ -25283,14 +26027,14 @@ init_prompt();
25283
26027
  init_subprocess();
25284
26028
  await init_detect();
25285
26029
  import { Command as Command30 } from "commander";
25286
- import { existsSync as existsSync55, readFileSync as readFileSync44, writeFileSync as writeFileSync32, readdirSync as readdirSync16, rmSync as rmSync12, unlinkSync as unlinkSync9, lstatSync, readlinkSync } from "fs";
25287
- import { join as join52, resolve as resolve4, relative as relative5, isAbsolute as isAbsolute5 } from "path";
25288
- import { homedir as homedir31 } from "os";
26030
+ import { existsSync as existsSync56, readFileSync as readFileSync45, writeFileSync as writeFileSync32, readdirSync as readdirSync17, rmSync as rmSync12, unlinkSync as unlinkSync9, lstatSync, readlinkSync } from "fs";
26031
+ import { join as join53, resolve as resolve4, relative as relative5, isAbsolute as isAbsolute5 } from "path";
26032
+ import { homedir as homedir32 } from "os";
25289
26033
  function loadSetupState4(filePath) {
25290
- if (!existsSync55(filePath))
26034
+ if (!existsSync56(filePath))
25291
26035
  return null;
25292
26036
  try {
25293
- return JSON.parse(readFileSync44(filePath, "utf-8"));
26037
+ return JSON.parse(readFileSync45(filePath, "utf-8"));
25294
26038
  } catch {
25295
26039
  return null;
25296
26040
  }
@@ -25298,22 +26042,22 @@ function loadSetupState4(filePath) {
25298
26042
  var PRESERVED_ENTRIES = ["bin", "apps", "trash"];
25299
26043
  function removeRunworkState(stateDir, opts) {
25300
26044
  const result = { removed: [], preserved: [], errors: [] };
25301
- if (!existsSync55(stateDir))
26045
+ if (!existsSync56(stateDir))
25302
26046
  return result;
25303
26047
  const preserve = new Set(PRESERVED_ENTRIES);
25304
26048
  if (opts.keepAuth)
25305
26049
  preserve.add(".credentials");
25306
26050
  let entries;
25307
26051
  try {
25308
- entries = readdirSync16(stateDir);
26052
+ entries = readdirSync17(stateDir);
25309
26053
  } catch (err) {
25310
26054
  result.errors.push(`${stateDir}: ${err instanceof Error ? err.message : err}`);
25311
26055
  return result;
25312
26056
  }
25313
26057
  for (const entry of entries) {
25314
- const target = join52(stateDir, entry);
26058
+ const target = join53(stateDir, entry);
25315
26059
  if (preserve.has(entry)) {
25316
- if (existsSync55(target))
26060
+ if (existsSync56(target))
25317
26061
  result.preserved.push(target);
25318
26062
  continue;
25319
26063
  }
@@ -25329,11 +26073,11 @@ function removeRunworkState(stateDir, opts) {
25329
26073
  var SHELL_PROFILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile", ".profile"];
25330
26074
  var BIN_DIR_PATTERN = /\.runwork[\\/]bin/;
25331
26075
  function stripRunworkPathLines(file) {
25332
- if (!existsSync55(file))
26076
+ if (!existsSync56(file))
25333
26077
  return false;
25334
26078
  let content;
25335
26079
  try {
25336
- content = readFileSync44(file, "utf-8");
26080
+ content = readFileSync45(file, "utf-8");
25337
26081
  } catch {
25338
26082
  return false;
25339
26083
  }
@@ -25362,7 +26106,7 @@ function stripRunworkPathLines(file) {
25362
26106
  }
25363
26107
  }
25364
26108
  function cleanShellProfilePathEntries() {
25365
- return SHELL_PROFILES.map((name) => join52(homedir31(), name)).filter(stripRunworkPathLines);
26109
+ return SHELL_PROFILES.map((name) => join53(homedir32(), name)).filter(stripRunworkPathLines);
25366
26110
  }
25367
26111
  function cleanPowerShellProfilePathEntries() {
25368
26112
  if (process.platform !== "win32")
@@ -25402,7 +26146,7 @@ function removeRunworkSymlink(linkPath) {
25402
26146
  } catch {
25403
26147
  return false;
25404
26148
  }
25405
- const ours = resolve4(join52(homedir31(), ".runwork", "bin"));
26149
+ const ours = resolve4(join53(homedir32(), ".runwork", "bin"));
25406
26150
  const rel = relative5(ours, resolve4(target));
25407
26151
  const insideOurs = rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
25408
26152
  if (!insideOurs)
@@ -25415,8 +26159,8 @@ function removeRunworkSymlink(linkPath) {
25415
26159
  }
25416
26160
  }
25417
26161
  var uninstallCommand = new Command30("uninstall").description("Remove all Runwork configuration from local agents (MCP servers, skills, instructions)").option("-y, --yes", "Skip confirmation prompt").option("--keep-auth", "Keep authentication credentials (only remove agent configs)").action(async (opts) => {
25418
- const projectStatePath = join52(process.cwd(), ".runwork", "setup.json");
25419
- const userStatePath = join52(homedir31(), ".runwork", "setup.json");
26162
+ const projectStatePath = join53(process.cwd(), ".runwork", "setup.json");
26163
+ const userStatePath = join53(homedir32(), ".runwork", "setup.json");
25420
26164
  const projectState = loadSetupState4(projectStatePath);
25421
26165
  const userState = loadSetupState4(userStatePath);
25422
26166
  if (!projectState && !userState) {
@@ -25503,8 +26247,8 @@ This will remove all Runwork configuration from your local agents:
25503
26247
  }
25504
26248
  }
25505
26249
  }
25506
- const stateDir = label === "project" ? join52(process.cwd(), ".runwork") : join52(homedir31(), ".runwork");
25507
- if (existsSync55(stateDir)) {
26250
+ const stateDir = label === "project" ? join53(process.cwd(), ".runwork") : join53(homedir32(), ".runwork");
26251
+ if (existsSync56(stateDir)) {
25508
26252
  const outcome = removeRunworkState(stateDir, {
25509
26253
  keepAuth: Boolean(opts.keepAuth) && label === "user"
25510
26254
  });
@@ -25534,7 +26278,7 @@ This will remove all Runwork configuration from your local agents:
25534
26278
  console.log(` - ${file}`);
25535
26279
  }
25536
26280
  const removedLinks = [
25537
- join52(homedir31(), ".local", "bin", "runwork"),
26281
+ join53(homedir32(), ".local", "bin", "runwork"),
25538
26282
  "/usr/local/bin/runwork"
25539
26283
  ].filter(removeRunworkSymlink);
25540
26284
  if (removedLinks.length > 0) {
@@ -25546,7 +26290,7 @@ This will remove all Runwork configuration from your local agents:
25546
26290
  if (process.platform === "win32") {
25547
26291
  console.log("");
25548
26292
  console.log(" Still on your PATH (remove by hand if you want it gone):");
25549
- console.log(` ${join52(homedir31(), ".runwork", "bin")} in your user PATH`);
26293
+ console.log(` ${join53(homedir32(), ".runwork", "bin")} in your user PATH`);
25550
26294
  }
25551
26295
  console.log("");
25552
26296
  if (errors > 0) {
@@ -25672,7 +26416,7 @@ var membersCommand = new Command32("members").description("List workspace member
25672
26416
  init_store();
25673
26417
  init_client();
25674
26418
  import { Command as Command33 } from "commander";
25675
- import { readFileSync as readFileSync45 } from "fs";
26419
+ import { readFileSync as readFileSync46 } from "fs";
25676
26420
  function normalizeApiPath(rawPath, baseUrl) {
25677
26421
  if (/^https?:\/\//i.test(rawPath)) {
25678
26422
  const target = new URL(rawPath);
@@ -25705,7 +26449,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
25705
26449
  let curlStr = opts.curl;
25706
26450
  if (opts.curlFile) {
25707
26451
  try {
25708
- curlStr = readFileSync45(opts.curlFile, "utf-8");
26452
+ curlStr = readFileSync46(opts.curlFile, "utf-8");
25709
26453
  } catch (err) {
25710
26454
  console.error(`Could not read --curl-file: ${err instanceof Error ? err.message : err}`);
25711
26455
  process.exit(1);
@@ -25725,7 +26469,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
25725
26469
  let raw = opts.body;
25726
26470
  if (raw.startsWith("@")) {
25727
26471
  try {
25728
- raw = readFileSync45(raw.slice(1), "utf-8");
26472
+ raw = readFileSync46(raw.slice(1), "utf-8");
25729
26473
  } catch (err) {
25730
26474
  console.error(`Could not read body file: ${err instanceof Error ? err.message : err}`);
25731
26475
  process.exit(1);
@@ -25779,9 +26523,9 @@ init_preflight();
25779
26523
  init_credentials();
25780
26524
  await init_detect();
25781
26525
  import { parse as parse2 } from "smol-toml";
25782
- import { existsSync as existsSync56, readFileSync as readFileSync46 } from "fs";
25783
- import { join as join53, sep as sep4 } from "path";
25784
- import { homedir as homedir32, platform as osPlatform2, arch as osArch } from "os";
26526
+ import { existsSync as existsSync57, readFileSync as readFileSync47 } from "fs";
26527
+ import { join as join54, sep as sep4 } from "path";
26528
+ import { homedir as homedir33, platform as osPlatform2, arch as osArch } from "os";
25785
26529
  var BASE_URL2 = process.env.RUNWORK_DOWNLOAD_BASE_URL || "https://runwork.ai";
25786
26530
  var LATEST_JSON_URL2 = `${BASE_URL2}/cli/latest.json`;
25787
26531
  function detectPlatform() {
@@ -25809,10 +26553,10 @@ function buildContext() {
25809
26553
  const credentials = getCredentials();
25810
26554
  const client = credentials ? new ApiClient(credentials) : null;
25811
26555
  let config = null;
25812
- const configPath = join53(process.cwd(), ".runwork.json");
25813
- if (existsSync56(configPath)) {
26556
+ const configPath = join54(process.cwd(), ".runwork.json");
26557
+ if (existsSync57(configPath)) {
25814
26558
  try {
25815
- config = JSON.parse(readFileSync46(configPath, "utf-8"));
26559
+ config = JSON.parse(readFileSync47(configPath, "utf-8"));
25816
26560
  } catch {}
25817
26561
  }
25818
26562
  return { credentials, client, config, cwd: process.cwd() };
@@ -25866,8 +26610,8 @@ async function checkCliVersion() {
25866
26610
  };
25867
26611
  }
25868
26612
  async function checkCliArtifactReachable() {
25869
- const platform7 = detectPlatform();
25870
- if (!platform7.key) {
26613
+ const platform9 = detectPlatform();
26614
+ if (!platform9.key) {
25871
26615
  return {
25872
26616
  name: "cli-artifact",
25873
26617
  status: "skip",
@@ -25883,12 +26627,12 @@ async function checkCliArtifactReachable() {
25883
26627
  fix: "check network / outbound access to runwork.ai"
25884
26628
  };
25885
26629
  }
25886
- const entry = manifest.artifacts?.[platform7.key];
26630
+ const entry = manifest.artifacts?.[platform9.key];
25887
26631
  if (!entry?.path) {
25888
26632
  return {
25889
26633
  name: "cli-artifact",
25890
26634
  status: "fail",
25891
- message: `manifest has no artifact for ${platform7.key}`
26635
+ message: `manifest has no artifact for ${platform9.key}`
25892
26636
  };
25893
26637
  }
25894
26638
  const artifactUrl = `${BASE_URL2}${entry.path}`;
@@ -25901,7 +26645,7 @@ async function checkCliArtifactReachable() {
25901
26645
  message: `${artifactUrl} returned HTTP ${response.status}`
25902
26646
  };
25903
26647
  }
25904
- return { name: "cli-artifact", status: "pass", message: `${platform7.key} reachable` };
26648
+ return { name: "cli-artifact", status: "pass", message: `${platform9.key} reachable` };
25905
26649
  } catch (err) {
25906
26650
  const msg = err instanceof Error ? err.message : String(err);
25907
26651
  return {
@@ -25913,9 +26657,9 @@ async function checkCliArtifactReachable() {
25913
26657
  }
25914
26658
  async function checkCliInstallLocation() {
25915
26659
  const isWindows2 = osPlatform2() === "win32";
25916
- const home = homedir32();
25917
- const canonicalDir = join53(home, ".runwork", "bin");
25918
- const canonicalBinary = isWindows2 ? join53(canonicalDir, "runwork.exe") : join53(canonicalDir, "runwork");
26660
+ const home2 = homedir33();
26661
+ const canonicalDir = join54(home2, ".runwork", "bin");
26662
+ const canonicalBinary = isWindows2 ? join54(canonicalDir, "runwork.exe") : join54(canonicalDir, "runwork");
25919
26663
  const candidates = [process.execPath, process.argv[1] || ""].filter(Boolean);
25920
26664
  const runsFromCanonical = candidates.some((p) => normalizePath(p) === normalizePath(canonicalBinary));
25921
26665
  if (runsFromCanonical) {
@@ -25925,7 +26669,7 @@ async function checkCliInstallLocation() {
25925
26669
  message: `canonical (${canonicalBinary})`
25926
26670
  };
25927
26671
  }
25928
- if (existsSync56(canonicalBinary)) {
26672
+ if (existsSync57(canonicalBinary)) {
25929
26673
  return {
25930
26674
  name: "cli-install-location",
25931
26675
  status: "warn",
@@ -26058,8 +26802,8 @@ async function checkGitCredentialHelper(ctx) {
26058
26802
  };
26059
26803
  }
26060
26804
  async function checkProjectConfig(ctx) {
26061
- const configPath = join53(ctx.cwd, ".runwork.json");
26062
- if (!existsSync56(configPath)) {
26805
+ const configPath = join54(ctx.cwd, ".runwork.json");
26806
+ if (!existsSync57(configPath)) {
26063
26807
  if (!ctx.credentials) {
26064
26808
  return { name: "project-config", status: "skip", message: "no project (not logged in)" };
26065
26809
  }
@@ -26121,7 +26865,7 @@ async function checkGitRemote(ctx) {
26121
26865
  if (!ctx.config) {
26122
26866
  return { name: "git-remote", status: "skip", message: "skipped (no project)" };
26123
26867
  }
26124
- if (!existsSync56(join53(ctx.cwd, ".git"))) {
26868
+ if (!existsSync57(join54(ctx.cwd, ".git"))) {
26125
26869
  return {
26126
26870
  name: "git-remote",
26127
26871
  status: "fail",
@@ -26175,12 +26919,12 @@ async function checkDeployFreshness(ctx) {
26175
26919
  return { name: "deploy-freshness", status: "skip", message: "local HEAD unknown" };
26176
26920
  }
26177
26921
  function loadSetupState5() {
26178
- const projectPath = join53(process.cwd(), ".runwork", "setup.json");
26179
- const userPath = join53(homedir32(), ".runwork", "setup.json");
26922
+ const projectPath = join54(process.cwd(), ".runwork", "setup.json");
26923
+ const userPath = join54(homedir33(), ".runwork", "setup.json");
26180
26924
  for (const p of [projectPath, userPath]) {
26181
- if (existsSync56(p)) {
26925
+ if (existsSync57(p)) {
26182
26926
  try {
26183
- return JSON.parse(readFileSync46(p, "utf-8"));
26927
+ return JSON.parse(readFileSync47(p, "utf-8"));
26184
26928
  } catch {
26185
26929
  continue;
26186
26930
  }
@@ -26195,13 +26939,13 @@ async function checkCodexNetwork() {
26195
26939
  if (!state || !state.configuredAgents.includes("codex")) {
26196
26940
  return { name, status: "skip", message: "Codex not configured for Runwork" };
26197
26941
  }
26198
- const configPath = join53(homedir32(), ".codex", "config.toml");
26199
- if (!existsSync56(configPath)) {
26942
+ const configPath = join54(homedir33(), ".codex", "config.toml");
26943
+ if (!existsSync57(configPath)) {
26200
26944
  return { name, status: "skip", message: "no Codex config found" };
26201
26945
  }
26202
26946
  let parsed;
26203
26947
  try {
26204
- parsed = parse2(readFileSync46(configPath, "utf-8"));
26948
+ parsed = parse2(readFileSync47(configPath, "utf-8"));
26205
26949
  } catch {
26206
26950
  return { name, status: "warn", message: "could not parse ~/.codex/config.toml" };
26207
26951
  }
@@ -26254,19 +26998,19 @@ async function checkCodexDesktopProject() {
26254
26998
  if (!usesCodex) {
26255
26999
  return { name, status: "skip", message: "Codex not configured for Runwork" };
26256
27000
  }
26257
- const statePath2 = join53(homedir32(), ".codex", ".codex-global-state.json");
26258
- if (!existsSync56(statePath2)) {
27001
+ const statePath2 = join54(homedir33(), ".codex", ".codex-global-state.json");
27002
+ if (!existsSync57(statePath2)) {
26259
27003
  return { name, status: "skip", message: "Codex desktop app not detected" };
26260
27004
  }
26261
27005
  let savedRoots = [];
26262
27006
  try {
26263
- const parsed = JSON.parse(readFileSync46(statePath2, "utf-8"));
27007
+ const parsed = JSON.parse(readFileSync47(statePath2, "utf-8"));
26264
27008
  const roots = parsed["electron-saved-workspace-roots"];
26265
27009
  savedRoots = Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
26266
27010
  } catch {
26267
27011
  return { name, status: "warn", message: "could not read Codex desktop state" };
26268
27012
  }
26269
- const runworkDir = join53(homedir32(), ".runwork");
27013
+ const runworkDir = join54(homedir33(), ".runwork");
26270
27014
  if (savedRoots.includes(runworkDir)) {
26271
27015
  return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
26272
27016
  }
@@ -26320,9 +27064,9 @@ async function checkAgentSetup() {
26320
27064
  if (!adapter2 || !adapter2.supportsMcpScope("user"))
26321
27065
  continue;
26322
27066
  const mcpConfigPath = getMcpConfigPath2(slug, "user");
26323
- if (mcpConfigPath && existsSync56(mcpConfigPath)) {
27067
+ if (mcpConfigPath && existsSync57(mcpConfigPath)) {
26324
27068
  try {
26325
- const content = readFileSync46(mcpConfigPath, "utf-8");
27069
+ const content = readFileSync47(mcpConfigPath, "utf-8");
26326
27070
  const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
26327
27071
  if (missingMcp.length > 0) {
26328
27072
  details.push(`${missingMcp.length} MCP server(s) missing from ${slug} config`);
@@ -26353,8 +27097,8 @@ async function checkAgentSetup() {
26353
27097
  const missingSkills = state.skills.filter((name) => {
26354
27098
  if (isCoveredByMcp(name))
26355
27099
  return false;
26356
- const skillPath = join53(skillsDir, name, "SKILL.md");
26357
- return !existsSync56(skillPath);
27100
+ const skillPath = join54(skillsDir, name, "SKILL.md");
27101
+ return !existsSync57(skillPath);
26358
27102
  });
26359
27103
  if (missingSkills.length > 0) {
26360
27104
  details.push(`${missingSkills.length} skill(s) missing from ${slug}`);
@@ -26384,28 +27128,28 @@ async function checkAgentSetup() {
26384
27128
  };
26385
27129
  }
26386
27130
  function getMcpConfigPath2(slug, scope) {
26387
- const home = homedir32();
27131
+ const home2 = homedir33();
26388
27132
  switch (slug) {
26389
27133
  case "claude-code":
26390
- return scope === "project" ? join53(process.cwd(), ".mcp.json") : join53(home, ".claude", "settings.json");
27134
+ return scope === "project" ? join54(process.cwd(), ".mcp.json") : join54(home2, ".claude", "settings.json");
26391
27135
  case "cursor":
26392
- return scope === "project" ? join53(process.cwd(), ".cursor", "mcp.json") : join53(home, ".cursor", "mcp.json");
27136
+ return scope === "project" ? join54(process.cwd(), ".cursor", "mcp.json") : join54(home2, ".cursor", "mcp.json");
26393
27137
  case "windsurf":
26394
- return scope === "project" ? join53(process.cwd(), ".windsurf", "mcp.json") : join53(home, ".windsurf", "mcp.json");
27138
+ return scope === "project" ? join54(process.cwd(), ".windsurf", "mcp.json") : join54(home2, ".windsurf", "mcp.json");
26395
27139
  case "codex":
26396
27140
  case "codex-app":
26397
- return scope === "user" ? join53(home, ".codex", "config.toml") : null;
27141
+ return scope === "user" ? join54(home2, ".codex", "config.toml") : null;
26398
27142
  case "gemini":
26399
- return scope === "user" ? join53(home, ".gemini", "settings.json") : null;
27143
+ return scope === "user" ? join54(home2, ".gemini", "settings.json") : null;
26400
27144
  default:
26401
27145
  return null;
26402
27146
  }
26403
27147
  }
26404
27148
  async function checkWorkspacePointers() {
26405
- const userStatePath = join53(homedir32(), ".runwork", "setup.json");
26406
- const state = existsSync56(userStatePath) ? (() => {
27149
+ const userStatePath = join54(homedir33(), ".runwork", "setup.json");
27150
+ const state = existsSync57(userStatePath) ? (() => {
26407
27151
  try {
26408
- return JSON.parse(readFileSync46(userStatePath, "utf-8"));
27152
+ return JSON.parse(readFileSync47(userStatePath, "utf-8"));
26409
27153
  } catch {
26410
27154
  return null;
26411
27155
  }
@@ -26435,15 +27179,15 @@ async function checkWorkspacePointers() {
26435
27179
  };
26436
27180
  }
26437
27181
  function getSkillsDir(slug, scope) {
26438
- const home = homedir32();
27182
+ const home2 = homedir33();
26439
27183
  switch (slug) {
26440
27184
  case "claude-code":
26441
- return scope === "project" ? join53(process.cwd(), ".claude", "skills") : join53(home, ".claude", "skills");
27185
+ return scope === "project" ? join54(process.cwd(), ".claude", "skills") : join54(home2, ".claude", "skills");
26442
27186
  case "codex":
26443
27187
  case "codex-app":
26444
- return scope === "project" ? join53(process.cwd(), ".agents", "skills") : join53(home, ".agents", "skills");
27188
+ return scope === "project" ? join54(process.cwd(), ".agents", "skills") : join54(home2, ".agents", "skills");
26445
27189
  case "gemini":
26446
- return scope === "project" ? join53(process.cwd(), ".gemini", "skills") : join53(home, ".gemini", "skills");
27190
+ return scope === "project" ? join54(process.cwd(), ".gemini", "skills") : join54(home2, ".gemini", "skills");
26447
27191
  default:
26448
27192
  return null;
26449
27193
  }
@@ -26496,8 +27240,8 @@ async function runAllChecks(options) {
26496
27240
  // src/health/fix.ts
26497
27241
  init_credentials();
26498
27242
  init_remote();
26499
- import { existsSync as existsSync57 } from "fs";
26500
- import { join as join54 } from "path";
27243
+ import { existsSync as existsSync58 } from "fs";
27244
+ import { join as join55 } from "path";
26501
27245
  async function applyDoctorFixes(ctx, failingNames) {
26502
27246
  const failing = new Set(failingNames);
26503
27247
  const outcomes = [];
@@ -26524,7 +27268,7 @@ async function applyDoctorFixes(ctx, failingNames) {
26524
27268
  applied: false,
26525
27269
  message: "no project config -- run inside an app directory"
26526
27270
  });
26527
- } else if (!existsSync57(join54(ctx.cwd, ".git"))) {
27271
+ } else if (!existsSync58(join55(ctx.cwd, ".git"))) {
26528
27272
  outcomes.push({
26529
27273
  name: "git-remote",
26530
27274
  applied: false,
@@ -26543,10 +27287,10 @@ async function applyDoctorFixes(ctx, failingNames) {
26543
27287
  }
26544
27288
 
26545
27289
  // src/agents/runtime-detection.ts
26546
- import { existsSync as existsSync58, readFileSync as readFileSync47, statSync as statSync11, readdirSync as readdirSync17 } from "fs";
26547
- import { homedir as homedir33 } from "os";
26548
- import { join as join55 } from "path";
26549
- var RUNWORK_SESSIONS_DIR = join55(homedir33(), ".runwork", "sessions");
27290
+ import { existsSync as existsSync59, readFileSync as readFileSync48, statSync as statSync12, readdirSync as readdirSync18 } from "fs";
27291
+ import { homedir as homedir34 } from "os";
27292
+ import { join as join56 } from "path";
27293
+ var RUNWORK_SESSIONS_DIR = join56(homedir34(), ".runwork", "sessions");
26550
27294
  function detectCurrentAgent() {
26551
27295
  const claudeCodeSessionId = process.env.CLAUDE_CODE_SESSION_ID;
26552
27296
  if (claudeCodeSessionId) {
@@ -26609,11 +27353,11 @@ function detectCurrentAgent() {
26609
27353
  return null;
26610
27354
  }
26611
27355
  function readHookSessionInfo(sessionId) {
26612
- const path4 = join55(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
26613
- if (!existsSync58(path4))
27356
+ const path4 = join56(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
27357
+ if (!existsSync59(path4))
26614
27358
  return null;
26615
27359
  try {
26616
- const raw = readFileSync47(path4, "utf8");
27360
+ const raw = readFileSync48(path4, "utf8");
26617
27361
  const parsed = JSON.parse(raw);
26618
27362
  return parsed;
26619
27363
  } catch {
@@ -26621,40 +27365,40 @@ function readHookSessionInfo(sessionId) {
26621
27365
  }
26622
27366
  }
26623
27367
  function findClaudeCodeSessionFile(sessionId) {
26624
- const root = join55(homedir33(), ".claude", "projects");
26625
- if (!existsSync58(root))
27368
+ const root = join56(homedir34(), ".claude", "projects");
27369
+ if (!existsSync59(root))
26626
27370
  return null;
26627
27371
  let projectDirs;
26628
27372
  try {
26629
- projectDirs = readdirSync17(root);
27373
+ projectDirs = readdirSync18(root);
26630
27374
  } catch {
26631
27375
  return null;
26632
27376
  }
26633
27377
  for (const dir of projectDirs) {
26634
- const candidate = join55(root, dir, `${sessionId}.jsonl`);
26635
- if (existsSync58(candidate))
27378
+ const candidate = join56(root, dir, `${sessionId}.jsonl`);
27379
+ if (existsSync59(candidate))
26636
27380
  return candidate;
26637
27381
  }
26638
27382
  return null;
26639
27383
  }
26640
27384
  function findCodexRolloutFile(threadId) {
26641
- const root = join55(homedir33(), ".codex", "sessions");
26642
- if (!existsSync58(root))
27385
+ const root = join56(homedir34(), ".codex", "sessions");
27386
+ if (!existsSync59(root))
26643
27387
  return null;
26644
27388
  const stack = [root];
26645
27389
  while (stack.length > 0) {
26646
27390
  const dir = stack.pop();
26647
27391
  let entries;
26648
27392
  try {
26649
- entries = readdirSync17(dir);
27393
+ entries = readdirSync18(dir);
26650
27394
  } catch {
26651
27395
  continue;
26652
27396
  }
26653
27397
  for (const entry of entries) {
26654
- const full = join55(dir, entry);
27398
+ const full = join56(dir, entry);
26655
27399
  let s;
26656
27400
  try {
26657
- s = statSync11(full);
27401
+ s = statSync12(full);
26658
27402
  } catch {
26659
27403
  continue;
26660
27404
  }
@@ -26668,30 +27412,30 @@ function findCodexRolloutFile(threadId) {
26668
27412
  return null;
26669
27413
  }
26670
27414
  function findNewestClaudeCodeSession() {
26671
- const root = join55(homedir33(), ".claude", "projects");
26672
- if (!existsSync58(root))
27415
+ const root = join56(homedir34(), ".claude", "projects");
27416
+ if (!existsSync59(root))
26673
27417
  return null;
26674
27418
  let projectDirs;
26675
27419
  try {
26676
- projectDirs = readdirSync17(root);
27420
+ projectDirs = readdirSync18(root);
26677
27421
  } catch {
26678
27422
  return null;
26679
27423
  }
26680
27424
  let best = null;
26681
27425
  for (const dir of projectDirs) {
26682
- const projectPath = join55(root, dir);
27426
+ const projectPath = join56(root, dir);
26683
27427
  let files;
26684
27428
  try {
26685
- files = readdirSync17(projectPath);
27429
+ files = readdirSync18(projectPath);
26686
27430
  } catch {
26687
27431
  continue;
26688
27432
  }
26689
27433
  for (const file of files) {
26690
27434
  if (!file.endsWith(".jsonl"))
26691
27435
  continue;
26692
- const full = join55(projectPath, file);
27436
+ const full = join56(projectPath, file);
26693
27437
  try {
26694
- const s = statSync11(full);
27438
+ const s = statSync12(full);
26695
27439
  if (!best || s.mtimeMs > best.mtime) {
26696
27440
  best = {
26697
27441
  sessionId: file.replace(/\.jsonl$/, ""),
@@ -26707,8 +27451,8 @@ function findNewestClaudeCodeSession() {
26707
27451
  return best ? { sessionId: best.sessionId, path: best.path } : null;
26708
27452
  }
26709
27453
  function findNewestCodexRollout() {
26710
- const root = join55(homedir33(), ".codex", "sessions");
26711
- if (!existsSync58(root))
27454
+ const root = join56(homedir34(), ".codex", "sessions");
27455
+ if (!existsSync59(root))
26712
27456
  return null;
26713
27457
  const stack = [root];
26714
27458
  let best = null;
@@ -26716,15 +27460,15 @@ function findNewestCodexRollout() {
26716
27460
  const dir = stack.pop();
26717
27461
  let entries;
26718
27462
  try {
26719
- entries = readdirSync17(dir);
27463
+ entries = readdirSync18(dir);
26720
27464
  } catch {
26721
27465
  continue;
26722
27466
  }
26723
27467
  for (const entry of entries) {
26724
- const full = join55(dir, entry);
27468
+ const full = join56(dir, entry);
26725
27469
  let s;
26726
27470
  try {
26727
- s = statSync11(full);
27471
+ s = statSync12(full);
26728
27472
  } catch {
26729
27473
  continue;
26730
27474
  }
@@ -26951,11 +27695,13 @@ var doctorCommand = new Command34("doctor").description("Check system health: au
26951
27695
  // src/commands/debug.ts
26952
27696
  init_colors();
26953
27697
  import { Command as Command35 } from "commander";
26954
- import { readFileSync as readFileSync48 } from "fs";
26955
- import { homedir as homedir35, platform as platform7, release, arch, type as osType } from "os";
26956
- import { join as join58 } from "path";
27698
+ import { readFileSync as readFileSync49 } from "fs";
27699
+ import { homedir as homedir36, platform as platform9, release, arch, type as osType } from "os";
27700
+ import { join as join59 } from "path";
26957
27701
 
26958
27702
  // src/debug/capture-plan.ts
27703
+ init_transcript_stores();
27704
+ init_registry_data();
26959
27705
  var CONFIG_MAX_BYTES = 64 * 1024;
26960
27706
  var LOG_TAIL_BYTES = 64 * 1024;
26961
27707
  var CENSUS_MAX_ENTRIES = 200;
@@ -26981,9 +27727,9 @@ var ENV_NAMES = [
26981
27727
  ];
26982
27728
  function buildCapturePlan(input) {
26983
27729
  const sep5 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
26984
- const join56 = (...parts) => parts.join(sep5);
26985
- const home = input.homeDir.replace(/[/\\]+$/, "");
26986
- const rw = (...parts) => join56(home, ".runwork", ...parts);
27730
+ const join57 = (...parts) => parts.join(sep5);
27731
+ const home2 = input.homeDir.replace(/[/\\]+$/, "");
27732
+ const rw = (...parts) => join57(home2, ".runwork", ...parts);
26987
27733
  const steps = [];
26988
27734
  steps.push({ id: "env", kind: "env", names: ENV_NAMES, note: "process environment (proxy credentials stripped)" });
26989
27735
  for (const [id, file] of [
@@ -27013,62 +27759,129 @@ function buildCapturePlan(input) {
27013
27759
  ["codex.agents-md", ".codex", "AGENTS.md"],
27014
27760
  ["gemini.settings", ".gemini", "settings.json"]
27015
27761
  ]) {
27016
- steps.push({ id, kind: "file", path: join56(home, ...parts), maxBytes: CONFIG_MAX_BYTES });
27017
- }
27762
+ steps.push({ id, kind: "file", path: join57(home2, ...parts), maxBytes: CONFIG_MAX_BYTES });
27763
+ }
27764
+ steps.push({
27765
+ id: "claude.desktop-config",
27766
+ kind: "file",
27767
+ path: join57(appDataRootFor(input, join57), "Claude", "claude_desktop_config.json"),
27768
+ maxBytes: CONFIG_MAX_BYTES,
27769
+ note: "the MCP config we write for Claude Desktop, next to its session store"
27770
+ });
27771
+ steps.push({
27772
+ id: "codex.version",
27773
+ kind: "file",
27774
+ path: join57(home2, ".codex", "version.json"),
27775
+ maxBytes: 4096,
27776
+ note: "Codex build, for placing an unrecognised originator value"
27777
+ });
27018
27778
  for (const [id, ...parts] of [
27019
27779
  ["claude.skills", ".claude", "skills"],
27020
27780
  ["claude.plugins", ".claude", "plugins"],
27021
27781
  ["agents.skills", ".agents", "skills"],
27022
27782
  ["codex.skills", ".codex", "skills"]
27023
27783
  ]) {
27024
- steps.push({ id, kind: "census", path: join56(home, ...parts), depth: 1, maxEntries: CENSUS_MAX_ENTRIES });
27784
+ steps.push({ id, kind: "census", path: join57(home2, ...parts), depth: 1, maxEntries: CENSUS_MAX_ENTRIES });
27785
+ }
27786
+ for (const store of resolveTranscriptStores({
27787
+ platform: input.platform,
27788
+ homeDir: home2,
27789
+ sep: sep5,
27790
+ appData: input.appData,
27791
+ localAppData: input.localAppData
27792
+ })) {
27793
+ const id = `stores.${store.def.id.replace(/\//g, ".")}`;
27794
+ steps.push(store.def.kind === "file" ? { id, kind: "stat", path: store.path, ...store.def.note ? { note: store.def.note } : {} } : { id, kind: "census", path: store.path, depth: 2, maxEntries: CENSUS_MAX_ENTRIES, ...store.def.note ? { note: store.def.note } : {} });
27795
+ for (const parent of parentsWorthProbing(store.path, sep5)) {
27796
+ steps.push({ id: `${id}.parent`, kind: "census", path: parent, depth: 1, maxEntries: 50, note: "is the vendor directory there at all" });
27797
+ }
27798
+ store.altPaths.forEach((alt, i) => {
27799
+ steps.push({ id: `${id}.alt${i}`, kind: "stat", path: alt, note: "alternate location; a hit means the canonical path is wrong here" });
27800
+ });
27801
+ }
27802
+ if (input.platform === "win32") {
27803
+ steps.push({
27804
+ id: "windows.appx-packages",
27805
+ kind: "census",
27806
+ path: join57(input.localAppData ?? join57(home2, "AppData", "Local"), "Packages"),
27807
+ depth: 1,
27808
+ maxEntries: CENSUS_MAX_ENTRIES,
27809
+ note: "AppX package identities: an MSIX agent can virtualize its writes in here"
27810
+ });
27025
27811
  }
27026
- steps.push({ id: "transcripts.claude-code", kind: "census", path: join56(home, ".claude", "projects"), depth: 1, maxEntries: CENSUS_MAX_ENTRIES }, { id: "transcripts.codex", kind: "census", path: join56(home, ".codex", "sessions"), depth: 2, maxEntries: CENSUS_MAX_ENTRIES }, { id: "transcripts.gemini", kind: "census", path: join56(home, ".gemini", "tmp"), depth: 1, maxEntries: CENSUS_MAX_ENTRIES }, { id: "transcripts.cowork", kind: "census", path: coworkBaseDir(input, join56), depth: 1, maxEntries: CENSUS_MAX_ENTRIES, note: "macOS TCC can refuse this while it still exists" });
27027
27812
  for (const profile of shellProfiles(input.platform)) {
27028
27813
  steps.push({
27029
27814
  id: `shell${profile}`,
27030
27815
  kind: "stat",
27031
- path: join56(home, profile),
27816
+ path: join57(home2, profile),
27032
27817
  note: "presence only: profile bodies can contain the user's own secrets"
27033
27818
  });
27034
27819
  }
27035
27820
  steps.push(...binaryResolutionSteps(input));
27821
+ steps.push(...agentBinaryProbes(input));
27036
27822
  if (input.cliPath) {
27037
- steps.push({ id: "cli.version", kind: "exec", command: input.cliPath, args: ["--version"] }, { id: "cli.doctor", kind: "exec", command: input.cliPath, args: ["--json", "doctor", "-v"] }, { id: "cli.conversations", kind: "exec", command: input.cliPath, args: ["--json", "conversations", "status", "--days", "0"], note: "per-agent scan outcome, no conversation data" });
27823
+ steps.push({ id: "cli.version", kind: "exec", command: input.cliPath, args: ["--version"] }, { id: "cli.doctor", kind: "exec", command: input.cliPath, args: ["--json", "doctor", "-v"] }, { id: "cli.conversations", kind: "exec", command: input.cliPath, args: ["--json", "conversations", "status", "--days", "0"], note: "per-agent scan outcome, no conversation data" }, { id: "cli.stores", kind: "exec", command: input.cliPath, args: ["--json", "conversations", "stores"], note: "per-store contents and provenance, no conversation text" });
27038
27824
  }
27039
27825
  return steps;
27040
27826
  }
27041
- function coworkBaseDir(input, join56) {
27042
- const home = input.homeDir.replace(/[/\\]+$/, "");
27043
- if (input.platform === "darwin") {
27044
- return join56(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions");
27045
- }
27046
- if (input.platform === "win32") {
27047
- const base = input.appData ?? join56(home, "AppData", "Roaming");
27048
- return join56(base, "Claude", "local-agent-mode-sessions");
27827
+ function parentsWorthProbing(storePath4, sep5) {
27828
+ const idx = storePath4.lastIndexOf(sep5);
27829
+ if (idx <= 0)
27830
+ return [];
27831
+ const parent = storePath4.slice(0, idx);
27832
+ const parentIdx = parent.lastIndexOf(sep5);
27833
+ if (parentIdx <= 0)
27834
+ return [];
27835
+ return [parent];
27836
+ }
27837
+ function agentBinaryProbes(input) {
27838
+ const finder = input.platform === "win32" ? "where.exe" : "which";
27839
+ const args = (binary) => input.platform === "win32" ? [binary] : ["-a", binary];
27840
+ const seen = new Set;
27841
+ const steps = [];
27842
+ for (const agent of getDetectableAgents()) {
27843
+ const binary = agent.launch?.cli;
27844
+ if (!binary || seen.has(binary))
27845
+ continue;
27846
+ seen.add(binary);
27847
+ steps.push({
27848
+ id: `agent-binary.${agent.slug}`,
27849
+ kind: "exec",
27850
+ command: finder,
27851
+ args: args(binary),
27852
+ note: `is ${agent.name}'s CLI on PATH, and where`
27853
+ });
27049
27854
  }
27050
- return join56(home, ".config", "Claude", "local-agent-mode-sessions");
27855
+ return steps;
27856
+ }
27857
+ function appDataRootFor(input, join57) {
27858
+ const home2 = input.homeDir.replace(/[/\\]+$/, "");
27859
+ if (input.platform === "darwin")
27860
+ return join57(home2, "Library", "Application Support");
27861
+ if (input.platform === "win32")
27862
+ return input.appData ?? join57(home2, "AppData", "Roaming");
27863
+ return join57(home2, ".config");
27051
27864
  }
27052
- function shellProfiles(platform7) {
27053
- if (platform7 === "win32")
27865
+ function shellProfiles(platform9) {
27866
+ if (platform9 === "win32")
27054
27867
  return [];
27055
27868
  return [".zshrc", ".zprofile", ".bashrc", ".bash_profile", ".profile"];
27056
27869
  }
27057
27870
  function binaryResolutionSteps(input) {
27058
27871
  const sep5 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
27059
- const join56 = (...parts) => parts.join(sep5);
27060
- const home = input.homeDir.replace(/[/\\]+$/, "");
27872
+ const join57 = (...parts) => parts.join(sep5);
27873
+ const home2 = input.homeDir.replace(/[/\\]+$/, "");
27061
27874
  if (input.platform === "win32") {
27062
27875
  return [
27063
27876
  { id: "binaries.where", kind: "exec", command: "where.exe", args: ["runwork"], note: "every match, not just the first" },
27064
- { id: "binaries.runwork-bin", kind: "stat", path: join56(home, ".runwork", "bin", "runwork.exe") },
27877
+ { id: "binaries.runwork-bin", kind: "stat", path: join57(home2, ".runwork", "bin", "runwork.exe") },
27065
27878
  { id: "binaries.user-path", kind: "exec", command: "reg.exe", args: ["query", "HKCU\\Environment", "/v", "Path"], note: "the PATH a NEW shell will inherit, not this one" }
27066
27879
  ];
27067
27880
  }
27068
27881
  return [
27069
27882
  { id: "binaries.which", kind: "exec", command: "which", args: ["-a", "runwork"], note: "every match, not just the first" },
27070
- { id: "binaries.runwork-bin", kind: "stat", path: join56(home, ".runwork", "bin", "runwork") },
27071
- { id: "binaries.local-bin", kind: "stat", path: join56(home, ".local", "bin", "runwork") },
27883
+ { id: "binaries.runwork-bin", kind: "stat", path: join57(home2, ".runwork", "bin", "runwork") },
27884
+ { id: "binaries.local-bin", kind: "stat", path: join57(home2, ".local", "bin", "runwork") },
27072
27885
  ...input.platform === "darwin" ? [{ id: "binaries.usr-local-bin", kind: "stat", path: "/usr/local/bin/runwork" }] : []
27073
27886
  ];
27074
27887
  }
@@ -27284,10 +28097,10 @@ async function runCapture(port, producer, steps, opts = {}) {
27284
28097
  // src/utils/machine-id.ts
27285
28098
  init_atomic_json();
27286
28099
  import { randomUUID } from "crypto";
27287
- import { homedir as homedir34 } from "os";
27288
- import { join as join56 } from "path";
28100
+ import { homedir as homedir35 } from "os";
28101
+ import { join as join57 } from "path";
27289
28102
  function machineIdPath() {
27290
- return join56(homedir34(), ".runwork", "machine.json");
28103
+ return join57(homedir35(), ".runwork", "machine.json");
27291
28104
  }
27292
28105
  function isValidId(value) {
27293
28106
  return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
@@ -27315,8 +28128,8 @@ init_resolve();
27315
28128
  // src/debug/node-port.ts
27316
28129
  init_subprocess();
27317
28130
  init_which();
27318
- import { closeSync as closeSync5, fsyncSync, mkdirSync as mkdirSync29, openSync as openSync5, readSync as readSync3, readdirSync as readdirSync18, statSync as statSync12, writeSync } from "fs";
27319
- import { dirname as dirname12, join as join57 } from "path";
28131
+ import { closeSync as closeSync6, fsyncSync, mkdirSync as mkdirSync29, openSync as openSync6, readSync as readSync4, readdirSync as readdirSync19, statSync as statSync13, writeSync } from "fs";
28132
+ import { dirname as dirname12, join as join58 } from "path";
27320
28133
  var EXEC_OUTPUT_MAX = 256 * 1024;
27321
28134
  var EXEC_TIMEOUT_MS = 20000;
27322
28135
  function truncate5(text2, maxBytes) {
@@ -27324,7 +28137,7 @@ function truncate5(text2, maxBytes) {
27324
28137
  }
27325
28138
  function entryKind(path4) {
27326
28139
  try {
27327
- const s = statSync12(path4);
28140
+ const s = statSync13(path4);
27328
28141
  return s.isDirectory() ? "dir" : s.isFile() ? "file" : "other";
27329
28142
  } catch {
27330
28143
  return "other";
@@ -27332,9 +28145,9 @@ function entryKind(path4) {
27332
28145
  }
27333
28146
  function createNodeCapturePort(outputPath) {
27334
28147
  mkdirSync29(dirname12(outputPath), { recursive: true });
27335
- const fd = openSync5(outputPath, "w");
28148
+ const fd = openSync6(outputPath, "w");
27336
28149
  return {
27337
- close: () => closeSync5(fd),
28150
+ close: () => closeSync6(fd),
27338
28151
  async append(record) {
27339
28152
  writeSync(fd, JSON.stringify(record) + `
27340
28153
  `);
@@ -27350,7 +28163,7 @@ function createNodeCapturePort(outputPath) {
27350
28163
  const { dir, prefix, level } = queue.shift();
27351
28164
  let names;
27352
28165
  try {
27353
- names = readdirSync18(dir);
28166
+ names = readdirSync19(dir);
27354
28167
  } catch (err) {
27355
28168
  if (first)
27356
28169
  throw err;
@@ -27361,12 +28174,12 @@ function createNodeCapturePort(outputPath) {
27361
28174
  for (const name of names) {
27362
28175
  if (out.length >= maxEntries)
27363
28176
  break;
27364
- const full = join57(dir, name);
28177
+ const full = join58(dir, name);
27365
28178
  const kind = entryKind(full);
27366
28179
  let bytes;
27367
28180
  let modifiedAt;
27368
28181
  try {
27369
- const s = statSync12(full);
28182
+ const s = statSync13(full);
27370
28183
  bytes = s.size;
27371
28184
  modifiedAt = new Date(s.mtimeMs).toISOString();
27372
28185
  } catch {}
@@ -27379,7 +28192,7 @@ function createNodeCapturePort(outputPath) {
27379
28192
  return out;
27380
28193
  },
27381
28194
  async stat(path4) {
27382
- const s = statSync12(path4);
28195
+ const s = statSync13(path4);
27383
28196
  return {
27384
28197
  bytes: s.size,
27385
28198
  modifiedAt: new Date(s.mtimeMs).toISOString(),
@@ -27387,16 +28200,16 @@ function createNodeCapturePort(outputPath) {
27387
28200
  };
27388
28201
  },
27389
28202
  async readText(path4, maxBytes, tail) {
27390
- const s = statSync12(path4);
28203
+ const s = statSync13(path4);
27391
28204
  const size = s.size;
27392
28205
  const length = Math.min(size, maxBytes);
27393
28206
  const start = tail && size > maxBytes ? size - maxBytes : 0;
27394
28207
  const buffer = Buffer.alloc(length);
27395
- const handle = openSync5(path4, "r");
28208
+ const handle = openSync6(path4, "r");
27396
28209
  try {
27397
- readSync3(handle, buffer, 0, length, start);
28210
+ readSync4(handle, buffer, 0, length, start);
27398
28211
  } finally {
27399
- closeSync5(handle);
28212
+ closeSync6(handle);
27400
28213
  }
27401
28214
  return { text: buffer.toString("utf-8"), truncated: size > length };
27402
28215
  },
@@ -27429,7 +28242,7 @@ init_which();
27429
28242
  await init_detect();
27430
28243
  function defaultOutputPath(now) {
27431
28244
  const stamp = now.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
27432
- return join58(homedir35(), ".runwork", "debug", `runwork-debug-${stamp}.jsonl`);
28245
+ return join59(homedir36(), ".runwork", "debug", `runwork-debug-${stamp}.jsonl`);
27433
28246
  }
27434
28247
  async function cliClaims() {
27435
28248
  const records = [];
@@ -27442,7 +28255,7 @@ async function cliClaims() {
27442
28255
  execPath: process.execPath,
27443
28256
  argv0: process.argv[1] ?? null,
27444
28257
  nodeVersion: process.version,
27445
- platform: platform7(),
28258
+ platform: platform9(),
27446
28259
  osType: osType(),
27447
28260
  release: release(),
27448
28261
  arch: arch(),
@@ -27482,9 +28295,10 @@ debugCommand.command("capture").description("Collect a diagnostic bundle to a fi
27482
28295
  const outputPath = typeof opts.out === "string" && opts.out ? opts.out : defaultOutputPath(new Date);
27483
28296
  const cliPath = whichBinary("runwork");
27484
28297
  const plan = buildCapturePlan({
27485
- platform: platform7(),
27486
- homeDir: homedir35(),
28298
+ platform: platform9(),
28299
+ homeDir: homedir36(),
27487
28300
  appData: process.env.APPDATA ?? null,
28301
+ localAppData: process.env.LOCALAPPDATA ?? null,
27488
28302
  cliPath
27489
28303
  });
27490
28304
  if (!json) {
@@ -27528,7 +28342,7 @@ Done. ${counted} checks recorded.`));
27528
28342
  });
27529
28343
  async function sendBundle(path4, note) {
27530
28344
  try {
27531
- const content = readFileSync48(path4, "utf-8");
28345
+ const content = readFileSync49(path4, "utf-8");
27532
28346
  const summary = summarizeBundle(content);
27533
28347
  const machineId = getMachineId();
27534
28348
  if (!machineId)
@@ -27547,7 +28361,7 @@ async function sendBundle(path4, note) {
27547
28361
  ...note ? { note } : {},
27548
28362
  context: {
27549
28363
  cliVersion: VERSION,
27550
- platform: platform7(),
28364
+ platform: platform9(),
27551
28365
  release: release(),
27552
28366
  stepsPlanned: summary.stepsPlanned,
27553
28367
  stepsRun: summary.stepsRun,
@@ -27567,8 +28381,8 @@ init_store();
27567
28381
  init_client();
27568
28382
  init_resolve();
27569
28383
  import { Command as Command36 } from "commander";
27570
- import { readFileSync as readFileSync49, writeFileSync as writeFileSync33, existsSync as existsSync59, mkdtempSync as mkdtempSync4 } from "fs";
27571
- import { join as join59 } from "path";
28384
+ import { readFileSync as readFileSync50, writeFileSync as writeFileSync33, existsSync as existsSync60, mkdtempSync as mkdtempSync4 } from "fs";
28385
+ import { join as join60 } from "path";
27572
28386
  import { tmpdir as tmpdir4 } from "os";
27573
28387
  import { createHash as createHash6 } from "crypto";
27574
28388
 
@@ -27690,13 +28504,13 @@ function resolveLocalSessionShare(opts, conversation) {
27690
28504
  process.exit(1);
27691
28505
  }
27692
28506
  const title = opts.title ?? conversation.title ?? conversation.project;
27693
- const markdown = renderTranscriptMarkdown(readFileSync49(conversation.transcriptPath, "utf8"), family, title);
28507
+ const markdown = renderTranscriptMarkdown(readFileSync50(conversation.transcriptPath, "utf8"), family, title);
27694
28508
  if (!markdown) {
27695
28509
  console.error("Error: this conversation has no shareable content.");
27696
28510
  process.exit(1);
27697
28511
  }
27698
- const tempDir = mkdtempSync4(join59(tmpdir4(), "runwork-share-"));
27699
- const transcriptFile = join59(tempDir, "transcript.md");
28512
+ const tempDir = mkdtempSync4(join60(tmpdir4(), "runwork-share-"));
28513
+ const transcriptFile = join60(tempDir, "transcript.md");
27700
28514
  writeFileSync33(transcriptFile, markdown);
27701
28515
  opts.transcriptFile = transcriptFile;
27702
28516
  opts.nativeFile = opts.nativeFile ?? conversation.transcriptPath;
@@ -27734,7 +28548,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
27734
28548
  console.error("Error: --transcript-file is required. Pass the path to the LLM-emitted markdown transcript.");
27735
28549
  process.exit(1);
27736
28550
  }
27737
- if (!existsSync59(opts.transcriptFile)) {
28551
+ if (!existsSync60(opts.transcriptFile)) {
27738
28552
  console.error(`Error: transcript file does not exist: ${opts.transcriptFile}`);
27739
28553
  process.exit(1);
27740
28554
  }
@@ -27755,7 +28569,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
27755
28569
  const credentials = requireAuth();
27756
28570
  const client = new ApiClient(credentials);
27757
28571
  const { workspaceId } = await resolveWorkspace2(client, { workspace: opts.workspace });
27758
- const transcriptContent = readFileSync49(opts.transcriptFile, "utf8");
28572
+ const transcriptContent = readFileSync50(opts.transcriptFile, "utf8");
27759
28573
  const bundles = [
27760
28574
  {
27761
28575
  format: "transcript",
@@ -27768,19 +28582,19 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
27768
28582
  const sourceAgent = opts.sourceAgent ?? detected?.slug ?? "generic";
27769
28583
  let nativeFilePath = null;
27770
28584
  if (opts.nativeFile) {
27771
- if (!existsSync59(opts.nativeFile)) {
28585
+ if (!existsSync60(opts.nativeFile)) {
27772
28586
  console.error(`Error: --native-file path does not exist: ${opts.nativeFile}`);
27773
28587
  process.exit(1);
27774
28588
  }
27775
28589
  nativeFilePath = opts.nativeFile;
27776
- } else if (detected?.sessionFilePath && existsSync59(detected.sessionFilePath)) {
28590
+ } else if (detected?.sessionFilePath && existsSync60(detected.sessionFilePath)) {
27777
28591
  nativeFilePath = detected.sessionFilePath;
27778
28592
  }
27779
28593
  if (nativeFilePath) {
27780
28594
  const nativeFormat = nativeBundleFormatForAgent(sourceAgent);
27781
28595
  if (nativeFormat) {
27782
28596
  try {
27783
- const content = readFileSync49(nativeFilePath, "utf8");
28597
+ const content = readFileSync50(nativeFilePath, "utf8");
27784
28598
  bundles.push({
27785
28599
  format: nativeFormat,
27786
28600
  content,
@@ -27796,7 +28610,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
27796
28610
  let metadata = {};
27797
28611
  if (opts.metadataFile) {
27798
28612
  try {
27799
- metadata = JSON.parse(readFileSync49(opts.metadataFile, "utf8"));
28613
+ metadata = JSON.parse(readFileSync50(opts.metadataFile, "utf8"));
27800
28614
  } catch (err) {
27801
28615
  console.error(`Error: --metadata-file is not valid JSON: ${err instanceof Error ? err.message : err}`);
27802
28616
  process.exit(1);
@@ -27906,8 +28720,8 @@ init_resolve();
27906
28720
  init_registry_data();
27907
28721
  import { Command as Command39 } from "commander";
27908
28722
  import { writeFileSync as writeFileSync34, mkdirSync as mkdirSync30, realpathSync } from "fs";
27909
- import { homedir as homedir36 } from "os";
27910
- import { join as join60 } from "path";
28723
+ import { homedir as homedir37 } from "os";
28724
+ import { join as join61 } from "path";
27911
28725
  import { spawn as spawn5 } from "child_process";
27912
28726
  init_registry();
27913
28727
  init_which();
@@ -27946,9 +28760,9 @@ function extractCodexUuid(rolloutContent) {
27946
28760
  }
27947
28761
  function placeClaudeJsonl(uuid, content, recipientCwd) {
27948
28762
  const encoded = encodeClaudeCodeCwd(recipientCwd);
27949
- const projectDir = join60(homedir36(), ".claude", "projects", encoded);
28763
+ const projectDir = join61(homedir37(), ".claude", "projects", encoded);
27950
28764
  mkdirSync30(projectDir, { recursive: true });
27951
- const placedAt = join60(projectDir, `${uuid}.jsonl`);
28765
+ const placedAt = join61(projectDir, `${uuid}.jsonl`);
27952
28766
  writeFileSync34(placedAt, content);
27953
28767
  return { placedAt, runFromCwd: recipientCwd };
27954
28768
  }
@@ -27957,10 +28771,10 @@ function placeCodexRollout(uuid, content) {
27957
28771
  const yyyy = String(now.getUTCFullYear());
27958
28772
  const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
27959
28773
  const dd = String(now.getUTCDate()).padStart(2, "0");
27960
- const dir = join60(homedir36(), ".codex", "sessions", yyyy, mm, dd);
28774
+ const dir = join61(homedir37(), ".codex", "sessions", yyyy, mm, dd);
27961
28775
  mkdirSync30(dir, { recursive: true });
27962
28776
  const ts = now.toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
27963
- const placedAt = join60(dir, `rollout-${ts}-${uuid}.jsonl`);
28777
+ const placedAt = join61(dir, `rollout-${ts}-${uuid}.jsonl`);
27964
28778
  writeFileSync34(placedAt, content);
27965
28779
  return { placedAt };
27966
28780
  }