runwork 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1273 -882
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -853,6 +853,28 @@ var init_client = __esm(() => {
853
853
  init_http();
854
854
  });
855
855
 
856
+ // src/utils/atomic-json.ts
857
+ import { existsSync, mkdirSync, readFileSync as readFileSync2, renameSync, writeFileSync } from "fs";
858
+ import { dirname } from "path";
859
+ function writeJsonAtomic(path, value, opts = {}) {
860
+ mkdirSync(dirname(path), { recursive: true });
861
+ const json = JSON.stringify(value, null, 2);
862
+ const tmpPath = `${path}.${process.pid}.tmp`;
863
+ writeFileSync(tmpPath, json, opts.mode !== undefined ? { mode: opts.mode } : {});
864
+ renameSync(tmpPath, path);
865
+ }
866
+ function readJsonOrNull(path) {
867
+ if (!existsSync(path))
868
+ return null;
869
+ try {
870
+ const parsed = JSON.parse(readFileSync2(path, "utf-8"));
871
+ return parsed && typeof parsed === "object" ? parsed : null;
872
+ } catch {
873
+ return null;
874
+ }
875
+ }
876
+ var init_atomic_json = () => {};
877
+
856
878
  // src/auth/store.ts
857
879
  var exports_store = {};
858
880
  __export(exports_store, {
@@ -861,7 +883,7 @@ __export(exports_store, {
861
883
  getCredentials: () => getCredentials,
862
884
  clearCredentials: () => clearCredentials
863
885
  });
864
- import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync, unlinkSync } from "fs";
886
+ import { readFileSync as readFileSync3, existsSync as existsSync2, unlinkSync } from "fs";
865
887
  import { join as join2 } from "path";
866
888
  import { homedir } from "os";
867
889
  function getCredentials() {
@@ -880,21 +902,20 @@ function getCredentials() {
880
902
  defaultWorkspaceName: undefined
881
903
  };
882
904
  }
883
- if (!existsSync(CREDENTIALS_FILE))
905
+ if (!existsSync2(CREDENTIALS_FILE))
884
906
  return null;
885
907
  try {
886
- const raw = readFileSync2(CREDENTIALS_FILE, "utf-8");
908
+ const raw = readFileSync3(CREDENTIALS_FILE, "utf-8");
887
909
  return JSON.parse(raw);
888
910
  } catch {
889
911
  return null;
890
912
  }
891
913
  }
892
914
  function saveCredentials(credentials) {
893
- mkdirSync(RUNWORK_DIR, { recursive: true });
894
- writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { mode: 384 });
915
+ writeJsonAtomic(CREDENTIALS_FILE, credentials, { mode: 384 });
895
916
  }
896
917
  function clearCredentials() {
897
- if (existsSync(CREDENTIALS_FILE)) {
918
+ if (existsSync2(CREDENTIALS_FILE)) {
898
919
  unlinkSync(CREDENTIALS_FILE);
899
920
  }
900
921
  }
@@ -917,6 +938,7 @@ function requireAuth() {
917
938
  }
918
939
  var RUNWORK_DIR, CREDENTIALS_FILE;
919
940
  var init_store = __esm(() => {
941
+ init_atomic_json();
920
942
  RUNWORK_DIR = join2(homedir(), ".runwork");
921
943
  CREDENTIALS_FILE = join2(RUNWORK_DIR, ".credentials");
922
944
  });
@@ -934,7 +956,7 @@ var execFileSync = (file, args, options) => {
934
956
  var init_subprocess = () => {};
935
957
 
936
958
  // src/git/credentials.ts
937
- import { existsSync as existsSync2 } from "fs";
959
+ import { existsSync as existsSync3 } from "fs";
938
960
  function buildHelperValue(execPath, scriptPath) {
939
961
  const normalised = execPath.replace(/\\/g, "/");
940
962
  const runtimeName = normalised.split("/").pop()?.toLowerCase() ?? "";
@@ -1015,7 +1037,7 @@ function helperBinaryStatus(value) {
1015
1037
  const helperPath = pathMatch?.[1] ?? pathMatch?.[2] ?? "";
1016
1038
  if (!helperPath)
1017
1039
  return { ok: true, path: null };
1018
- return { ok: existsSync2(helperPath), path: helperPath };
1040
+ return { ok: existsSync3(helperPath), path: helperPath };
1019
1041
  }
1020
1042
  async function ensureGitCredentialHelper(baseUrl) {
1021
1043
  let origin;
@@ -1087,10 +1109,21 @@ var init_credentials = __esm(() => {
1087
1109
  });
1088
1110
 
1089
1111
  // src/auth/login-flow.ts
1090
- async function performLogin(baseUrl) {
1112
+ function decorateLoginUrl(loginUrl, options) {
1113
+ const params = [];
1114
+ if (options?.register)
1115
+ params.push("mode=register");
1116
+ if (options?.provider)
1117
+ params.push(`provider=${encodeURIComponent(options.provider)}`);
1118
+ if (params.length === 0)
1119
+ return loginUrl;
1120
+ return `${loginUrl}${loginUrl.includes("?") ? "&" : "?"}${params.join("&")}`;
1121
+ }
1122
+ async function performLogin(baseUrl, options) {
1091
1123
  const url = baseUrl || DEFAULT_BASE_URL2;
1092
1124
  const client = new ApiClient({ apiKey: "", email: "", baseUrl: url });
1093
- const { sessionId, loginUrl } = await client.initiateLogin();
1125
+ const { sessionId, loginUrl: rawLoginUrl } = await client.initiateLogin();
1126
+ const loginUrl = decorateLoginUrl(rawLoginUrl, options);
1094
1127
  const open = await import("open");
1095
1128
  await open.default(loginUrl);
1096
1129
  console.log(`If browser didn't open, visit: ${loginUrl}`);
@@ -1165,7 +1198,7 @@ function extractBaseUrl(loginUrl) {
1165
1198
  }
1166
1199
  }
1167
1200
  async function pollAndSave(client, sessionId, baseUrl) {
1168
- const maxAttempts = 60;
1201
+ const maxAttempts = 360;
1169
1202
  const pollInterval = 5000;
1170
1203
  for (let i = 0;i < maxAttempts; i++) {
1171
1204
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
@@ -1280,7 +1313,7 @@ var init_identity = __esm(() => {
1280
1313
  });
1281
1314
 
1282
1315
  // src/git/preflight.ts
1283
- import { existsSync as existsSync3 } from "fs";
1316
+ import { existsSync as existsSync4 } from "fs";
1284
1317
  import { win32 as winPath } from "path";
1285
1318
  import { homedir as homedir2 } from "os";
1286
1319
  function tryRun(bin) {
@@ -1302,9 +1335,9 @@ function whereGit() {
1302
1335
  const out = buf.toString("utf-8");
1303
1336
  const lines = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
1304
1337
  const exe = lines.find((line) => /\.exe$/i.test(line));
1305
- if (exe && existsSync3(exe))
1338
+ if (exe && existsSync4(exe))
1306
1339
  return exe;
1307
- const fallback = lines.find((line) => existsSync3(line));
1340
+ const fallback = lines.find((line) => existsSync4(line));
1308
1341
  return fallback ?? null;
1309
1342
  } catch {
1310
1343
  return null;
@@ -1329,7 +1362,7 @@ function registryGit() {
1329
1362
  continue;
1330
1363
  const installRoot = match[1].trim();
1331
1364
  const gitExe = winPath.join(installRoot, "cmd", "git.exe");
1332
- if (existsSync3(gitExe))
1365
+ if (existsSync4(gitExe))
1333
1366
  return gitExe;
1334
1367
  } catch {}
1335
1368
  }
@@ -1397,7 +1430,7 @@ function probeGit() {
1397
1430
  }
1398
1431
  }
1399
1432
  for (const candidate of canonicalGitCandidates()) {
1400
- if (!existsSync3(candidate))
1433
+ if (!existsSync4(candidate))
1401
1434
  continue;
1402
1435
  const verify = tryRun(candidate);
1403
1436
  if (verify.ok) {
@@ -1536,7 +1569,7 @@ async function resolveApp(client, nameOrId, workspaceId) {
1536
1569
  }
1537
1570
 
1538
1571
  // src/utils/ignore-matcher.ts
1539
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
1572
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1540
1573
  import { basename, join as join3 } from "path";
1541
1574
  function defaultIgnoreSets() {
1542
1575
  return {
@@ -1578,10 +1611,10 @@ function parseGitignoreContent(content) {
1578
1611
  }
1579
1612
  function loadGitignoreFromDir(dir) {
1580
1613
  const path = join3(dir, ".gitignore");
1581
- if (!existsSync4(path))
1614
+ if (!existsSync5(path))
1582
1615
  return { dirs: new Set, files: new Set };
1583
1616
  try {
1584
- return parseGitignoreContent(readFileSync3(path, "utf-8"));
1617
+ return parseGitignoreContent(readFileSync4(path, "utf-8"));
1585
1618
  } catch {
1586
1619
  return { dirs: new Set, files: new Set };
1587
1620
  }
@@ -1637,7 +1670,7 @@ var init_ignore_matcher = __esm(() => {
1637
1670
 
1638
1671
  // src/template/manifest.ts
1639
1672
  import { createHash } from "crypto";
1640
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2 } from "fs";
1673
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync6, readdirSync, mkdirSync as mkdirSync2 } from "fs";
1641
1674
  import { join as join4, relative, sep } from "path";
1642
1675
  function sha256(data) {
1643
1676
  return "sha256:" + createHash("sha256").update(data).digest("hex");
@@ -1669,24 +1702,24 @@ async function generateManifest(dir) {
1669
1702
  const sets = buildIgnoreSets(dir);
1670
1703
  const allFiles = walkDir(dir, dir, sets);
1671
1704
  for (const relPath of allFiles) {
1672
- const content = readFileSync4(join4(dir, relPath));
1705
+ const content = readFileSync5(join4(dir, relPath));
1673
1706
  files[relPath] = sha256(content);
1674
1707
  }
1675
1708
  return { version: 1, files };
1676
1709
  }
1677
1710
  async function saveManifest(dir, manifest) {
1678
1711
  const manifestDir = join4(dir, ".runwork");
1679
- if (!existsSync5(manifestDir)) {
1712
+ if (!existsSync6(manifestDir)) {
1680
1713
  mkdirSync2(manifestDir, { recursive: true });
1681
1714
  }
1682
1715
  writeFileSync2(join4(manifestDir, "template-manifest.json"), JSON.stringify(manifest, null, 2));
1683
1716
  }
1684
1717
  async function loadManifest(dir) {
1685
1718
  const manifestPath = join4(dir, ".runwork", "template-manifest.json");
1686
- if (!existsSync5(manifestPath))
1719
+ if (!existsSync6(manifestPath))
1687
1720
  return null;
1688
1721
  try {
1689
- const manifest = JSON.parse(readFileSync4(manifestPath, "utf-8"));
1722
+ const manifest = JSON.parse(readFileSync5(manifestPath, "utf-8"));
1690
1723
  const files = {};
1691
1724
  for (const [relPath, hash] of Object.entries(manifest.files)) {
1692
1725
  files[relPath.split("\\").join("/")] = hash;
@@ -1719,7 +1752,7 @@ async function detectUserEdits(dir, manifest) {
1719
1752
  continue;
1720
1753
  const expectedHash = manifest.files[relPath];
1721
1754
  if (expectedHash) {
1722
- const content = readFileSync4(join4(dir, relPath));
1755
+ const content = readFileSync5(join4(dir, relPath));
1723
1756
  if (sha256(content) === expectedHash)
1724
1757
  continue;
1725
1758
  }
@@ -1743,7 +1776,7 @@ async function detectUserEdits(dir, manifest) {
1743
1776
  continue;
1744
1777
  const filePath = join4(dir, relPath);
1745
1778
  try {
1746
- const content = readFileSync4(filePath);
1779
+ const content = readFileSync5(filePath);
1747
1780
  if (sha256(content) !== expectedHash) {
1748
1781
  edits.push(relPath);
1749
1782
  }
@@ -1757,8 +1790,8 @@ var init_manifest = __esm(() => {
1757
1790
  });
1758
1791
 
1759
1792
  // src/utils/zip.ts
1760
- import { mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync3 } from "fs";
1761
- import { join as join5, dirname, relative as relative2, sep as sep2 } from "path";
1793
+ import { mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync, writeFileSync as writeFileSync3 } from "fs";
1794
+ import { join as join5, dirname as dirname2, relative as relative2, sep as sep2 } from "path";
1762
1795
  import { unzipSync, zipSync } from "fflate";
1763
1796
  function ensureDirSync(dir) {
1764
1797
  try {
@@ -1776,7 +1809,7 @@ function extractZip(zipData, targetDir) {
1776
1809
  ensureDirSync(fullPath);
1777
1810
  continue;
1778
1811
  }
1779
- ensureDirSync(dirname(fullPath));
1812
+ ensureDirSync(dirname2(fullPath));
1780
1813
  writeFileSync3(fullPath, data);
1781
1814
  }
1782
1815
  }
@@ -1790,13 +1823,13 @@ function createZipFromDir(sourceDir, outputPath) {
1790
1823
  walk(absPath);
1791
1824
  } else if (stats.isFile()) {
1792
1825
  const relPath = relative2(sourceDir, absPath).split(sep2).join("/");
1793
- files[relPath] = readFileSync5(absPath);
1826
+ files[relPath] = readFileSync6(absPath);
1794
1827
  }
1795
1828
  }
1796
1829
  };
1797
1830
  walk(sourceDir);
1798
1831
  const zipped = zipSync(files);
1799
- ensureDirSync(dirname(outputPath));
1832
+ ensureDirSync(dirname2(outputPath));
1800
1833
  writeFileSync3(outputPath, zipped);
1801
1834
  }
1802
1835
  var init_zip = () => {};
@@ -2092,18 +2125,18 @@ __export(exports_init, {
2092
2125
  DEFAULT_APPS_DIR: () => DEFAULT_APPS_DIR
2093
2126
  });
2094
2127
  import { Command as Command2 } from "commander";
2095
- import { writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
2128
+ import { writeFileSync as writeFileSync4, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
2096
2129
  import { join as join7, resolve } from "path";
2097
2130
  import { homedir as homedir4 } from "os";
2098
2131
  async function execInit(client, appName, workspace, options = {}, creds) {
2099
2132
  const app = await client.initApp(workspace.id, appName);
2100
2133
  const slug = app.slug || appName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2101
2134
  const parentDir = options.here ? process.cwd() : DEFAULT_APPS_DIR;
2102
- if (!options.here && !existsSync6(parentDir)) {
2135
+ if (!options.here && !existsSync7(parentDir)) {
2103
2136
  mkdirSync4(parentDir, { recursive: true });
2104
2137
  }
2105
2138
  const dir = join7(parentDir, slug);
2106
- if (existsSync6(dir)) {
2139
+ if (existsSync7(dir)) {
2107
2140
  console.error(`Directory "${dir}" already exists.`);
2108
2141
  process.exit(1);
2109
2142
  }
@@ -2130,7 +2163,7 @@ async function execInit(client, appName, workspace, options = {}, creds) {
2130
2163
  appName: app.name
2131
2164
  };
2132
2165
  writeFileSync4(join7(dir, ".runwork.json"), JSON.stringify(config, null, 2));
2133
- if (!existsSync6(join7(dir, ".git"))) {
2166
+ if (!existsSync7(join7(dir, ".git"))) {
2134
2167
  try {
2135
2168
  execFileSync("git", ["init"], { cwd: dir, stdio: "pipe" });
2136
2169
  } catch (err) {
@@ -2148,7 +2181,7 @@ async function execInit(client, appName, workspace, options = {}, creds) {
2148
2181
  } catch {
2149
2182
  execFileSync("git", ["remote", "set-url", "runwork", remoteUrl], { cwd: dir, stdio: "pipe" });
2150
2183
  }
2151
- if (!existsSync6(join7(dir, ".gitignore"))) {
2184
+ if (!existsSync7(join7(dir, ".gitignore"))) {
2152
2185
  writeFileSync4(join7(dir, ".gitignore"), `node_modules/
2153
2186
  .runwork/
2154
2187
  .dev.vars
@@ -2401,7 +2434,7 @@ __export(exports_clone, {
2401
2434
  RESTRICTED_FS_HELP: () => RESTRICTED_FS_HELP
2402
2435
  });
2403
2436
  import { Command as Command3 } from "commander";
2404
- import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync7 } from "fs";
2437
+ import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync8 } from "fs";
2405
2438
  import { join as join8, resolve as resolve2 } from "path";
2406
2439
  async function execClone(client, app, directory, creds) {
2407
2440
  const slug = app.slug || app.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -2419,7 +2452,7 @@ async function execClone(client, app, directory, creds) {
2419
2452
  }
2420
2453
  const manifest = await generateManifest(dir);
2421
2454
  await saveManifest(dir, manifest);
2422
- if (!existsSync7(join8(dir, ".git"))) {
2455
+ if (!existsSync8(join8(dir, ".git"))) {
2423
2456
  try {
2424
2457
  execFileSync("git", ["init"], { cwd: dir, stdio: "pipe" });
2425
2458
  } catch (err) {
@@ -2592,7 +2625,7 @@ App "${cloneResult.appName}" cloned to ${cloneResult.directory}`);
2592
2625
  });
2593
2626
 
2594
2627
  // src/git/auto-commit.ts
2595
- import { readFileSync as readFileSync6 } from "fs";
2628
+ import { readFileSync as readFileSync7 } from "fs";
2596
2629
  import { watch } from "chokidar";
2597
2630
  import { join as join9, relative as relative4 } from "path";
2598
2631
  async function watchAndAutoCommit(directory, client, appId, callbacks) {
@@ -2654,7 +2687,7 @@ async function executeFastSync(directory, client, appId) {
2654
2687
  if (BINARY_EXTENSIONS.has(ext.toLowerCase()))
2655
2688
  continue;
2656
2689
  try {
2657
- const contents = readFileSync6(join9(directory, filePath), "utf-8");
2690
+ const contents = readFileSync7(join9(directory, filePath), "utf-8");
2658
2691
  files.push({ filePath, fileContents: contents });
2659
2692
  } catch {}
2660
2693
  }
@@ -2948,16 +2981,16 @@ var init_sync = __esm(() => {
2948
2981
  });
2949
2982
 
2950
2983
  // src/git/critical-files.ts
2951
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "fs";
2984
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
2952
2985
  import { join as join11 } from "path";
2953
2986
  function snapshotCriticalFiles(cwd) {
2954
2987
  const snapshots = [];
2955
2988
  for (const rel of CRITICAL_FILES) {
2956
2989
  const abs = join11(cwd, rel);
2957
- if (!existsSync8(abs))
2990
+ if (!existsSync9(abs))
2958
2991
  continue;
2959
2992
  try {
2960
- snapshots.push({ path: rel, contents: readFileSync7(abs, "utf-8") });
2993
+ snapshots.push({ path: rel, contents: readFileSync8(abs, "utf-8") });
2961
2994
  } catch {}
2962
2995
  }
2963
2996
  return snapshots;
@@ -2966,7 +2999,7 @@ function restoreMissingCriticalFiles(cwd, snapshots) {
2966
2999
  const restored = [];
2967
3000
  for (const snap of snapshots) {
2968
3001
  const abs = join11(cwd, snap.path);
2969
- if (existsSync8(abs))
3002
+ if (existsSync9(abs))
2970
3003
  continue;
2971
3004
  try {
2972
3005
  writeFileSync6(abs, snap.contents, "utf-8");
@@ -3009,7 +3042,7 @@ function buildStartupSyncSummary(input) {
3009
3042
 
3010
3043
  // src/logs/tailer.ts
3011
3044
  import { appendFileSync, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
3012
- import { join as join12, dirname as dirname2 } from "path";
3045
+ import { join as join12, dirname as dirname3 } from "path";
3013
3046
  function formatTime() {
3014
3047
  const now = new Date;
3015
3048
  return [
@@ -3059,7 +3092,7 @@ function startLogTailer(options) {
3059
3092
  } = options;
3060
3093
  const logFilePath = join12(projectDir, LOG_FILE);
3061
3094
  if (toFile) {
3062
- mkdirSync6(dirname2(logFilePath), { recursive: true });
3095
+ mkdirSync6(dirname3(logFilePath), { recursive: true });
3063
3096
  writeFileSync7(logFilePath, `# Runwork dev logs - started ${new Date().toISOString()}
3064
3097
 
3065
3098
  `, "utf-8");
@@ -7469,13 +7502,13 @@ export {};
7469
7502
  });
7470
7503
 
7471
7504
  // src/types-manager.ts
7472
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync4, copyFileSync, writeFileSync as writeFileSync9 } from "fs";
7505
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync4, copyFileSync, writeFileSync as writeFileSync9 } from "fs";
7473
7506
  import { join as join14 } from "path";
7474
7507
  async function populateTypes(projectDir) {
7475
7508
  const typesDir = join14(projectDir, TYPES_DIR);
7476
7509
  mkdirSync9(typesDir, { recursive: true });
7477
7510
  const frameworkDist = join14(projectDir, "node_modules/@runworkai/framework/dist");
7478
- if (existsSync13(frameworkDist)) {
7511
+ if (existsSync14(frameworkDist)) {
7479
7512
  copyDtsFiles(frameworkDist, typesDir);
7480
7513
  console.log("Types populated from node_modules/@runworkai/framework");
7481
7514
  return;
@@ -7612,7 +7645,7 @@ function createKeyboardListener() {
7612
7645
  }
7613
7646
 
7614
7647
  // src/generated/version.ts
7615
- var VERSION = "0.19.0";
7648
+ var VERSION = "0.20.0";
7616
7649
 
7617
7650
  // src/commands/dev.ts
7618
7651
  var exports_dev = {};
@@ -7621,7 +7654,7 @@ __export(exports_dev, {
7621
7654
  devCommand: () => devCommand
7622
7655
  });
7623
7656
  import { Command as Command4, Option } from "commander";
7624
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync10, existsSync as existsSync14 } from "fs";
7657
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, existsSync as existsSync15 } from "fs";
7625
7658
  import { join as join15 } from "path";
7626
7659
  async function populateSkill(projectDir, client, appId) {
7627
7660
  try {
@@ -7632,11 +7665,11 @@ async function populateSkill(projectDir, client, appId) {
7632
7665
  } catch {}
7633
7666
  }
7634
7667
  function readConfig() {
7635
- if (!existsSync14(".runwork.json")) {
7668
+ if (!existsSync15(".runwork.json")) {
7636
7669
  console.error("No .runwork.json found. Run `runwork init` first.");
7637
7670
  process.exit(1);
7638
7671
  }
7639
- return JSON.parse(readFileSync11(".runwork.json", "utf-8"));
7672
+ return JSON.parse(readFileSync12(".runwork.json", "utf-8"));
7640
7673
  }
7641
7674
  async function execDev(options) {
7642
7675
  const useJson = options?.json ?? false;
@@ -8516,7 +8549,7 @@ var exports_welcome = {};
8516
8549
  __export(exports_welcome, {
8517
8550
  runWelcomeWizard: () => runWelcomeWizard
8518
8551
  });
8519
- import { basename as basename3 } from "path";
8552
+ import { basename as basename4 } from "path";
8520
8553
  async function runWelcomeWizard() {
8521
8554
  console.log(getWelcomeBanner());
8522
8555
  let creds = getCredentials();
@@ -8582,7 +8615,7 @@ async function runWelcomeWizard() {
8582
8615
  const { execDev: execDev2 } = await Promise.resolve().then(() => (init_dev(), exports_dev));
8583
8616
  await execDev2();
8584
8617
  } else {
8585
- const slug = basename3(appDir) || appDir;
8618
+ const slug = basename4(appDir) || appDir;
8586
8619
  console.log("");
8587
8620
  console.log(`Next: ${cyan(`cd ${slug} && runwork dev`)}`);
8588
8621
  }
@@ -8597,13 +8630,13 @@ var init_welcome = __esm(() => {
8597
8630
  });
8598
8631
 
8599
8632
  // src/index.ts
8600
- import { Command as Command36 } from "commander";
8633
+ import { Command as Command37 } from "commander";
8601
8634
 
8602
8635
  // src/commands/login.ts
8603
8636
  init_login_flow();
8604
8637
  init_colors();
8605
8638
  import { Command } from "commander";
8606
- var loginCommand = new Command("login").description("Authenticate with Runwork platform").argument("[url]", "Login URL from a previous --no-open session").option("--base-url <url>", "Platform URL", "https://runwork.ai").option("--no-open", "Print login URL without opening browser (polls for completion)").option("--print-only", "With --no-open: print URL and exit without polling").option("--api-key <key>", "Authenticate directly with an API key (for CI)").action(async (url, options) => {
8639
+ var loginCommand = new Command("login").description("Authenticate with Runwork platform").argument("[url]", "Login URL from a previous --no-open session").option("--base-url <url>", "Platform URL", "https://runwork.ai").option("--no-open", "Print login URL without opening browser (polls for completion)").option("--print-only", "With --no-open: print URL and exit without polling").option("--api-key <key>", "Authenticate directly with an API key (for CI)").option("--register", "Open the browser on the registration form for a new account").option("--provider <provider>", "Start this OAuth provider flow directly (google, github)").action(async (url, options) => {
8607
8640
  if (!options)
8608
8641
  return;
8609
8642
  if (options.apiKey) {
@@ -8621,7 +8654,7 @@ var loginCommand = new Command("login").description("Authenticate with Runwork p
8621
8654
  printNextSteps();
8622
8655
  return;
8623
8656
  }
8624
- await performLogin(options.baseUrl);
8657
+ await performLogin(options.baseUrl, { register: options.register, provider: options.provider });
8625
8658
  printNextSteps();
8626
8659
  });
8627
8660
  function printNextSteps() {
@@ -8644,12 +8677,12 @@ init_store();
8644
8677
  init_client();
8645
8678
  init_colors();
8646
8679
  import { Command as Command5, Option as Option2 } from "commander";
8647
- import { readFileSync as readFileSync14, existsSync as existsSync17 } from "fs";
8680
+ import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
8648
8681
 
8649
8682
  // src/deploy/deploy-state.ts
8650
8683
  init_subprocess();
8651
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync12, writeFileSync as writeFileSync11 } from "fs";
8652
- import { dirname as dirname3, join as join16 } from "path";
8684
+ import { existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "fs";
8685
+ import { dirname as dirname4, join as join16 } from "path";
8653
8686
  function deployStatePath(cwd) {
8654
8687
  return join16(cwd, ".runwork", "last-deploy.json");
8655
8688
  }
@@ -8663,17 +8696,17 @@ function getHeadSha(cwd) {
8663
8696
  function writeDeployState(cwd, state) {
8664
8697
  const path2 = deployStatePath(cwd);
8665
8698
  try {
8666
- if (!existsSync15(dirname3(path2)))
8667
- mkdirSync10(dirname3(path2), { recursive: true });
8699
+ if (!existsSync16(dirname4(path2)))
8700
+ mkdirSync10(dirname4(path2), { recursive: true });
8668
8701
  writeFileSync11(path2, JSON.stringify(state, null, 2));
8669
8702
  } catch {}
8670
8703
  }
8671
8704
  function readDeployState(cwd) {
8672
8705
  const path2 = deployStatePath(cwd);
8673
- if (!existsSync15(path2))
8706
+ if (!existsSync16(path2))
8674
8707
  return null;
8675
8708
  try {
8676
- const parsed = JSON.parse(readFileSync12(path2, "utf-8"));
8709
+ const parsed = JSON.parse(readFileSync13(path2, "utf-8"));
8677
8710
  if (typeof parsed.sha === "string" && typeof parsed.deployedAt === "string") {
8678
8711
  return { sha: parsed.sha, deployedAt: parsed.deployedAt, url: parsed.url ?? "" };
8679
8712
  }
@@ -8701,8 +8734,8 @@ function getDeploySummary(cwd) {
8701
8734
 
8702
8735
  // src/deploy/deploy-status.ts
8703
8736
  init_session();
8704
- import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
8705
- import { dirname as dirname4, join as join17 } from "path";
8737
+ import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
8738
+ import { dirname as dirname5, join as join17 } from "path";
8706
8739
  function evaluateDeployStatus(status, deps = {}) {
8707
8740
  if (status.state !== "in-progress") {
8708
8741
  return { status, effectiveState: status.state };
@@ -8726,17 +8759,17 @@ function deployLogPath(cwd) {
8726
8759
  function writeDeployStatus(cwd, status) {
8727
8760
  const path2 = statusPath(cwd);
8728
8761
  try {
8729
- if (!existsSync16(dirname4(path2)))
8730
- mkdirSync11(dirname4(path2), { recursive: true });
8762
+ if (!existsSync17(dirname5(path2)))
8763
+ mkdirSync11(dirname5(path2), { recursive: true });
8731
8764
  writeFileSync12(path2, JSON.stringify(status, null, 2));
8732
8765
  } catch {}
8733
8766
  }
8734
8767
  function readDeployStatus(cwd) {
8735
8768
  const path2 = statusPath(cwd);
8736
- if (!existsSync16(path2))
8769
+ if (!existsSync17(path2))
8737
8770
  return null;
8738
8771
  try {
8739
- const parsed = JSON.parse(readFileSync13(path2, "utf-8"));
8772
+ const parsed = JSON.parse(readFileSync14(path2, "utf-8"));
8740
8773
  if ((parsed.state === "in-progress" || parsed.state === "succeeded" || parsed.state === "failed") && typeof parsed.startedAt === "string") {
8741
8774
  return parsed;
8742
8775
  }
@@ -8842,7 +8875,7 @@ init_prompt();
8842
8875
  var deployCommand = new Command5("deploy").description("Deploy the current app to production").option("-y, --yes", "Skip the confirmation prompt when the working tree differs from the preview").option("--detach", "Run the deploy in the background and return immediately. Logs go to .runwork/deploy-{stdout,stderr}.log; poll `runwork deploy --status`.").option("--status", "Show the status (in-progress/succeeded/failed) of the last deploy started from this machine, plus the deployed-vs-local commit.").addOption(new Option2(DEPLOY_DETACHED_CHILD_FLAG).hideHelp()).action(async (opts, command) => {
8843
8876
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
8844
8877
  const cwd = process.cwd();
8845
- if (!existsSync17(".runwork.json")) {
8878
+ if (!existsSync18(".runwork.json")) {
8846
8879
  if (useJson) {
8847
8880
  jsonOut(buildErrorResponse("deploy", "No .runwork.json found", "This directory is not a Runwork app.", ["Run runwork init to create an app first", "Or cd into an existing app directory"]));
8848
8881
  process.exit(1);
@@ -8855,7 +8888,7 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
8855
8888
  return;
8856
8889
  }
8857
8890
  requireGit("deploy");
8858
- const config = JSON.parse(readFileSync14(".runwork.json", "utf-8"));
8891
+ const config = JSON.parse(readFileSync15(".runwork.json", "utf-8"));
8859
8892
  const isChild = isInternalDeployChild(process.argv);
8860
8893
  if (opts.detach && !isChild) {
8861
8894
  const startedAt = new Date().toISOString();
@@ -9068,7 +9101,7 @@ init_client();
9068
9101
  init_colors();
9069
9102
  init_preflight();
9070
9103
  import { Command as Command6 } from "commander";
9071
- import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
9104
+ import { readFileSync as readFileSync16, existsSync as existsSync19 } from "fs";
9072
9105
 
9073
9106
  // src/validate/freshness.ts
9074
9107
  init_subprocess();
@@ -9140,7 +9173,7 @@ var BUILD_FOLLOWUP = "In-sandbox typecheck/lint requires a worker exec endpoint
9140
9173
  var validateCommand = new Command6("validate").description("Validate the app before deploy: git sync state + preview liveness (no local deps needed)").action(async (_opts, command) => {
9141
9174
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
9142
9175
  const cwd = process.cwd();
9143
- if (!existsSync18(".runwork.json")) {
9176
+ if (!existsSync19(".runwork.json")) {
9144
9177
  if (useJson) {
9145
9178
  jsonOut({ success: false, command: "validate", error: "No .runwork.json found. Run inside a Runwork app." });
9146
9179
  process.exit(1);
@@ -9149,7 +9182,7 @@ var validateCommand = new Command6("validate").description("Validate the app bef
9149
9182
  process.exit(1);
9150
9183
  }
9151
9184
  requireGit("validate");
9152
- const config = JSON.parse(readFileSync15(".runwork.json", "utf-8"));
9185
+ const config = JSON.parse(readFileSync16(".runwork.json", "utf-8"));
9153
9186
  const creds = requireAuth();
9154
9187
  const client = new ApiClient(creds);
9155
9188
  const sync = getGitFreshness(cwd);
@@ -9205,13 +9238,13 @@ var validateCommand = new Command6("validate").description("Validate the app bef
9205
9238
  init_store();
9206
9239
  init_client();
9207
9240
  import { Command as Command7 } from "commander";
9208
- import { readFileSync as readFileSync16, existsSync as existsSync19 } from "fs";
9241
+ import { readFileSync as readFileSync17, existsSync as existsSync20 } from "fs";
9209
9242
  function readConfig2() {
9210
- if (!existsSync19(".runwork.json")) {
9243
+ if (!existsSync20(".runwork.json")) {
9211
9244
  console.error("No .runwork.json found. Run `runwork init` first.");
9212
9245
  process.exit(1);
9213
9246
  }
9214
- return JSON.parse(readFileSync16(".runwork.json", "utf-8"));
9247
+ return JSON.parse(readFileSync17(".runwork.json", "utf-8"));
9215
9248
  }
9216
9249
  function formatEvent(event) {
9217
9250
  const time = new Date(event.timestamp).toLocaleTimeString();
@@ -9632,12 +9665,12 @@ var logoutCommand = new Command9("logout").description("Remove stored Runwork cr
9632
9665
  init_store();
9633
9666
  init_client();
9634
9667
  import { Command as Command10 } from "commander";
9635
- import { readFileSync as readFileSync18, existsSync as existsSync21 } from "fs";
9668
+ import { readFileSync as readFileSync19, existsSync as existsSync22 } from "fs";
9636
9669
 
9637
9670
  // src/workspace/resolve.ts
9638
9671
  init_store();
9639
9672
  init_prompt();
9640
- import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
9673
+ import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
9641
9674
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9642
9675
  async function resolveWorkspace2(client, options = {}) {
9643
9676
  if (options.workspace) {
@@ -9650,9 +9683,9 @@ async function resolveWorkspace2(client, options = {}) {
9650
9683
  if (process.env.WORKSPACE_ID) {
9651
9684
  return { workspaceId: process.env.WORKSPACE_ID, workspaceName: "", source: "flag" };
9652
9685
  }
9653
- if (existsSync20(".runwork.json")) {
9686
+ if (existsSync21(".runwork.json")) {
9654
9687
  try {
9655
- const config = JSON.parse(readFileSync17(".runwork.json", "utf-8"));
9688
+ const config = JSON.parse(readFileSync18(".runwork.json", "utf-8"));
9656
9689
  if (config.workspaceId) {
9657
9690
  return {
9658
9691
  workspaceId: config.workspaceId,
@@ -9697,7 +9730,7 @@ function saveDefaultWorkspace(workspaceId, workspaceName) {
9697
9730
  }
9698
9731
  }
9699
9732
  function hasProjectConfig() {
9700
- return existsSync20(".runwork.json");
9733
+ return existsSync21(".runwork.json");
9701
9734
  }
9702
9735
  async function resolveApp2(client, workspaceId, options = {}) {
9703
9736
  if (options.app) {
@@ -9709,9 +9742,9 @@ async function resolveApp2(client, workspaceId, options = {}) {
9709
9742
  }
9710
9743
  return { appId: match.id, appName: match.name, source: "flag" };
9711
9744
  }
9712
- if (existsSync20(".runwork.json")) {
9745
+ if (existsSync21(".runwork.json")) {
9713
9746
  try {
9714
- const config = JSON.parse(readFileSync17(".runwork.json", "utf-8"));
9747
+ const config = JSON.parse(readFileSync18(".runwork.json", "utf-8"));
9715
9748
  if (config.appId) {
9716
9749
  return { appId: config.appId, appName: config.appName || "", source: "project" };
9717
9750
  }
@@ -10044,11 +10077,11 @@ var callCommand = new Command10("call").description("Make a proxy call to a conn
10044
10077
  let curlStr = opts.curl;
10045
10078
  if (opts.curlFile) {
10046
10079
  const filePath = opts.curlFile;
10047
- if (!existsSync21(filePath)) {
10080
+ if (!existsSync22(filePath)) {
10048
10081
  console.error(`File not found: ${filePath}`);
10049
10082
  process.exit(1);
10050
10083
  }
10051
- curlStr = readFileSync18(filePath, "utf-8");
10084
+ curlStr = readFileSync19(filePath, "utf-8");
10052
10085
  }
10053
10086
  try {
10054
10087
  const result = await parseCurlToRequest(curlStr);
@@ -10111,14 +10144,14 @@ init_store();
10111
10144
  init_client();
10112
10145
  init_colors();
10113
10146
  import { Command as Command11 } from "commander";
10114
- import { readFileSync as readFileSync19, existsSync as existsSync22 } from "fs";
10147
+ import { readFileSync as readFileSync20, existsSync as existsSync23 } from "fs";
10115
10148
  var openCommand = new Command11("open").description("Open app preview or dashboard in browser").argument("[target]", "What to open: preview (default), dashboard", "preview").action(async (target, _opts, command) => {
10116
10149
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
10117
- if (!existsSync22(".runwork.json")) {
10150
+ if (!existsSync23(".runwork.json")) {
10118
10151
  console.error("No .runwork.json found. Run `runwork init` first.");
10119
10152
  process.exit(1);
10120
10153
  }
10121
- const config = JSON.parse(readFileSync19(".runwork.json", "utf-8"));
10154
+ const config = JSON.parse(readFileSync20(".runwork.json", "utf-8"));
10122
10155
  const creds = requireAuth();
10123
10156
  const client = new ApiClient(creds);
10124
10157
  const open = await import("open");
@@ -10159,7 +10192,7 @@ var openCommand = new Command11("open").description("Open app preview or dashboa
10159
10192
  // src/commands/info.ts
10160
10193
  init_agent_guidance();
10161
10194
  import { Command as Command12 } from "commander";
10162
- import { readFileSync as readFileSync20, existsSync as existsSync23 } from "fs";
10195
+ import { readFileSync as readFileSync21, existsSync as existsSync24 } from "fs";
10163
10196
  import { join as join20 } from "path";
10164
10197
 
10165
10198
  // src/utils/app-info.ts
@@ -10351,20 +10384,20 @@ function readLocalDevSession(appDir, appId) {
10351
10384
  };
10352
10385
  }
10353
10386
  function tryReadConfig() {
10354
- if (!existsSync23(".runwork.json"))
10387
+ if (!existsSync24(".runwork.json"))
10355
10388
  return null;
10356
10389
  try {
10357
- return JSON.parse(readFileSync20(".runwork.json", "utf-8"));
10390
+ return JSON.parse(readFileSync21(".runwork.json", "utf-8"));
10358
10391
  } catch {
10359
10392
  return null;
10360
10393
  }
10361
10394
  }
10362
10395
  function readBlueprint(cwd) {
10363
10396
  const blueprintPath = join20(cwd, "blueprint.json");
10364
- if (!existsSync23(blueprintPath))
10397
+ if (!existsSync24(blueprintPath))
10365
10398
  return null;
10366
10399
  try {
10367
- return JSON.parse(readFileSync20(blueprintPath, "utf-8"));
10400
+ return JSON.parse(readFileSync21(blueprintPath, "utf-8"));
10368
10401
  } catch {
10369
10402
  return null;
10370
10403
  }
@@ -10708,7 +10741,7 @@ var infoCommand = new Command12("info").description("Show app context, registrie
10708
10741
  init_store();
10709
10742
  init_client();
10710
10743
  import { Command as Command13 } from "commander";
10711
- import { readFileSync as readFileSync21, existsSync as existsSync24 } from "fs";
10744
+ import { readFileSync as readFileSync22, existsSync as existsSync25 } from "fs";
10712
10745
  function truncate(text2, max) {
10713
10746
  if (!text2)
10714
10747
  return "";
@@ -10786,7 +10819,7 @@ var pushCommand = new Command13("push").description("Upload a local skill file t
10786
10819
  nameArg = first;
10787
10820
  filePath = second;
10788
10821
  } else if (first) {
10789
- if (existsSync24(first)) {
10822
+ if (existsSync25(first)) {
10790
10823
  filePath = first;
10791
10824
  } else if (!process.stdin.isTTY) {
10792
10825
  nameArg = first;
@@ -10803,11 +10836,11 @@ var pushCommand = new Command13("push").description("Upload a local skill file t
10803
10836
  }
10804
10837
  let content;
10805
10838
  if (filePath) {
10806
- if (!existsSync24(filePath)) {
10839
+ if (!existsSync25(filePath)) {
10807
10840
  console.error(`File not found: ${filePath}`);
10808
10841
  process.exit(1);
10809
10842
  }
10810
- content = readFileSync21(filePath, "utf-8");
10843
+ content = readFileSync22(filePath, "utf-8");
10811
10844
  } else {
10812
10845
  content = await readStdin2();
10813
10846
  if (!content.trim()) {
@@ -11019,8 +11052,8 @@ var skillsCommand = new Command13("skills").description("Manage workspace skills
11019
11052
  // src/commands/reflect.ts
11020
11053
  init_subprocess();
11021
11054
  import { Command as Command14 } from "commander";
11022
- import { writeFileSync as writeFileSync27, mkdirSync as mkdirSync26 } from "fs";
11023
- import { join as join34 } from "path";
11055
+ import { writeFileSync as writeFileSync25, mkdirSync as mkdirSync25 } from "fs";
11056
+ import { join as join37 } from "path";
11024
11057
 
11025
11058
  // src/utils/which.ts
11026
11059
  init_subprocess();
@@ -11058,9 +11091,9 @@ init_client();
11058
11091
 
11059
11092
  // src/agents/claude-code.ts
11060
11093
  init_subprocess();
11061
- import { chmodSync, existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync24, readdirSync as readdirSync5, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync16 } from "fs";
11062
- import { join as join21 } from "path";
11063
- import { homedir as homedir5, platform as platform2 } from "os";
11094
+ import { chmodSync, existsSync as existsSync30, mkdirSync as mkdirSync16, readFileSync as readFileSync25, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync16 } from "fs";
11095
+ import { join as join23 } from "path";
11096
+ import { homedir as homedir6, platform as platform2 } from "os";
11064
11097
 
11065
11098
  // ../../shared/skill/skill-canonical.ts
11066
11099
  function toSkillSlug(value) {
@@ -11169,6 +11202,10 @@ function buildSkillMd(parts) {
11169
11202
  var RUNWORK_MCP_PREFIX = "Runwork: ";
11170
11203
  var RUNWORK_MCP_PREFIX_LEGACY = "runwork-";
11171
11204
  var RUNWORK_WORKSPACE_MCP_NAME = "Runwork";
11205
+ var RUNWORK_PLUGIN_MARKETPLACE = "runwork";
11206
+ function isRunworkPluginKey(key) {
11207
+ return key.endsWith(`@${RUNWORK_PLUGIN_MARKETPLACE}`);
11208
+ }
11172
11209
  function appendTokenToUrl(url, token) {
11173
11210
  const parsed = new URL(url);
11174
11211
  parsed.searchParams.set("token", token);
@@ -11504,9 +11541,70 @@ function skillNameFromPath(path2) {
11504
11541
  return canonical || null;
11505
11542
  }
11506
11543
 
11544
+ // src/utils/trash.ts
11545
+ init_atomic_json();
11546
+ import { cpSync, existsSync as existsSync26, mkdirSync as mkdirSync13, readdirSync as readdirSync5, renameSync as renameSync3, rmSync as rmSync4, statSync as statSync3 } from "fs";
11547
+ import { basename as basename2, dirname as dirname6, join as join21 } from "path";
11548
+ import { homedir as homedir5 } from "os";
11549
+ var TRASH_RETENTION_DAYS = 30;
11550
+ function trashRoot() {
11551
+ return join21(homedir5(), ".runwork", "trash");
11552
+ }
11553
+ function batchDir(now) {
11554
+ const stamp = now.toISOString().replace(/[:.]/g, "-");
11555
+ return join21(trashRoot(), `${stamp}-${process.pid}`);
11556
+ }
11557
+ function pruneTrash(now = new Date) {
11558
+ const root = trashRoot();
11559
+ if (!existsSync26(root))
11560
+ return;
11561
+ const cutoff = now.getTime() - TRASH_RETENTION_DAYS * 24 * 60 * 60 * 1000;
11562
+ for (const entry of readdirSync5(root)) {
11563
+ const dir = join21(root, entry);
11564
+ try {
11565
+ if (statSync3(dir).mtimeMs < cutoff)
11566
+ rmSync4(dir, { recursive: true, force: true });
11567
+ } catch {}
11568
+ }
11569
+ }
11570
+ var activeBatch = null;
11571
+ function moveToTrash(sourcePath, reason, now = new Date) {
11572
+ if (!existsSync26(sourcePath))
11573
+ return null;
11574
+ if (!activeBatch || !activeBatch.startsWith(trashRoot())) {
11575
+ activeBatch = batchDir(now);
11576
+ pruneTrash(now);
11577
+ }
11578
+ const parent = basename2(dirname6(sourcePath));
11579
+ const grandparent = basename2(dirname6(dirname6(sourcePath)));
11580
+ const destDir = join21(activeBatch, `${grandparent}__${parent}`.replace(/[^a-zA-Z0-9._-]/g, "-"));
11581
+ const dest = join21(destDir, basename2(sourcePath));
11582
+ try {
11583
+ mkdirSync13(destDir, { recursive: true });
11584
+ try {
11585
+ renameSync3(sourcePath, dest);
11586
+ } catch {
11587
+ cpSync(sourcePath, dest, { recursive: true });
11588
+ rmSync4(sourcePath, { recursive: true, force: true });
11589
+ }
11590
+ } catch {
11591
+ return null;
11592
+ }
11593
+ const manifestPath = join21(activeBatch, "manifest.json");
11594
+ const manifest = readJsonOrNull(manifestPath) ?? { entries: [] };
11595
+ manifest.entries.push({ from: sourcePath, to: dest, reason, at: now.toISOString() });
11596
+ try {
11597
+ writeJsonAtomic(manifestPath, manifest);
11598
+ } catch {}
11599
+ return dest;
11600
+ }
11601
+ function currentTrashBatch() {
11602
+ return activeBatch;
11603
+ }
11604
+
11507
11605
  // src/agents/utils/json-config.ts
11508
- import { readFileSync as readFileSync22, writeFileSync as writeFileSync14, mkdirSync as mkdirSync13, existsSync as existsSync25 } from "fs";
11509
- import { dirname as dirname5 } from "path";
11606
+ import { readFileSync as readFileSync23, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14, existsSync as existsSync27 } from "fs";
11607
+ import { dirname as dirname7 } from "path";
11510
11608
 
11511
11609
  // src/sync/hash.ts
11512
11610
  import { createHash as createHash2 } from "crypto";
@@ -11538,21 +11636,21 @@ function isRunworkManagedKey(key) {
11538
11636
  return key === RUNWORK_WORKSPACE_MCP_NAME || key.startsWith(RUNWORK_MCP_PREFIX) || key.startsWith(RUNWORK_MCP_PREFIX_LEGACY);
11539
11637
  }
11540
11638
  function readJsonConfig(filePath) {
11541
- if (!existsSync25(filePath))
11639
+ if (!existsSync27(filePath))
11542
11640
  return {};
11543
11641
  try {
11544
- return JSON.parse(readFileSync22(filePath, "utf-8"));
11642
+ return JSON.parse(readFileSync23(filePath, "utf-8"));
11545
11643
  } catch {
11546
11644
  return {};
11547
11645
  }
11548
11646
  }
11549
11647
  function writeJsonConfig(filePath, config) {
11550
- mkdirSync13(dirname5(filePath), { recursive: true });
11648
+ mkdirSync14(dirname7(filePath), { recursive: true });
11551
11649
  writeFileSync14(filePath, JSON.stringify(config, null, 2) + `
11552
11650
  `);
11553
11651
  }
11554
11652
  function removeRunworkMcpServers(filePath, topKey) {
11555
- if (!existsSync25(filePath))
11653
+ if (!existsSync27(filePath))
11556
11654
  return false;
11557
11655
  const config = readJsonConfig(filePath);
11558
11656
  const existing = config[topKey] || {};
@@ -11591,18 +11689,46 @@ function mergeJsonMcpServers(filePath, servers, topKey) {
11591
11689
  return true;
11592
11690
  }
11593
11691
 
11692
+ // src/agents/utils/skill-removal.ts
11693
+ import { existsSync as existsSync28, readdirSync as readdirSync6 } from "fs";
11694
+ import { join as join22 } from "path";
11695
+ function removeMatchingSkillDirs(dir, allowed, reason = "skill removed") {
11696
+ if (!allowed.size || !existsSync28(dir))
11697
+ return;
11698
+ for (const entry of readdirSync6(dir)) {
11699
+ if (!allowed.has(entry))
11700
+ continue;
11701
+ moveToTrash(join22(dir, entry), reason);
11702
+ }
11703
+ }
11704
+ function removeMatchingSkillFiles(dir, allowed, suffix, reason = "skill removed") {
11705
+ if (!allowed.size || !existsSync28(dir))
11706
+ return;
11707
+ const names = new Set([...allowed].map((slug) => `${slug}${suffix}`));
11708
+ for (const entry of readdirSync6(dir)) {
11709
+ if (!names.has(entry))
11710
+ continue;
11711
+ moveToTrash(join22(dir, entry), reason);
11712
+ }
11713
+ }
11714
+
11594
11715
  // src/agents/utils/instruction-hint.ts
11595
- import { existsSync as existsSync26, readFileSync as readFileSync23, writeFileSync as writeFileSync15, mkdirSync as mkdirSync14 } from "fs";
11596
- import { dirname as dirname6 } from "path";
11716
+ import { existsSync as existsSync29, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "fs";
11717
+ import { dirname as dirname8 } from "path";
11597
11718
  var START_MARKER = "<!-- runwork:start -->";
11598
11719
  var END_MARKER = "<!-- runwork:end -->";
11599
11720
  var TEAM_START_MARKER = "<!-- runwork-team:start -->";
11600
11721
  var TEAM_END_MARKER = "<!-- runwork-team:end -->";
11601
11722
  function writeHintToFile(filePath, hint) {
11602
- mkdirSync14(dirname6(filePath), { recursive: true });
11723
+ mkdirSync15(dirname8(filePath), { recursive: true });
11724
+ if (!hint.includes(START_MARKER) || !hint.includes(END_MARKER)) {
11725
+ hint = `${START_MARKER}
11726
+ ${hint}
11727
+ ${END_MARKER}`;
11728
+ }
11603
11729
  let content = "";
11604
- if (existsSync26(filePath)) {
11605
- content = readFileSync23(filePath, "utf-8");
11730
+ if (existsSync29(filePath)) {
11731
+ content = readFileSync24(filePath, "utf-8");
11606
11732
  }
11607
11733
  const startIdx = content.indexOf(START_MARKER);
11608
11734
  const endIdx = content.indexOf(END_MARKER);
@@ -11624,9 +11750,9 @@ function writeHintToFile(filePath, hint) {
11624
11750
  writeFileSync15(filePath, content);
11625
11751
  }
11626
11752
  function removeHintFromFile(filePath) {
11627
- if (!existsSync26(filePath))
11753
+ if (!existsSync29(filePath))
11628
11754
  return false;
11629
- let content = readFileSync23(filePath, "utf-8");
11755
+ let content = readFileSync24(filePath, "utf-8");
11630
11756
  const startIdx = content.indexOf(START_MARKER);
11631
11757
  const endIdx = content.indexOf(END_MARKER);
11632
11758
  if (startIdx < 0 || endIdx < 0)
@@ -11644,9 +11770,9 @@ function removeHintFromFile(filePath) {
11644
11770
  return true;
11645
11771
  }
11646
11772
  function removeTeamInstructionsFromFile(filePath) {
11647
- if (!existsSync26(filePath))
11773
+ if (!existsSync29(filePath))
11648
11774
  return false;
11649
- let content = readFileSync23(filePath, "utf-8");
11775
+ let content = readFileSync24(filePath, "utf-8");
11650
11776
  const startIdx = content.indexOf(TEAM_START_MARKER);
11651
11777
  const endIdx = content.indexOf(TEAM_END_MARKER);
11652
11778
  if (startIdx < 0 || endIdx < 0)
@@ -11664,10 +11790,10 @@ function removeTeamInstructionsFromFile(filePath) {
11664
11790
  return true;
11665
11791
  }
11666
11792
  function writeTeamInstructionsToFile(filePath, instructions) {
11667
- mkdirSync14(dirname6(filePath), { recursive: true });
11793
+ mkdirSync15(dirname8(filePath), { recursive: true });
11668
11794
  let content = "";
11669
- if (existsSync26(filePath)) {
11670
- content = readFileSync23(filePath, "utf-8");
11795
+ if (existsSync29(filePath)) {
11796
+ content = readFileSync24(filePath, "utf-8");
11671
11797
  }
11672
11798
  const block = `${TEAM_START_MARKER}
11673
11799
  ${instructions}
@@ -11974,7 +12100,7 @@ class ClaudeCodeAdapter {
11974
12100
  if (whichBinary("claude"))
11975
12101
  return true;
11976
12102
  if (platform2() === "darwin")
11977
- return existsSync27("/Applications/Claude.app");
12103
+ return existsSync30("/Applications/Claude.app");
11978
12104
  return false;
11979
12105
  }
11980
12106
  supportsMcpScope(_scope) {
@@ -11985,7 +12111,7 @@ class ClaudeCodeAdapter {
11985
12111
  }
11986
12112
  async writeMcpServers(servers, scope) {
11987
12113
  if (scope === "project") {
11988
- const filePath = join21(process.cwd(), ".mcp.json");
12114
+ const filePath = join23(process.cwd(), ".mcp.json");
11989
12115
  const entries = {};
11990
12116
  for (const s of servers) {
11991
12117
  entries[s.name] = {
@@ -11997,7 +12123,7 @@ class ClaudeCodeAdapter {
11997
12123
  }
11998
12124
  mergeJsonMcpServers(filePath, entries, "mcpServers");
11999
12125
  } else {
12000
- const settingsPath = join21(homedir5(), ".claude", "settings.json");
12126
+ const settingsPath = join23(homedir6(), ".claude", "settings.json");
12001
12127
  const entries = {};
12002
12128
  for (const s of servers) {
12003
12129
  entries[s.name] = {
@@ -12009,11 +12135,11 @@ class ClaudeCodeAdapter {
12009
12135
  }
12010
12136
  mergeJsonMcpServers(settingsPath, entries, "mcpServers");
12011
12137
  const pluginDir = this.getPluginDir();
12012
- mkdirSync15(pluginDir, { recursive: true });
12013
- const pluginMcpPath = join21(pluginDir, ".mcp.json");
12138
+ mkdirSync16(pluginDir, { recursive: true });
12139
+ const pluginMcpPath = join23(pluginDir, ".mcp.json");
12014
12140
  const marketDir = this.getMarketplaceDir();
12015
- mkdirSync15(marketDir, { recursive: true });
12016
- const marketplaceMcpPath = join21(marketDir, ".mcp.json");
12141
+ mkdirSync16(marketDir, { recursive: true });
12142
+ const marketplaceMcpPath = join23(marketDir, ".mcp.json");
12017
12143
  const pluginEntries = {};
12018
12144
  for (const s of servers) {
12019
12145
  pluginEntries[s.name] = {
@@ -12028,44 +12154,44 @@ class ClaudeCodeAdapter {
12028
12154
  }
12029
12155
  }
12030
12156
  installSessionStartHook(pluginDir, label) {
12031
- const hooksDir = join21(pluginDir, "hooks");
12032
- mkdirSync15(hooksDir, { recursive: true });
12033
- const scriptPath = join21(hooksDir, "on-session-start.sh");
12157
+ const hooksDir = join23(pluginDir, "hooks");
12158
+ mkdirSync16(hooksDir, { recursive: true });
12159
+ const scriptPath = join23(hooksDir, "on-session-start.sh");
12034
12160
  writeFileSync16(scriptPath, SESSION_START_HOOK_SCRIPT);
12035
12161
  try {
12036
12162
  chmodSync(scriptPath, 493);
12037
12163
  } catch {}
12038
- writeFileSync16(join21(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12164
+ writeFileSync16(join23(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12039
12165
  vlog(` [Claude Code] Installed SessionStart hook (${label}) -> ${scriptPath}`);
12040
12166
  }
12041
12167
  async writeSkills(skills, scope) {
12042
- const baseDir = scope === "project" ? join21(process.cwd(), ".claude", "skills") : join21(homedir5(), ".claude", "skills");
12168
+ const baseDir = scope === "project" ? join23(process.cwd(), ".claude", "skills") : join23(homedir6(), ".claude", "skills");
12043
12169
  for (const skill of skills) {
12044
- const skillDir = join21(baseDir, skill.filename);
12170
+ const skillDir = join23(baseDir, skill.filename);
12045
12171
  cleanupOldSkillDir(baseDir, skill);
12046
- mkdirSync15(skillDir, { recursive: true });
12047
- writeFileSync16(join21(skillDir, "SKILL.md"), buildSkillMd2(skill));
12172
+ mkdirSync16(skillDir, { recursive: true });
12173
+ writeFileSync16(join23(skillDir, "SKILL.md"), buildSkillMd2(skill));
12048
12174
  }
12049
12175
  if (scope === "user") {
12050
12176
  const pluginDir = this.getPluginDir();
12051
- const pluginJsonDir = join21(pluginDir, ".claude-plugin");
12052
- mkdirSync15(pluginJsonDir, { recursive: true });
12053
- writeFileSync16(join21(pluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12177
+ const pluginJsonDir = join23(pluginDir, ".claude-plugin");
12178
+ mkdirSync16(pluginJsonDir, { recursive: true });
12179
+ writeFileSync16(join23(pluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12054
12180
  for (const skill of skills) {
12055
- const skillDir = join21(pluginDir, "skills", skill.filename);
12056
- cleanupOldSkillDir(join21(pluginDir, "skills"), skill);
12057
- mkdirSync15(skillDir, { recursive: true });
12058
- writeFileSync16(join21(skillDir, "SKILL.md"), buildSkillMd2(skill));
12181
+ const skillDir = join23(pluginDir, "skills", skill.filename);
12182
+ cleanupOldSkillDir(join23(pluginDir, "skills"), skill);
12183
+ mkdirSync16(skillDir, { recursive: true });
12184
+ writeFileSync16(join23(skillDir, "SKILL.md"), buildSkillMd2(skill));
12059
12185
  }
12060
12186
  const marketDir = this.getMarketplaceDir();
12061
- const marketPluginJsonDir = join21(marketDir, ".claude-plugin");
12062
- mkdirSync15(marketPluginJsonDir, { recursive: true });
12063
- writeFileSync16(join21(marketPluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12187
+ const marketPluginJsonDir = join23(marketDir, ".claude-plugin");
12188
+ mkdirSync16(marketPluginJsonDir, { recursive: true });
12189
+ writeFileSync16(join23(marketPluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12064
12190
  for (const skill of skills) {
12065
- const skillDir = join21(marketDir, "skills", skill.filename);
12066
- cleanupOldSkillDir(join21(marketDir, "skills"), skill);
12067
- mkdirSync15(skillDir, { recursive: true });
12068
- writeFileSync16(join21(skillDir, "SKILL.md"), buildSkillMd2(skill));
12191
+ const skillDir = join23(marketDir, "skills", skill.filename);
12192
+ cleanupOldSkillDir(join23(marketDir, "skills"), skill);
12193
+ mkdirSync16(skillDir, { recursive: true });
12194
+ writeFileSync16(join23(skillDir, "SKILL.md"), buildSkillMd2(skill));
12069
12195
  }
12070
12196
  this.registerPlugin(pluginDir);
12071
12197
  }
@@ -12076,19 +12202,19 @@ class ClaudeCodeAdapter {
12076
12202
  return;
12077
12203
  const pluginDir = this.getPluginDir();
12078
12204
  const marketDir = this.getMarketplaceDir();
12079
- if (existsSync27(pluginDir)) {
12205
+ if (existsSync30(pluginDir)) {
12080
12206
  this.installSessionStartHook(pluginDir, "plugin cache");
12081
12207
  }
12082
- if (existsSync27(marketDir)) {
12208
+ if (existsSync30(marketDir)) {
12083
12209
  this.installSessionStartHook(marketDir, "marketplace");
12084
12210
  }
12085
12211
  }
12086
12212
  async writeInstructionHint(hint, scope) {
12087
- const filePath = scope === "project" ? join21(process.cwd(), ".claude", "CLAUDE.md") : join21(homedir5(), ".claude", "CLAUDE.md");
12213
+ const filePath = scope === "project" ? join23(process.cwd(), ".claude", "CLAUDE.md") : join23(homedir6(), ".claude", "CLAUDE.md");
12088
12214
  writeHintToFile(filePath, hint);
12089
12215
  }
12090
12216
  async writeTeamInstructions(instructions, scope) {
12091
- const filePath = scope === "project" ? join21(process.cwd(), ".claude", "CLAUDE.md") : join21(homedir5(), ".claude", "CLAUDE.md");
12217
+ const filePath = scope === "project" ? join23(process.cwd(), ".claude", "CLAUDE.md") : join23(homedir6(), ".claude", "CLAUDE.md");
12092
12218
  writeTeamInstructionsToFile(filePath, instructions);
12093
12219
  if (scope === "user") {
12094
12220
  const skillContent = `---
@@ -12100,21 +12226,21 @@ ${instructions}`;
12100
12226
  const pluginDir = this.getPluginDir();
12101
12227
  const marketDir = this.getMarketplaceDir();
12102
12228
  for (const dir of [
12103
- join21(pluginDir, "skills", "runwork-team-instructions"),
12104
- join21(marketDir, "skills", "runwork-team-instructions")
12229
+ join23(pluginDir, "skills", "runwork-team-instructions"),
12230
+ join23(marketDir, "skills", "runwork-team-instructions")
12105
12231
  ]) {
12106
- mkdirSync15(dir, { recursive: true });
12107
- writeFileSync16(join21(dir, "SKILL.md"), skillContent);
12232
+ mkdirSync16(dir, { recursive: true });
12233
+ writeFileSync16(join23(dir, "SKILL.md"), skillContent);
12108
12234
  }
12109
12235
  }
12110
12236
  }
12111
12237
  async writeAgentConfig(config, scope, baseline) {
12112
- const settingsPath = scope === "project" ? join21(process.cwd(), ".claude", "settings.json") : join21(homedir5(), ".claude", "settings.json");
12113
- const hadFile = existsSync27(settingsPath);
12238
+ const settingsPath = scope === "project" ? join23(process.cwd(), ".claude", "settings.json") : join23(homedir6(), ".claude", "settings.json");
12239
+ const hadFile = existsSync30(settingsPath);
12114
12240
  let settings = {};
12115
12241
  if (hadFile) {
12116
12242
  try {
12117
- settings = JSON.parse(readFileSync24(settingsPath, "utf-8"));
12243
+ settings = JSON.parse(readFileSync25(settingsPath, "utf-8"));
12118
12244
  } catch {}
12119
12245
  }
12120
12246
  if (settings.permissions && typeof settings.permissions === "object") {
@@ -12144,37 +12270,39 @@ ${instructions}`;
12144
12270
  }
12145
12271
  if (!hadFile && !config.modelPreference && !config.permissionRules)
12146
12272
  return;
12147
- mkdirSync15(join21(settingsPath, ".."), { recursive: true });
12273
+ mkdirSync16(join23(settingsPath, ".."), { recursive: true });
12148
12274
  writeFileSync16(settingsPath, JSON.stringify(settings, null, 2));
12149
12275
  }
12150
12276
  async readManagedBlock(_scope) {
12151
12277
  return;
12152
12278
  }
12279
+ async removeSkills(skillFilenames, scope) {
12280
+ if (!skillFilenames.length)
12281
+ return;
12282
+ const allowed = new Set(skillFilenames);
12283
+ const roots = scope === "project" ? [join23(process.cwd(), ".claude", "skills")] : [
12284
+ join23(homedir6(), ".claude", "skills"),
12285
+ join23(this.getPluginDir(), "skills"),
12286
+ join23(this.getMarketplaceDir(), "skills")
12287
+ ];
12288
+ for (const dir of roots)
12289
+ removeMatchingSkillDirs(dir, allowed);
12290
+ }
12153
12291
  async cleanup(scope, manifest) {
12154
12292
  if (scope === "project") {
12155
- removeRunworkMcpServers(join21(process.cwd(), ".mcp.json"), "mcpServers");
12293
+ removeRunworkMcpServers(join23(process.cwd(), ".mcp.json"), "mcpServers");
12156
12294
  } else {
12157
- removeRunworkMcpServers(join21(homedir5(), ".claude", "settings.json"), "mcpServers");
12295
+ removeRunworkMcpServers(join23(homedir6(), ".claude", "settings.json"), "mcpServers");
12158
12296
  }
12159
- const skillsDir = scope === "project" ? join21(process.cwd(), ".claude", "skills") : join21(homedir5(), ".claude", "skills");
12160
- if (existsSync27(skillsDir) && manifest?.skillFilenames.length) {
12161
- const allowed = new Set(manifest.skillFilenames);
12162
- for (const entry of readdirSync5(skillsDir)) {
12163
- if (!allowed.has(entry))
12164
- continue;
12165
- try {
12166
- rmSync4(join21(skillsDir, entry), { recursive: true, force: true });
12167
- } catch {}
12168
- }
12169
- }
12170
- const instructionFile = scope === "project" ? join21(process.cwd(), ".claude", "CLAUDE.md") : join21(homedir5(), ".claude", "CLAUDE.md");
12297
+ await this.removeSkills(manifest?.skillFilenames ?? [], scope);
12298
+ const instructionFile = scope === "project" ? join23(process.cwd(), ".claude", "CLAUDE.md") : join23(homedir6(), ".claude", "CLAUDE.md");
12171
12299
  removeHintFromFile(instructionFile);
12172
12300
  removeTeamInstructionsFromFile(instructionFile);
12173
12301
  if (scope === "user") {
12174
- const settingsPath = join21(homedir5(), ".claude", "settings.json");
12175
- if (existsSync27(settingsPath)) {
12302
+ const settingsPath = join23(homedir6(), ".claude", "settings.json");
12303
+ if (existsSync30(settingsPath)) {
12176
12304
  try {
12177
- const settings = JSON.parse(readFileSync24(settingsPath, "utf-8"));
12305
+ const settings = JSON.parse(readFileSync25(settingsPath, "utf-8"));
12178
12306
  if (settings.permissions) {
12179
12307
  for (const key of ["allow", "deny"]) {
12180
12308
  const arr = settings.permissions[key];
@@ -12185,7 +12313,10 @@ ${instructions}`;
12185
12313
  }
12186
12314
  }
12187
12315
  if (settings.enabledPlugins) {
12188
- delete settings.enabledPlugins[`${PLUGIN_NAME}@runwork`];
12316
+ for (const key of Object.keys(settings.enabledPlugins)) {
12317
+ if (isRunworkPluginKey(key))
12318
+ delete settings.enabledPlugins[key];
12319
+ }
12189
12320
  }
12190
12321
  writeFileSync16(settingsPath, JSON.stringify(settings, null, 2));
12191
12322
  } catch {}
@@ -12193,25 +12324,28 @@ ${instructions}`;
12193
12324
  const pluginDir = this.getPluginDir();
12194
12325
  const marketRoot = this.getMarketplaceRoot();
12195
12326
  for (const dir of [pluginDir, marketRoot]) {
12196
- if (existsSync27(dir)) {
12327
+ if (existsSync30(dir)) {
12197
12328
  try {
12198
- rmSync4(dir, { recursive: true, force: true });
12329
+ rmSync5(dir, { recursive: true, force: true });
12199
12330
  } catch {}
12200
12331
  }
12201
12332
  }
12202
12333
  const pluginsBase = this.getPluginsBaseDir();
12203
- const installedPath = join21(pluginsBase, "installed_plugins.json");
12204
- if (existsSync27(installedPath)) {
12334
+ const installedPath = join23(pluginsBase, "installed_plugins.json");
12335
+ if (existsSync30(installedPath)) {
12205
12336
  try {
12206
12337
  const installed = readJsonConfig(installedPath);
12207
12338
  if (installed.plugins) {
12208
- delete installed.plugins[`${PLUGIN_NAME}@runwork`];
12339
+ for (const key of Object.keys(installed.plugins)) {
12340
+ if (isRunworkPluginKey(key))
12341
+ delete installed.plugins[key];
12342
+ }
12209
12343
  writeJsonConfig(installedPath, installed);
12210
12344
  }
12211
12345
  } catch {}
12212
12346
  }
12213
- const marketplacesPath = join21(pluginsBase, "known_marketplaces.json");
12214
- if (existsSync27(marketplacesPath)) {
12347
+ const marketplacesPath = join23(pluginsBase, "known_marketplaces.json");
12348
+ if (existsSync30(marketplacesPath)) {
12215
12349
  try {
12216
12350
  const marketplaces = readJsonConfig(marketplacesPath);
12217
12351
  delete marketplaces["runwork"];
@@ -12222,11 +12356,11 @@ ${instructions}`;
12222
12356
  }
12223
12357
  async readUsageStats(lastSyncAt) {
12224
12358
  try {
12225
- const claudeDir = join21(homedir5(), ".claude");
12226
- if (!existsSync27(claudeDir))
12359
+ const claudeDir = join23(homedir6(), ".claude");
12360
+ if (!existsSync30(claudeDir))
12227
12361
  return null;
12228
- const projectsDir = join21(claudeDir, "projects");
12229
- if (!existsSync27(projectsDir))
12362
+ const projectsDir = join23(claudeDir, "projects");
12363
+ if (!existsSync30(projectsDir))
12230
12364
  return null;
12231
12365
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
12232
12366
  let sessionCount = 0;
@@ -12240,25 +12374,25 @@ ${instructions}`;
12240
12374
  const seenEntries = new Set;
12241
12375
  let cwdEntries;
12242
12376
  try {
12243
- cwdEntries = readdirSync5(projectsDir);
12377
+ cwdEntries = readdirSync7(projectsDir);
12244
12378
  } catch {
12245
12379
  return null;
12246
12380
  }
12247
12381
  for (const cwd of cwdEntries) {
12248
- const cwdPath = join21(projectsDir, cwd);
12382
+ const cwdPath = join23(projectsDir, cwd);
12249
12383
  let files;
12250
12384
  try {
12251
- files = readdirSync5(cwdPath);
12385
+ files = readdirSync7(cwdPath);
12252
12386
  } catch {
12253
12387
  continue;
12254
12388
  }
12255
12389
  for (const file of files) {
12256
12390
  if (!file.endsWith(".jsonl"))
12257
12391
  continue;
12258
- const filePath = join21(cwdPath, file);
12392
+ const filePath = join23(cwdPath, file);
12259
12393
  let stat;
12260
12394
  try {
12261
- stat = statSync3(filePath);
12395
+ stat = statSync4(filePath);
12262
12396
  } catch {
12263
12397
  continue;
12264
12398
  }
@@ -12266,7 +12400,7 @@ ${instructions}`;
12266
12400
  continue;
12267
12401
  let content;
12268
12402
  try {
12269
- content = readFileSync24(filePath, "utf-8");
12403
+ content = readFileSync25(filePath, "utf-8");
12270
12404
  } catch {
12271
12405
  continue;
12272
12406
  }
@@ -12352,32 +12486,32 @@ ${instructions}`;
12352
12486
  }
12353
12487
  async readSessionDigests(sinceISO) {
12354
12488
  try {
12355
- const projectsDir = join21(homedir5(), ".claude", "projects");
12356
- if (!existsSync27(projectsDir))
12489
+ const projectsDir = join23(homedir6(), ".claude", "projects");
12490
+ if (!existsSync30(projectsDir))
12357
12491
  return null;
12358
12492
  const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
12359
12493
  let cwdEntries;
12360
12494
  try {
12361
- cwdEntries = readdirSync5(projectsDir);
12495
+ cwdEntries = readdirSync7(projectsDir);
12362
12496
  } catch {
12363
12497
  return null;
12364
12498
  }
12365
12499
  const digests = [];
12366
12500
  for (const cwd of cwdEntries) {
12367
- const cwdPath = join21(projectsDir, cwd);
12501
+ const cwdPath = join23(projectsDir, cwd);
12368
12502
  let files;
12369
12503
  try {
12370
- files = readdirSync5(cwdPath);
12504
+ files = readdirSync7(cwdPath);
12371
12505
  } catch {
12372
12506
  continue;
12373
12507
  }
12374
12508
  for (const file of files) {
12375
12509
  if (!file.endsWith(".jsonl"))
12376
12510
  continue;
12377
- const filePath = join21(cwdPath, file);
12511
+ const filePath = join23(cwdPath, file);
12378
12512
  let stat;
12379
12513
  try {
12380
- stat = statSync3(filePath);
12514
+ stat = statSync4(filePath);
12381
12515
  } catch {
12382
12516
  continue;
12383
12517
  }
@@ -12385,7 +12519,7 @@ ${instructions}`;
12385
12519
  continue;
12386
12520
  let content;
12387
12521
  try {
12388
- content = readFileSync24(filePath, "utf-8");
12522
+ content = readFileSync25(filePath, "utf-8");
12389
12523
  } catch {
12390
12524
  continue;
12391
12525
  }
@@ -12401,8 +12535,8 @@ ${instructions}`;
12401
12535
  }
12402
12536
  async readSkillUsage(lastSyncAt) {
12403
12537
  try {
12404
- const projectsDir = join21(homedir5(), ".claude", "projects");
12405
- if (!existsSync27(projectsDir))
12538
+ const projectsDir = join23(homedir6(), ".claude", "projects");
12539
+ if (!existsSync30(projectsDir))
12406
12540
  return null;
12407
12541
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
12408
12542
  const skillCounts = new Map;
@@ -12418,25 +12552,25 @@ ${instructions}`;
12418
12552
  };
12419
12553
  let cwdEntries;
12420
12554
  try {
12421
- cwdEntries = readdirSync5(projectsDir);
12555
+ cwdEntries = readdirSync7(projectsDir);
12422
12556
  } catch {
12423
12557
  return null;
12424
12558
  }
12425
12559
  for (const cwd of cwdEntries) {
12426
- const cwdPath = join21(projectsDir, cwd);
12560
+ const cwdPath = join23(projectsDir, cwd);
12427
12561
  let files;
12428
12562
  try {
12429
- files = readdirSync5(cwdPath);
12563
+ files = readdirSync7(cwdPath);
12430
12564
  } catch {
12431
12565
  continue;
12432
12566
  }
12433
12567
  for (const file of files) {
12434
12568
  if (!file.endsWith(".jsonl"))
12435
12569
  continue;
12436
- const filePath = join21(cwdPath, file);
12570
+ const filePath = join23(cwdPath, file);
12437
12571
  let fileStat;
12438
12572
  try {
12439
- fileStat = statSync3(filePath);
12573
+ fileStat = statSync4(filePath);
12440
12574
  } catch {
12441
12575
  continue;
12442
12576
  }
@@ -12444,7 +12578,7 @@ ${instructions}`;
12444
12578
  continue;
12445
12579
  let content;
12446
12580
  try {
12447
- content = readFileSync24(filePath, "utf-8");
12581
+ content = readFileSync25(filePath, "utf-8");
12448
12582
  } catch {
12449
12583
  continue;
12450
12584
  }
@@ -12534,21 +12668,21 @@ ${instructions}`;
12534
12668
  }
12535
12669
  }
12536
12670
  getPluginsBaseDir() {
12537
- return join21(homedir5(), ".claude", "plugins");
12671
+ return join23(homedir6(), ".claude", "plugins");
12538
12672
  }
12539
12673
  getPluginDir() {
12540
- return join21(this.getPluginsBaseDir(), "cache", "runwork", PLUGIN_NAME, PLUGIN_VERSION);
12674
+ return join23(this.getPluginsBaseDir(), "cache", "runwork", PLUGIN_NAME, PLUGIN_VERSION);
12541
12675
  }
12542
12676
  getMarketplaceRoot() {
12543
- return join21(this.getPluginsBaseDir(), "marketplaces", "runwork");
12677
+ return join23(this.getPluginsBaseDir(), "marketplaces", "runwork");
12544
12678
  }
12545
12679
  getMarketplaceDir() {
12546
- return join21(this.getMarketplaceRoot(), "plugins", PLUGIN_NAME);
12680
+ return join23(this.getMarketplaceRoot(), "plugins", PLUGIN_NAME);
12547
12681
  }
12548
12682
  registerPlugin(pluginDir) {
12549
12683
  const pluginsBase = this.getPluginsBaseDir();
12550
- mkdirSync15(pluginsBase, { recursive: true });
12551
- const installedPath = join21(pluginsBase, "installed_plugins.json");
12684
+ mkdirSync16(pluginsBase, { recursive: true });
12685
+ const installedPath = join23(pluginsBase, "installed_plugins.json");
12552
12686
  const installed = readJsonConfig(installedPath);
12553
12687
  if (!installed.version)
12554
12688
  installed.version = 2;
@@ -12565,10 +12699,10 @@ ${instructions}`;
12565
12699
  }];
12566
12700
  writeJsonConfig(installedPath, installed);
12567
12701
  const marketRoot = this.getMarketplaceRoot();
12568
- const marketCatalogDir = join21(marketRoot, ".claude-plugin");
12569
- mkdirSync15(marketCatalogDir, { recursive: true });
12570
- writeFileSync16(join21(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson(), null, 2));
12571
- const marketplacesPath = join21(pluginsBase, "known_marketplaces.json");
12702
+ const marketCatalogDir = join23(marketRoot, ".claude-plugin");
12703
+ mkdirSync16(marketCatalogDir, { recursive: true });
12704
+ writeFileSync16(join23(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson(), null, 2));
12705
+ const marketplacesPath = join23(pluginsBase, "known_marketplaces.json");
12572
12706
  const marketplaces = readJsonConfig(marketplacesPath);
12573
12707
  marketplaces["runwork"] = {
12574
12708
  source: { source: "directory", path: marketRoot },
@@ -12577,7 +12711,7 @@ ${instructions}`;
12577
12711
  };
12578
12712
  writeJsonConfig(marketplacesPath, marketplaces);
12579
12713
  vlog(` [Claude Code] ${wasRegistered ? "Refreshed" : "Registered"} plugin ` + `${pluginKey} v${PLUGIN_VERSION} -> ${installedPath}`);
12580
- const settingsPath = join21(homedir5(), ".claude", "settings.json");
12714
+ const settingsPath = join23(homedir6(), ".claude", "settings.json");
12581
12715
  const settings = readJsonConfig(settingsPath);
12582
12716
  if (!settings["enabledPlugins"]) {
12583
12717
  settings["enabledPlugins"] = {};
@@ -12592,27 +12726,23 @@ ${instructions}`;
12592
12726
  function cleanupOldSkillDir(baseDir, skill) {
12593
12727
  if (skill.name === skill.filename)
12594
12728
  return;
12595
- const oldDir = join21(baseDir, skill.name);
12596
- if (existsSync27(oldDir)) {
12597
- try {
12598
- rmSync4(oldDir, { recursive: true, force: true });
12599
- } catch {}
12600
- }
12729
+ const oldDir = join23(baseDir, skill.name);
12730
+ moveToTrash(oldDir, `skill renamed to ${skill.filename}`);
12601
12731
  }
12602
12732
 
12603
12733
  // src/agents/claude-desktop.ts
12604
- import { existsSync as existsSync29, mkdtempSync as mkdtempSync3, readdirSync as readdirSync6, readFileSync as readFileSync25, rmSync as rmSync6, statSync as statSync4, writeFileSync as writeFileSync18, mkdirSync as mkdirSync17 } from "fs";
12605
- import { dirname as dirname7, join as join23 } from "path";
12606
- import { homedir as homedir6, platform as platform3, tmpdir as tmpdir3 } from "os";
12734
+ import { existsSync as existsSync32, mkdtempSync as mkdtempSync3, readdirSync as readdirSync8, readFileSync as readFileSync26, rmSync as rmSync7, statSync as statSync5, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18 } from "fs";
12735
+ import { dirname as dirname9, join as join25 } from "path";
12736
+ import { homedir as homedir7, platform as platform3, tmpdir as tmpdir3 } from "os";
12607
12737
  init_zip();
12608
12738
 
12609
12739
  // src/agents/claude-desktop-plugin-tree.ts
12610
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync16, rmSync as rmSync5, existsSync as existsSync28, writeFileSync as writeFileSync17 } from "fs";
12611
- import { join as join22 } from "path";
12740
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync17, rmSync as rmSync6, existsSync as existsSync31, writeFileSync as writeFileSync17 } from "fs";
12741
+ import { join as join24 } from "path";
12612
12742
  function writePluginMetadata(destDir, metadata) {
12613
- const pluginJsonDir = join22(destDir, ".claude-plugin");
12614
- mkdirSync16(pluginJsonDir, { recursive: true });
12615
- writeFileSync17(join22(pluginJsonDir, "plugin.json"), JSON.stringify({
12743
+ const pluginJsonDir = join24(destDir, ".claude-plugin");
12744
+ mkdirSync17(pluginJsonDir, { recursive: true });
12745
+ writeFileSync17(join24(pluginJsonDir, "plugin.json"), JSON.stringify({
12616
12746
  name: metadata.pluginName,
12617
12747
  version: metadata.pluginVersion,
12618
12748
  description: metadata.description,
@@ -12620,7 +12750,7 @@ function writePluginMetadata(destDir, metadata) {
12620
12750
  }, null, 2));
12621
12751
  }
12622
12752
  function writePluginMcpConfig(destDir, mcpServers) {
12623
- mkdirSync16(destDir, { recursive: true });
12753
+ mkdirSync17(destDir, { recursive: true });
12624
12754
  const mcpEntries = {};
12625
12755
  for (const server of mcpServers) {
12626
12756
  if (server.name === RUNWORK_WORKSPACE_MCP_NAME) {
@@ -12639,49 +12769,49 @@ function writePluginMcpConfig(destDir, mcpServers) {
12639
12769
  };
12640
12770
  }
12641
12771
  }
12642
- writeFileSync17(join22(destDir, ".mcp.json"), JSON.stringify({ mcpServers: mcpEntries }, null, 2));
12772
+ writeFileSync17(join24(destDir, ".mcp.json"), JSON.stringify({ mcpServers: mcpEntries }, null, 2));
12643
12773
  }
12644
12774
  function writePluginTeamInstructions(destDir, instructions) {
12645
- const skillDir = join22(destDir, "skills", "runwork-team-instructions");
12646
- mkdirSync16(skillDir, { recursive: true });
12775
+ const skillDir = join24(destDir, "skills", "runwork-team-instructions");
12776
+ mkdirSync17(skillDir, { recursive: true });
12647
12777
  const skillContent = `---
12648
12778
  name: runwork-team-instructions
12649
12779
  description: Team instructions from your Runwork workspace. Always follow these guidelines.
12650
12780
  ---
12651
12781
 
12652
12782
  ${instructions}`;
12653
- writeFileSync17(join22(skillDir, "SKILL.md"), skillContent);
12783
+ writeFileSync17(join24(skillDir, "SKILL.md"), skillContent);
12654
12784
  }
12655
12785
  function writePluginSkills(destDir, skills) {
12656
- const skillsRoot = join22(destDir, "skills");
12657
- mkdirSync16(skillsRoot, { recursive: true });
12786
+ const skillsRoot = join24(destDir, "skills");
12787
+ mkdirSync17(skillsRoot, { recursive: true });
12658
12788
  for (const skill of skills) {
12659
12789
  if (skill.name !== skill.filename) {
12660
- const legacyDir = join22(skillsRoot, skill.name);
12661
- if (existsSync28(legacyDir)) {
12790
+ const legacyDir = join24(skillsRoot, skill.name);
12791
+ if (existsSync31(legacyDir)) {
12662
12792
  try {
12663
- rmSync5(legacyDir, { recursive: true, force: true });
12793
+ rmSync6(legacyDir, { recursive: true, force: true });
12664
12794
  } catch {}
12665
12795
  }
12666
12796
  }
12667
- const skillDir = join22(skillsRoot, skill.filename);
12668
- mkdirSync16(skillDir, { recursive: true });
12669
- writeFileSync17(join22(skillDir, "SKILL.md"), buildSkillMd2(skill));
12797
+ const skillDir = join24(skillsRoot, skill.filename);
12798
+ mkdirSync17(skillDir, { recursive: true });
12799
+ writeFileSync17(join24(skillDir, "SKILL.md"), buildSkillMd2(skill));
12670
12800
  }
12671
12801
  }
12672
12802
  function writePluginSessionStartHook(destDir) {
12673
- const hooksDir = join22(destDir, "hooks");
12674
- mkdirSync16(hooksDir, { recursive: true });
12675
- const scriptPath = join22(hooksDir, "on-session-start.sh");
12803
+ const hooksDir = join24(destDir, "hooks");
12804
+ mkdirSync17(hooksDir, { recursive: true });
12805
+ const scriptPath = join24(hooksDir, "on-session-start.sh");
12676
12806
  writeFileSync17(scriptPath, SESSION_START_HOOK_SCRIPT);
12677
12807
  try {
12678
12808
  chmodSync2(scriptPath, 493);
12679
12809
  } catch {}
12680
- writeFileSync17(join22(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12810
+ writeFileSync17(join24(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12681
12811
  console.log(` [Claude Desktop (Cowork)] Bundled SessionStart hook -> ${scriptPath}`);
12682
12812
  }
12683
12813
  function writePluginTree(destDir, input) {
12684
- mkdirSync16(destDir, { recursive: true });
12814
+ mkdirSync17(destDir, { recursive: true });
12685
12815
  writePluginMetadata(destDir, {
12686
12816
  pluginName: input.pluginName,
12687
12817
  pluginVersion: input.pluginVersion,
@@ -12698,6 +12828,9 @@ var PLUGIN_NAME2 = "runwork";
12698
12828
  var PLUGIN_VERSION2 = "1.0.0";
12699
12829
  var PLUGIN_DESCRIPTION = "Skills and tools from your Runwork workspace";
12700
12830
  var PLUGIN_AUTHOR_NAME = "Runwork";
12831
+ function isRunworkRpmPluginName(name) {
12832
+ return !!name && (name === PLUGIN_NAME2 || name.startsWith(`${PLUGIN_NAME2}-`));
12833
+ }
12701
12834
  function getPluginMetadata() {
12702
12835
  return {
12703
12836
  pluginName: PLUGIN_NAME2,
@@ -12709,39 +12842,59 @@ function getPluginMetadata() {
12709
12842
  function getMcpConfigPath() {
12710
12843
  const os2 = platform3();
12711
12844
  if (os2 === "darwin") {
12712
- return join23(homedir6(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
12845
+ return join25(homedir7(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
12713
12846
  }
12714
12847
  if (os2 === "win32") {
12715
- return join23(process.env.APPDATA || join23(homedir6(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
12848
+ return join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
12716
12849
  }
12717
- return join23(homedir6(), ".config", "Claude", "claude_desktop_config.json");
12850
+ return join25(homedir7(), ".config", "Claude", "claude_desktop_config.json");
12718
12851
  }
12719
12852
  function getCoworkBaseDir() {
12720
12853
  const os2 = platform3();
12721
12854
  if (os2 === "darwin") {
12722
- return join23(homedir6(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
12855
+ return join25(homedir7(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
12723
12856
  }
12724
12857
  if (os2 === "win32") {
12725
- return join23(process.env.APPDATA || join23(homedir6(), "AppData", "Roaming"), "Claude", "local-agent-mode-sessions");
12858
+ return join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude", "local-agent-mode-sessions");
12726
12859
  }
12727
- return join23(homedir6(), ".config", "Claude", "local-agent-mode-sessions");
12860
+ return join25(homedir7(), ".config", "Claude", "local-agent-mode-sessions");
12861
+ }
12862
+ function listOrgDirs() {
12863
+ const baseDir = getCoworkBaseDir();
12864
+ if (!existsSync32(baseDir))
12865
+ return [];
12866
+ const dirs = [];
12867
+ try {
12868
+ const sessionDirs = readdirSync8(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12869
+ for (const sessionId of sessionDirs) {
12870
+ const sessionPath = join25(baseDir, sessionId);
12871
+ try {
12872
+ for (const orgId of readdirSync8(sessionPath).filter((d) => !d.startsWith("."))) {
12873
+ dirs.push(join25(sessionPath, orgId));
12874
+ }
12875
+ } catch {
12876
+ continue;
12877
+ }
12878
+ }
12879
+ } catch {}
12880
+ return dirs;
12728
12881
  }
12729
12882
  function walkOrgDirs(visit) {
12730
12883
  const baseDir = getCoworkBaseDir();
12731
- if (!existsSync29(baseDir))
12884
+ if (!existsSync32(baseDir))
12732
12885
  return null;
12733
12886
  try {
12734
- const sessionDirs = readdirSync6(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12887
+ const sessionDirs = readdirSync8(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12735
12888
  for (const sessionId of sessionDirs) {
12736
- const sessionPath = join23(baseDir, sessionId);
12889
+ const sessionPath = join25(baseDir, sessionId);
12737
12890
  let orgDirs;
12738
12891
  try {
12739
- orgDirs = readdirSync6(sessionPath).filter((d) => !d.startsWith("."));
12892
+ orgDirs = readdirSync8(sessionPath).filter((d) => !d.startsWith("."));
12740
12893
  } catch {
12741
12894
  continue;
12742
12895
  }
12743
12896
  for (const orgId of orgDirs) {
12744
- const orgDir = join23(sessionPath, orgId);
12897
+ const orgDir = join25(sessionPath, orgId);
12745
12898
  const result = visit(orgDir);
12746
12899
  if (result !== null)
12747
12900
  return result;
@@ -12753,20 +12906,20 @@ function walkOrgDirs(visit) {
12753
12906
  function getCoworkMemoryClaudeMdPaths() {
12754
12907
  const paths = [];
12755
12908
  const baseDir = getCoworkBaseDir();
12756
- if (!existsSync29(baseDir))
12909
+ if (!existsSync32(baseDir))
12757
12910
  return paths;
12758
12911
  try {
12759
- const sessionDirs = readdirSync6(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12912
+ const sessionDirs = readdirSync8(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12760
12913
  for (const sessionId of sessionDirs) {
12761
- const sessionPath = join23(baseDir, sessionId);
12914
+ const sessionPath = join25(baseDir, sessionId);
12762
12915
  let orgDirs;
12763
12916
  try {
12764
- orgDirs = readdirSync6(sessionPath).filter((d) => !d.startsWith("."));
12917
+ orgDirs = readdirSync8(sessionPath).filter((d) => !d.startsWith("."));
12765
12918
  } catch {
12766
12919
  continue;
12767
12920
  }
12768
12921
  for (const orgId of orgDirs) {
12769
- paths.push(join23(sessionPath, orgId, "memory", "CLAUDE.md"));
12922
+ paths.push(join25(sessionPath, orgId, "memory", "CLAUDE.md"));
12770
12923
  }
12771
12924
  }
12772
12925
  } catch {}
@@ -12774,22 +12927,22 @@ function getCoworkMemoryClaudeMdPaths() {
12774
12927
  }
12775
12928
  function findCoworkPluginsDir() {
12776
12929
  return walkOrgDirs((orgDir) => {
12777
- const pluginsDir = join23(orgDir, "cowork_plugins");
12778
- return existsSync29(join23(pluginsDir, "installed_plugins.json")) ? pluginsDir : null;
12930
+ const pluginsDir = join25(orgDir, "cowork_plugins");
12931
+ return existsSync32(join25(pluginsDir, "installed_plugins.json")) ? pluginsDir : null;
12779
12932
  });
12780
12933
  }
12781
12934
  function findRpmPluginByName(pluginName) {
12782
12935
  return walkOrgDirs((orgDir) => {
12783
- const manifestPath = join23(orgDir, "rpm", "manifest.json");
12784
- if (!existsSync29(manifestPath))
12936
+ const manifestPath = join25(orgDir, "rpm", "manifest.json");
12937
+ if (!existsSync32(manifestPath))
12785
12938
  return null;
12786
12939
  try {
12787
- const manifest = JSON.parse(readFileSync25(manifestPath, "utf-8"));
12940
+ const manifest = JSON.parse(readFileSync26(manifestPath, "utf-8"));
12788
12941
  const entry = manifest.plugins?.find((p) => p.name === pluginName);
12789
12942
  if (!entry?.id)
12790
12943
  return null;
12791
12944
  return {
12792
- pluginPath: join23(orgDir, "rpm", entry.id),
12945
+ pluginPath: join25(orgDir, "rpm", entry.id),
12793
12946
  orgDir
12794
12947
  };
12795
12948
  } catch {
@@ -12811,7 +12964,7 @@ function getMarketplaceJson2() {
12811
12964
  };
12812
12965
  }
12813
12966
  function getCoworkSettingsPath(pluginsDir) {
12814
- return join23(dirname7(pluginsDir), "cowork_settings.json");
12967
+ return join25(dirname9(pluginsDir), "cowork_settings.json");
12815
12968
  }
12816
12969
  function setCoworkPluginEnabled(pluginsDir, enabled) {
12817
12970
  const settingsPath = getCoworkSettingsPath(pluginsDir);
@@ -12828,8 +12981,8 @@ class ClaudeDesktopAdapter {
12828
12981
  async detect() {
12829
12982
  const os2 = platform3();
12830
12983
  if (os2 === "darwin")
12831
- return existsSync29("/Applications/Claude.app");
12832
- return existsSync29(getMcpConfigPath());
12984
+ return existsSync32("/Applications/Claude.app");
12985
+ return existsSync32(getMcpConfigPath());
12833
12986
  }
12834
12987
  supportsMcpScope(scope) {
12835
12988
  return scope === "user";
@@ -12859,8 +13012,8 @@ class ClaudeDesktopAdapter {
12859
13012
  }
12860
13013
  const pluginsDir = findCoworkPluginsDir();
12861
13014
  if (pluginsDir) {
12862
- const cacheDir = join23(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
12863
- const marketDir = join23(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2);
13015
+ const cacheDir = join25(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
13016
+ const marketDir = join25(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2);
12864
13017
  for (const dir of [cacheDir, marketDir]) {
12865
13018
  writePluginMcpConfig(dir, servers);
12866
13019
  }
@@ -12878,14 +13031,14 @@ class ClaudeDesktopAdapter {
12878
13031
  console.warn(" [Claude Desktop] Cowork plugins directory not found. Open Claude Desktop at least once first.");
12879
13032
  return 0;
12880
13033
  }
12881
- const cacheDir = join23(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
12882
- const marketRoot = join23(pluginsDir, "marketplaces", "runwork");
12883
- const marketDir = join23(marketRoot, "plugins", PLUGIN_NAME2);
13034
+ const cacheDir = join25(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
13035
+ const marketRoot = join25(pluginsDir, "marketplaces", "runwork");
13036
+ const marketDir = join25(marketRoot, "plugins", PLUGIN_NAME2);
12884
13037
  for (const dir of [cacheDir, marketDir]) {
12885
13038
  writePluginMetadata(dir, getPluginMetadata());
12886
13039
  writePluginSkills(dir, skills);
12887
13040
  }
12888
- const installedPath = join23(pluginsDir, "installed_plugins.json");
13041
+ const installedPath = join25(pluginsDir, "installed_plugins.json");
12889
13042
  const installed = readJsonConfig(installedPath);
12890
13043
  if (!installed.version)
12891
13044
  installed.version = 2;
@@ -12899,10 +13052,10 @@ class ClaudeDesktopAdapter {
12899
13052
  lastUpdated: new Date().toISOString()
12900
13053
  }];
12901
13054
  writeJsonConfig(installedPath, installed);
12902
- const marketCatalogDir = join23(marketRoot, ".claude-plugin");
12903
- mkdirSync17(marketCatalogDir, { recursive: true });
12904
- writeFileSync18(join23(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson2(), null, 2));
12905
- const marketplacesPath = join23(pluginsDir, "known_marketplaces.json");
13055
+ const marketCatalogDir = join25(marketRoot, ".claude-plugin");
13056
+ mkdirSync18(marketCatalogDir, { recursive: true });
13057
+ writeFileSync18(join25(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson2(), null, 2));
13058
+ const marketplacesPath = join25(pluginsDir, "known_marketplaces.json");
12906
13059
  const marketplaces = readJsonConfig(marketplacesPath);
12907
13060
  marketplaces["runwork"] = {
12908
13061
  source: { source: "directory", path: marketRoot },
@@ -12921,8 +13074,8 @@ class ClaudeDesktopAdapter {
12921
13074
  }
12922
13075
  }
12923
13076
  async buildPluginZip(skills, mcpServers, teamInstructions, outputPath) {
12924
- const stagingRoot = mkdtempSync3(join23(tmpdir3(), "runwork-plugin-"));
12925
- const pluginStagingDir = join23(stagingRoot, PLUGIN_NAME2);
13077
+ const stagingRoot = mkdtempSync3(join25(tmpdir3(), "runwork-plugin-"));
13078
+ const pluginStagingDir = join25(stagingRoot, PLUGIN_NAME2);
12926
13079
  try {
12927
13080
  writePluginTree(pluginStagingDir, {
12928
13081
  ...getPluginMetadata(),
@@ -12935,7 +13088,7 @@ class ClaudeDesktopAdapter {
12935
13088
  createZipFromDir(pluginStagingDir, outputPath);
12936
13089
  } finally {
12937
13090
  try {
12938
- rmSync6(stagingRoot, { recursive: true, force: true });
13091
+ rmSync7(stagingRoot, { recursive: true, force: true });
12939
13092
  } catch {}
12940
13093
  }
12941
13094
  }
@@ -12953,15 +13106,15 @@ class ClaudeDesktopAdapter {
12953
13106
  const pluginsDir = findCoworkPluginsDir();
12954
13107
  if (!pluginsDir)
12955
13108
  return;
12956
- writePluginTeamInstructions(join23(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2), instructions);
12957
- writePluginTeamInstructions(join23(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2), instructions);
13109
+ writePluginTeamInstructions(join25(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2), instructions);
13110
+ writePluginTeamInstructions(join25(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2), instructions);
12958
13111
  }
12959
13112
  async writeAgentConfig(config, _scope) {
12960
13113
  const configPath = getMcpConfigPath();
12961
13114
  let desktopConfig = {};
12962
- if (existsSync29(configPath)) {
13115
+ if (existsSync32(configPath)) {
12963
13116
  try {
12964
- desktopConfig = JSON.parse(readFileSync25(configPath, "utf-8"));
13117
+ desktopConfig = JSON.parse(readFileSync26(configPath, "utf-8"));
12965
13118
  } catch {}
12966
13119
  }
12967
13120
  if (!desktopConfig.preferences)
@@ -12995,62 +13148,71 @@ class ClaudeDesktopAdapter {
12995
13148
  removeTeamInstructionsFromFile(path2);
12996
13149
  } catch {}
12997
13150
  }
12998
- const rpm = findRpmPluginByName(PLUGIN_NAME2);
12999
- if (rpm) {
13000
- if (existsSync29(rpm.pluginPath)) {
13001
- try {
13002
- rmSync6(rpm.pluginPath, { recursive: true, force: true });
13003
- } catch {}
13004
- }
13005
- const manifestPath = join23(rpm.orgDir, "rpm", "manifest.json");
13006
- if (existsSync29(manifestPath)) {
13007
- try {
13008
- const manifest = JSON.parse(readFileSync25(manifestPath, "utf-8"));
13009
- if (Array.isArray(manifest.plugins)) {
13010
- manifest.plugins = manifest.plugins.filter((p) => p.name !== PLUGIN_NAME2);
13011
- manifest.lastUpdated = Date.now();
13012
- writeFileSync18(manifestPath, JSON.stringify(manifest, null, 2));
13013
- }
13014
- } catch {}
13015
- }
13151
+ for (const orgDir of listOrgDirs()) {
13152
+ const manifestPath = join25(orgDir, "rpm", "manifest.json");
13153
+ if (!existsSync32(manifestPath))
13154
+ continue;
13155
+ try {
13156
+ const manifest = JSON.parse(readFileSync26(manifestPath, "utf-8"));
13157
+ if (!Array.isArray(manifest.plugins))
13158
+ continue;
13159
+ const ours = manifest.plugins.filter((p) => isRunworkRpmPluginName(p.name));
13160
+ if (!ours.length)
13161
+ continue;
13162
+ for (const entry of ours) {
13163
+ if (!entry.id)
13164
+ continue;
13165
+ moveToTrash(join25(orgDir, "rpm", entry.id), `claude-desktop-plugin:${entry.name}`);
13166
+ }
13167
+ manifest.plugins = manifest.plugins.filter((p) => !isRunworkRpmPluginName(p.name));
13168
+ manifest.lastUpdated = Date.now();
13169
+ writeFileSync18(manifestPath, JSON.stringify(manifest, null, 2));
13170
+ } catch {}
13016
13171
  }
13017
- const pluginsDir = findCoworkPluginsDir();
13018
- if (pluginsDir) {
13019
- const cacheRunwork = join23(pluginsDir, "cache", "runwork");
13020
- const marketRunwork = join23(pluginsDir, "marketplaces", "runwork");
13172
+ for (const orgDir of listOrgDirs()) {
13173
+ const pluginsDir = join25(orgDir, "cowork_plugins");
13174
+ if (!existsSync32(join25(pluginsDir, "installed_plugins.json")))
13175
+ continue;
13176
+ const cacheRunwork = join25(pluginsDir, "cache", "runwork");
13177
+ const marketRunwork = join25(pluginsDir, "marketplaces", "runwork");
13021
13178
  for (const dir of [cacheRunwork, marketRunwork]) {
13022
- if (existsSync29(dir)) {
13179
+ if (existsSync32(dir)) {
13023
13180
  try {
13024
- rmSync6(dir, { recursive: true, force: true });
13181
+ rmSync7(dir, { recursive: true, force: true });
13025
13182
  } catch {}
13026
13183
  }
13027
13184
  }
13028
- const installedPath = join23(pluginsDir, "installed_plugins.json");
13029
- if (existsSync29(installedPath)) {
13030
- try {
13031
- const installed = readJsonConfig(installedPath);
13032
- if (installed.plugins) {
13033
- delete installed.plugins[`${PLUGIN_NAME2}@runwork`];
13034
- writeJsonConfig(installedPath, installed);
13185
+ const installedPath = join25(pluginsDir, "installed_plugins.json");
13186
+ try {
13187
+ const installed = readJsonConfig(installedPath);
13188
+ if (installed.plugins) {
13189
+ for (const key of Object.keys(installed.plugins)) {
13190
+ if (isRunworkPluginKey(key))
13191
+ delete installed.plugins[key];
13035
13192
  }
13036
- } catch {}
13037
- }
13038
- const marketplacesPath = join23(pluginsDir, "known_marketplaces.json");
13039
- if (existsSync29(marketplacesPath)) {
13193
+ writeJsonConfig(installedPath, installed);
13194
+ }
13195
+ } catch {}
13196
+ const marketplacesPath = join25(pluginsDir, "known_marketplaces.json");
13197
+ if (existsSync32(marketplacesPath)) {
13040
13198
  try {
13041
13199
  const marketplaces = readJsonConfig(marketplacesPath);
13042
- delete marketplaces["runwork"];
13200
+ delete marketplaces[RUNWORK_PLUGIN_MARKETPLACE];
13043
13201
  writeJsonConfig(marketplacesPath, marketplaces);
13044
13202
  } catch {}
13045
13203
  }
13046
13204
  const coworkSettingsPath = getCoworkSettingsPath(pluginsDir);
13047
- if (existsSync29(coworkSettingsPath)) {
13205
+ if (existsSync32(coworkSettingsPath)) {
13048
13206
  try {
13049
13207
  const settings = readJsonConfig(coworkSettingsPath);
13050
13208
  const enabledPlugins = settings.enabledPlugins;
13051
13209
  if (enabledPlugins && typeof enabledPlugins === "object" && !Array.isArray(enabledPlugins)) {
13052
- delete enabledPlugins[`${PLUGIN_NAME2}@runwork`];
13053
- settings.enabledPlugins = enabledPlugins;
13210
+ const flags = enabledPlugins;
13211
+ for (const key of Object.keys(flags)) {
13212
+ if (isRunworkPluginKey(key))
13213
+ delete flags[key];
13214
+ }
13215
+ settings.enabledPlugins = flags;
13054
13216
  writeJsonConfig(coworkSettingsPath, settings);
13055
13217
  }
13056
13218
  } catch {}
@@ -13062,22 +13224,22 @@ class ClaudeDesktopAdapter {
13062
13224
  const os2 = platform3();
13063
13225
  let claudeAppDir;
13064
13226
  if (os2 === "darwin") {
13065
- claudeAppDir = join23(homedir6(), "Library", "Application Support", "Claude");
13227
+ claudeAppDir = join25(homedir7(), "Library", "Application Support", "Claude");
13066
13228
  } else if (os2 === "win32") {
13067
- claudeAppDir = join23(process.env.APPDATA || join23(homedir6(), "AppData", "Roaming"), "Claude");
13229
+ claudeAppDir = join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude");
13068
13230
  } else {
13069
- claudeAppDir = join23(homedir6(), ".config", "Claude");
13231
+ claudeAppDir = join25(homedir7(), ".config", "Claude");
13070
13232
  }
13071
- if (!existsSync29(claudeAppDir))
13233
+ if (!existsSync32(claudeAppDir))
13072
13234
  return null;
13073
13235
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
13074
13236
  let sessionCount = 0;
13075
13237
  let latestActivity = 0;
13076
13238
  const modelsUsed = new Set;
13077
13239
  let maxMcpTools = 0;
13078
- const agentSessionsDir = join23(claudeAppDir, "local-agent-mode-sessions");
13240
+ const agentSessionsDir = join25(claudeAppDir, "local-agent-mode-sessions");
13079
13241
  const activeDays = new Set;
13080
- if (existsSync29(agentSessionsDir)) {
13242
+ if (existsSync32(agentSessionsDir)) {
13081
13243
  this.walkSessionDirs(agentSessionsDir, sinceMs, (session) => {
13082
13244
  const sessionTime = session.lastActivityAt ?? session.createdAt ?? 0;
13083
13245
  if (sessionTime > sinceMs) {
@@ -13095,8 +13257,8 @@ class ClaudeDesktopAdapter {
13095
13257
  }
13096
13258
  });
13097
13259
  }
13098
- const codeSessionsDir = join23(claudeAppDir, "claude-code-sessions");
13099
- if (existsSync29(codeSessionsDir)) {
13260
+ const codeSessionsDir = join25(claudeAppDir, "claude-code-sessions");
13261
+ if (existsSync32(codeSessionsDir)) {
13100
13262
  this.walkSessionDirs(codeSessionsDir, sinceMs, (session) => {
13101
13263
  const sessionTime = session.lastActivityAt ?? session.createdAt ?? 0;
13102
13264
  if (sessionTime > sinceMs) {
@@ -13110,10 +13272,10 @@ class ClaudeDesktopAdapter {
13110
13272
  });
13111
13273
  }
13112
13274
  let scheduledTaskRuns = 0;
13113
- const scheduledTasksPath = join23(claudeAppDir, "scheduled-tasks.json");
13114
- if (existsSync29(scheduledTasksPath)) {
13275
+ const scheduledTasksPath = join25(claudeAppDir, "scheduled-tasks.json");
13276
+ if (existsSync32(scheduledTasksPath)) {
13115
13277
  try {
13116
- const raw = readFileSync25(scheduledTasksPath, "utf-8");
13278
+ const raw = readFileSync26(scheduledTasksPath, "utf-8");
13117
13279
  const parsed = JSON.parse(raw);
13118
13280
  const tasks = Array.isArray(parsed) ? parsed : Object.values(parsed);
13119
13281
  for (const task of tasks) {
@@ -13149,15 +13311,15 @@ class ClaudeDesktopAdapter {
13149
13311
  const os2 = platform3();
13150
13312
  let claudeAppDir;
13151
13313
  if (os2 === "darwin") {
13152
- claudeAppDir = join23(homedir6(), "Library", "Application Support", "Claude");
13314
+ claudeAppDir = join25(homedir7(), "Library", "Application Support", "Claude");
13153
13315
  } else if (os2 === "win32") {
13154
- claudeAppDir = join23(process.env.APPDATA || join23(homedir6(), "AppData", "Roaming"), "Claude");
13316
+ claudeAppDir = join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude");
13155
13317
  } else {
13156
- claudeAppDir = join23(homedir6(), ".config", "Claude");
13318
+ claudeAppDir = join25(homedir7(), ".config", "Claude");
13157
13319
  }
13158
- const versionPath = join23(claudeAppDir, "claude-code", "sdk-version");
13159
- if (existsSync29(versionPath)) {
13160
- return readFileSync25(versionPath, "utf-8").trim();
13320
+ const versionPath = join25(claudeAppDir, "claude-code", "sdk-version");
13321
+ if (existsSync32(versionPath)) {
13322
+ return readFileSync26(versionPath, "utf-8").trim();
13161
13323
  }
13162
13324
  return null;
13163
13325
  } catch {
@@ -13166,31 +13328,31 @@ class ClaudeDesktopAdapter {
13166
13328
  }
13167
13329
  walkSessionDirs(baseDir, _sinceMs, onSession) {
13168
13330
  try {
13169
- for (const orgDir of readdirSync6(baseDir)) {
13331
+ for (const orgDir of readdirSync8(baseDir)) {
13170
13332
  if (orgDir.startsWith(".") || orgDir === "skills-plugin")
13171
13333
  continue;
13172
- const orgPath = join23(baseDir, orgDir);
13334
+ const orgPath = join25(baseDir, orgDir);
13173
13335
  try {
13174
- if (!statSync4(orgPath).isDirectory())
13336
+ if (!statSync5(orgPath).isDirectory())
13175
13337
  continue;
13176
13338
  } catch {
13177
13339
  continue;
13178
13340
  }
13179
- for (const userDir of readdirSync6(orgPath)) {
13341
+ for (const userDir of readdirSync8(orgPath)) {
13180
13342
  if (userDir.startsWith("."))
13181
13343
  continue;
13182
- const userPath = join23(orgPath, userDir);
13344
+ const userPath = join25(orgPath, userDir);
13183
13345
  try {
13184
- if (!statSync4(userPath).isDirectory())
13346
+ if (!statSync5(userPath).isDirectory())
13185
13347
  continue;
13186
13348
  } catch {
13187
13349
  continue;
13188
13350
  }
13189
- for (const file of readdirSync6(userPath)) {
13351
+ for (const file of readdirSync8(userPath)) {
13190
13352
  if (!file.endsWith(".json"))
13191
13353
  continue;
13192
13354
  try {
13193
- const session = JSON.parse(readFileSync25(join23(userPath, file), "utf-8"));
13355
+ const session = JSON.parse(readFileSync26(join25(userPath, file), "utf-8"));
13194
13356
  onSession(session);
13195
13357
  } catch {
13196
13358
  continue;
@@ -13204,9 +13366,9 @@ class ClaudeDesktopAdapter {
13204
13366
 
13205
13367
  // src/agents/cursor.ts
13206
13368
  init_subprocess();
13207
- import { existsSync as existsSync30, mkdirSync as mkdirSync18, readdirSync as readdirSync7, unlinkSync as unlinkSync4, writeFileSync as writeFileSync19 } from "fs";
13208
- import { join as join24 } from "path";
13209
- import { homedir as homedir7, platform as platform4 } from "os";
13369
+ import { existsSync as existsSync33, mkdirSync as mkdirSync19, unlinkSync as unlinkSync4, writeFileSync as writeFileSync19 } from "fs";
13370
+ import { join as join26 } from "path";
13371
+ import { homedir as homedir8, platform as platform4 } from "os";
13210
13372
 
13211
13373
  // src/utils/sqlite-adapter.ts
13212
13374
  var adapter = null;
@@ -13298,7 +13460,7 @@ class CursorAdapter {
13298
13460
  mcpProvidesSkills = true;
13299
13461
  async detect() {
13300
13462
  const os2 = platform4();
13301
- if (os2 === "darwin" && existsSync30("/Applications/Cursor.app"))
13463
+ if (os2 === "darwin" && existsSync33("/Applications/Cursor.app"))
13302
13464
  return true;
13303
13465
  return !!whichBinary("cursor");
13304
13466
  }
@@ -13309,7 +13471,7 @@ class CursorAdapter {
13309
13471
  return true;
13310
13472
  }
13311
13473
  async writeMcpServers(servers, scope) {
13312
- const filePath = scope === "project" ? join24(process.cwd(), ".cursor", "mcp.json") : join24(homedir7(), ".cursor", "mcp.json");
13474
+ const filePath = scope === "project" ? join26(process.cwd(), ".cursor", "mcp.json") : join26(homedir8(), ".cursor", "mcp.json");
13313
13475
  const entries = {};
13314
13476
  for (const s of servers) {
13315
13477
  entries[s.name] = {
@@ -13322,8 +13484,8 @@ class CursorAdapter {
13322
13484
  async writeSkills(skills, scope) {
13323
13485
  if (scope === "user")
13324
13486
  return 0;
13325
- const rulesDir = join24(process.cwd(), ".cursor", "rules");
13326
- mkdirSync18(rulesDir, { recursive: true });
13487
+ const rulesDir = join26(process.cwd(), ".cursor", "rules");
13488
+ mkdirSync19(rulesDir, { recursive: true });
13327
13489
  for (const skill of skills) {
13328
13490
  const mdcContent = `---
13329
13491
  description: "${skill.description}"
@@ -13331,30 +13493,30 @@ alwaysApply: false
13331
13493
  ---
13332
13494
 
13333
13495
  ${skill.content}`;
13334
- writeFileSync19(join24(rulesDir, `${skill.filename}.mdc`), mdcContent);
13496
+ writeFileSync19(join26(rulesDir, `${skill.filename}.mdc`), mdcContent);
13335
13497
  }
13336
13498
  return skills.length;
13337
13499
  }
13338
13500
  async writeInstructionHint(hint, scope) {
13339
- const filePath = scope === "project" ? join24(process.cwd(), ".cursor", "rules", "runwork.mdc") : join24(homedir7(), ".cursor", "rules", "runwork.mdc");
13501
+ const filePath = scope === "project" ? join26(process.cwd(), ".cursor", "rules", "runwork.mdc") : join26(homedir8(), ".cursor", "rules", "runwork.mdc");
13340
13502
  const mdcContent = `---
13341
13503
  description: "Runwork workspace connection"
13342
13504
  alwaysApply: true
13343
13505
  ---
13344
13506
 
13345
13507
  ${hint}`;
13346
- mkdirSync18(join24(filePath, ".."), { recursive: true });
13508
+ mkdirSync19(join26(filePath, ".."), { recursive: true });
13347
13509
  writeFileSync19(filePath, mdcContent);
13348
13510
  }
13349
13511
  async writeTeamInstructions(instructions, scope) {
13350
- const filePath = scope === "project" ? join24(process.cwd(), ".cursor", "rules", "runwork-team.mdc") : join24(homedir7(), ".cursor", "rules", "runwork-team.mdc");
13512
+ const filePath = scope === "project" ? join26(process.cwd(), ".cursor", "rules", "runwork-team.mdc") : join26(homedir8(), ".cursor", "rules", "runwork-team.mdc");
13351
13513
  const mdcContent = `---
13352
13514
  description: "Team instructions from Runwork workspace"
13353
13515
  alwaysApply: true
13354
13516
  ---
13355
13517
 
13356
13518
  ${instructions}`;
13357
- mkdirSync18(join24(filePath, ".."), { recursive: true });
13519
+ mkdirSync19(join26(filePath, ".."), { recursive: true });
13358
13520
  writeFileSync19(filePath, mdcContent);
13359
13521
  }
13360
13522
  async writeAgentConfig(config, scope, baseline) {
@@ -13364,7 +13526,7 @@ ${instructions}`;
13364
13526
  this.mergeSandboxAllowlist(config.networkAllowlist);
13365
13527
  }
13366
13528
  const globalDbPath = this.globalStorageDbPath();
13367
- if (!existsSync30(globalDbPath))
13529
+ if (!existsSync33(globalDbPath))
13368
13530
  return;
13369
13531
  const db = openWritableSqlite(globalDbPath);
13370
13532
  if (!db) {
@@ -13400,7 +13562,7 @@ ${instructions}`;
13400
13562
  return;
13401
13563
  }
13402
13564
  mergeSandboxAllowlist(domains) {
13403
- const configPath = join24(homedir7(), ".cursor", "sandbox.json");
13565
+ const configPath = join26(homedir8(), ".cursor", "sandbox.json");
13404
13566
  try {
13405
13567
  const config = readJsonConfig(configPath);
13406
13568
  if (!config.networkPolicy)
@@ -13415,29 +13577,25 @@ ${instructions}`;
13415
13577
  writeJsonConfig(configPath, config);
13416
13578
  } catch {}
13417
13579
  }
13580
+ async removeSkills(skillFilenames, scope) {
13581
+ if (scope !== "project")
13582
+ return;
13583
+ removeMatchingSkillFiles(join26(process.cwd(), ".cursor", "rules"), new Set(skillFilenames), ".mdc");
13584
+ }
13418
13585
  async cleanup(scope, manifest) {
13419
- const mcpPath = scope === "project" ? join24(process.cwd(), ".cursor", "mcp.json") : join24(homedir7(), ".cursor", "mcp.json");
13586
+ const mcpPath = scope === "project" ? join26(process.cwd(), ".cursor", "mcp.json") : join26(homedir8(), ".cursor", "mcp.json");
13420
13587
  removeRunworkMcpServers(mcpPath, "mcpServers");
13421
- const rulesDir = scope === "project" ? join24(process.cwd(), ".cursor", "rules") : join24(homedir7(), ".cursor", "rules");
13422
- if (existsSync30(rulesDir)) {
13588
+ const rulesDir = scope === "project" ? join26(process.cwd(), ".cursor", "rules") : join26(homedir8(), ".cursor", "rules");
13589
+ if (existsSync33(rulesDir)) {
13423
13590
  for (const file of ["runwork.mdc", "runwork-team.mdc"]) {
13424
- const filePath = join24(rulesDir, file);
13425
- if (existsSync30(filePath)) {
13591
+ const filePath = join26(rulesDir, file);
13592
+ if (existsSync33(filePath)) {
13426
13593
  try {
13427
13594
  unlinkSync4(filePath);
13428
13595
  } catch {}
13429
13596
  }
13430
13597
  }
13431
- if (manifest?.skillFilenames.length) {
13432
- const allowed = new Set(manifest.skillFilenames.map((f) => `${f}.mdc`));
13433
- for (const entry of readdirSync7(rulesDir)) {
13434
- if (allowed.has(entry)) {
13435
- try {
13436
- unlinkSync4(join24(rulesDir, entry));
13437
- } catch {}
13438
- }
13439
- }
13440
- }
13598
+ await this.removeSkills(manifest?.skillFilenames ?? [], scope);
13441
13599
  }
13442
13600
  }
13443
13601
  async readUsageStats(lastSyncAt) {
@@ -13454,7 +13612,7 @@ ${instructions}`;
13454
13612
  let latestActivity = 0;
13455
13613
  let agenticSessions = 0;
13456
13614
  let chatSessions = 0;
13457
- if (existsSync30(globalDbPath)) {
13615
+ if (existsSync33(globalDbPath)) {
13458
13616
  const composerResult = queryReadonlySqlite(globalDbPath, `SELECT value FROM cursorDiskKV WHERE key LIKE 'composerData:%'`);
13459
13617
  if (composerResult) {
13460
13618
  for (const line of composerResult.split(`
@@ -13512,10 +13670,10 @@ ${instructions}`;
13512
13670
  }
13513
13671
  }
13514
13672
  const sessionCount = newComposersWithoutId + activeComposerIds.size;
13515
- const trackingDbPath = join24(homedir7(), ".cursor", "ai-tracking", "ai-code-tracking.db");
13673
+ const trackingDbPath = join26(homedir8(), ".cursor", "ai-tracking", "ai-code-tracking.db");
13516
13674
  let aiCommitCount = 0;
13517
13675
  let avgAiPercent = 0;
13518
- if (existsSync30(trackingDbPath)) {
13676
+ if (existsSync33(trackingDbPath)) {
13519
13677
  const sinceSec = Math.floor(sinceMs / 1000);
13520
13678
  const commitResult = queryReadonlySqlite(trackingDbPath, `SELECT count(*), avg(CAST(v2AiPercentage AS REAL)) FROM scored_commits WHERE scoredAt > ${sinceSec}`);
13521
13679
  if (commitResult) {
@@ -13558,17 +13716,17 @@ ${instructions}`;
13558
13716
  globalStorageDbPath() {
13559
13717
  const os2 = platform4();
13560
13718
  if (os2 === "darwin") {
13561
- return join24(homedir7(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
13719
+ return join26(homedir8(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
13562
13720
  }
13563
13721
  if (os2 === "win32") {
13564
- return join24(process.env.APPDATA || join24(homedir7(), "AppData", "Roaming"), "Cursor", "User", "globalStorage", "state.vscdb");
13722
+ return join26(process.env.APPDATA || join26(homedir8(), "AppData", "Roaming"), "Cursor", "User", "globalStorage", "state.vscdb");
13565
13723
  }
13566
- return join24(homedir7(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
13724
+ return join26(homedir8(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
13567
13725
  }
13568
13726
  async readSessionDigests(sinceISO) {
13569
13727
  try {
13570
13728
  const dbPath = this.globalStorageDbPath();
13571
- if (!existsSync30(dbPath) || !sqliteAvailable())
13729
+ if (!existsSync33(dbPath) || !sqliteAvailable())
13572
13730
  return null;
13573
13731
  const composerRows = queryReadonlySqlite(dbPath, `SELECT json_object('id', json_extract(value,'$.composerId'), 'createdAt', json_extract(value,'$.createdAt')) FROM cursorDiskKV WHERE key LIKE 'composerData:%'`);
13574
13732
  const bubbleRows = queryReadonlySqlite(dbPath, `SELECT json_object('k', key, 'type', json_extract(value,'$.type'), 'text', substr(json_extract(value,'$.text'),1,2000), 'ts', json_extract(value,'$.createdAt'), 'tool', json_extract(value,'$.toolFormerData.name'), 'status', json_extract(value,'$.toolFormerData.status')) FROM cursorDiskKV WHERE key LIKE 'bubbleId:%'`);
@@ -13582,17 +13740,17 @@ ${instructions}`;
13582
13740
  }
13583
13741
 
13584
13742
  // src/agents/windsurf.ts
13585
- import { existsSync as existsSync31, mkdirSync as mkdirSync19, readdirSync as readdirSync8, unlinkSync as unlinkSync5, writeFileSync as writeFileSync20 } from "fs";
13586
- import { join as join25 } from "path";
13587
- import { homedir as homedir8, platform as platform5 } from "os";
13743
+ import { existsSync as existsSync34, mkdirSync as mkdirSync20, unlinkSync as unlinkSync5, writeFileSync as writeFileSync20 } from "fs";
13744
+ import { join as join27 } from "path";
13745
+ import { homedir as homedir9, platform as platform5 } from "os";
13588
13746
  function getWindsurfDataDir() {
13589
13747
  if (platform5() === "win32") {
13590
- return join25(process.env.APPDATA || join25(homedir8(), "AppData", "Roaming"), "Codeium", "windsurf");
13748
+ return join27(process.env.APPDATA || join27(homedir9(), "AppData", "Roaming"), "Codeium", "windsurf");
13591
13749
  }
13592
- return join25(homedir8(), ".codeium", "windsurf");
13750
+ return join27(homedir9(), ".codeium", "windsurf");
13593
13751
  }
13594
13752
  function getConfigPath() {
13595
- return join25(getWindsurfDataDir(), "mcp_config.json");
13753
+ return join27(getWindsurfDataDir(), "mcp_config.json");
13596
13754
  }
13597
13755
 
13598
13756
  class WindsurfAdapter {
@@ -13601,7 +13759,7 @@ class WindsurfAdapter {
13601
13759
  mcpProvidesSkills = true;
13602
13760
  async detect() {
13603
13761
  const os2 = platform5();
13604
- if (os2 === "darwin" && existsSync31("/Applications/Windsurf.app"))
13762
+ if (os2 === "darwin" && existsSync34("/Applications/Windsurf.app"))
13605
13763
  return true;
13606
13764
  return !!whichBinary("windsurf");
13607
13765
  }
@@ -13624,84 +13782,80 @@ class WindsurfAdapter {
13624
13782
  async writeSkills(skills, scope) {
13625
13783
  if (scope === "user")
13626
13784
  return 0;
13627
- const rulesDir = join25(process.cwd(), ".windsurf", "rules");
13628
- mkdirSync19(rulesDir, { recursive: true });
13785
+ const rulesDir = join27(process.cwd(), ".windsurf", "rules");
13786
+ mkdirSync20(rulesDir, { recursive: true });
13629
13787
  for (const skill of skills) {
13630
13788
  const content = `---
13631
13789
  trigger: manual
13632
13790
  ---
13633
13791
 
13634
13792
  ${skill.content}`;
13635
- writeFileSync20(join25(rulesDir, `${skill.filename}.md`), content);
13793
+ writeFileSync20(join27(rulesDir, `${skill.filename}.md`), content);
13636
13794
  }
13637
13795
  return skills.length;
13638
13796
  }
13639
13797
  async writeTeamInstructions(instructions, scope) {
13640
- const filePath = scope === "project" ? join25(process.cwd(), ".windsurf", "rules", "runwork-team.md") : join25(getWindsurfDataDir(), "rules", "runwork-team.md");
13798
+ const filePath = scope === "project" ? join27(process.cwd(), ".windsurf", "rules", "runwork-team.md") : join27(getWindsurfDataDir(), "rules", "runwork-team.md");
13641
13799
  const content = `---
13642
13800
  trigger: always_on
13643
13801
  description: "Team instructions from Runwork workspace"
13644
13802
  ---
13645
13803
 
13646
13804
  ${instructions}`;
13647
- mkdirSync19(join25(filePath, ".."), { recursive: true });
13805
+ mkdirSync20(join27(filePath, ".."), { recursive: true });
13648
13806
  writeFileSync20(filePath, content);
13649
13807
  }
13650
13808
  async writeInstructionHint(hint, scope) {
13651
- const filePath = scope === "project" ? join25(process.cwd(), ".windsurf", "rules", "runwork.md") : join25(getWindsurfDataDir(), "rules", "runwork.md");
13809
+ const filePath = scope === "project" ? join27(process.cwd(), ".windsurf", "rules", "runwork.md") : join27(getWindsurfDataDir(), "rules", "runwork.md");
13652
13810
  const content = `---
13653
13811
  trigger: always
13654
13812
  ---
13655
13813
 
13656
13814
  ${hint}`;
13657
- mkdirSync19(join25(filePath, ".."), { recursive: true });
13815
+ mkdirSync20(join27(filePath, ".."), { recursive: true });
13658
13816
  writeFileSync20(filePath, content);
13659
13817
  }
13818
+ async removeSkills(skillFilenames, scope) {
13819
+ if (scope !== "project")
13820
+ return;
13821
+ removeMatchingSkillFiles(join27(process.cwd(), ".windsurf", "rules"), new Set(skillFilenames), ".md");
13822
+ }
13660
13823
  async cleanup(scope, manifest) {
13661
13824
  if (scope === "user") {
13662
13825
  removeRunworkMcpServers(getConfigPath(), "mcpServers");
13663
13826
  }
13664
- const rulesDir = scope === "project" ? join25(process.cwd(), ".windsurf", "rules") : join25(getWindsurfDataDir(), "rules");
13665
- if (existsSync31(rulesDir)) {
13827
+ const rulesDir = scope === "project" ? join27(process.cwd(), ".windsurf", "rules") : join27(getWindsurfDataDir(), "rules");
13828
+ if (existsSync34(rulesDir)) {
13666
13829
  for (const file of ["runwork.md", "runwork-team.md"]) {
13667
- const filePath = join25(rulesDir, file);
13668
- if (existsSync31(filePath)) {
13830
+ const filePath = join27(rulesDir, file);
13831
+ if (existsSync34(filePath)) {
13669
13832
  try {
13670
13833
  unlinkSync5(filePath);
13671
13834
  } catch {}
13672
13835
  }
13673
13836
  }
13674
- if (manifest?.skillFilenames.length) {
13675
- const allowed = new Set(manifest.skillFilenames.map((f) => `${f}.md`));
13676
- for (const entry of readdirSync8(rulesDir)) {
13677
- if (allowed.has(entry)) {
13678
- try {
13679
- unlinkSync5(join25(rulesDir, entry));
13680
- } catch {}
13681
- }
13682
- }
13683
- }
13837
+ await this.removeSkills(manifest?.skillFilenames ?? [], scope);
13684
13838
  }
13685
13839
  }
13686
13840
  }
13687
13841
 
13688
13842
  // src/agents/codex.ts
13689
- import { existsSync as existsSync34, mkdirSync as mkdirSync20, readdirSync as readdirSync9, readFileSync as readFileSync26, rmSync as rmSync8, statSync as statSync5, writeFileSync as writeFileSync21 } from "fs";
13690
- import { join as join28 } from "path";
13691
- import { homedir as homedir11 } from "os";
13843
+ import { existsSync as existsSync37, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as readFileSync27, statSync as statSync6, writeFileSync as writeFileSync21 } from "fs";
13844
+ import { join as join30 } from "path";
13845
+ import { homedir as homedir12 } from "os";
13692
13846
  import { parse, stringify } from "smol-toml";
13693
13847
 
13694
13848
  // src/agents/detection.ts
13695
13849
  import { execFile } from "child_process";
13696
- import { existsSync as existsSync33 } from "fs";
13697
- import { homedir as homedir10, platform as platform7 } from "os";
13698
- import { isAbsolute as isAbsolute2, join as join27 } from "path";
13850
+ import { existsSync as existsSync36 } from "fs";
13851
+ import { homedir as homedir11, platform as platform7 } from "os";
13852
+ import { isAbsolute as isAbsolute2, join as join29 } from "path";
13699
13853
  import { promisify } from "util";
13700
13854
 
13701
13855
  // src/agents/registry.ts
13702
- import { platform as platform6, homedir as homedir9 } from "os";
13703
- import { isAbsolute, join as join26 } from "path";
13704
- import { existsSync as existsSync32 } from "fs";
13856
+ import { platform as platform6, homedir as homedir10 } from "os";
13857
+ import { isAbsolute, join as join28 } from "path";
13858
+ import { existsSync as existsSync35 } from "fs";
13705
13859
 
13706
13860
  // src/agents/registry-data.ts
13707
13861
  var CLAUDE_CODE_NATIVE_INSTALL_PATHS = [
@@ -14298,7 +14452,7 @@ function resolveToAbsolute(ps, scope) {
14298
14452
  const resolved = resolvePlatformString(ps);
14299
14453
  if (!resolved)
14300
14454
  return;
14301
- return scope === "global" ? join26(homedir9(), resolved) : join26(process.cwd(), resolved);
14455
+ return scope === "global" ? join28(homedir10(), resolved) : join28(process.cwd(), resolved);
14302
14456
  }
14303
14457
  function resolveAgentCliCommand(slug) {
14304
14458
  const agent = getAgent(slug);
@@ -14311,8 +14465,8 @@ function resolveAgentCliCommand(slug) {
14311
14465
  const resolved = resolvePlatformString(candidate);
14312
14466
  if (!resolved)
14313
14467
  continue;
14314
- const absolute = isAbsolute(resolved) ? resolved : join26(homedir9(), resolved);
14315
- if (existsSync32(absolute))
14468
+ const absolute = isAbsolute(resolved) ? resolved : join28(homedir10(), resolved);
14469
+ if (existsSync35(absolute))
14316
14470
  return absolute;
14317
14471
  }
14318
14472
  return null;
@@ -14355,13 +14509,13 @@ function resolveDetectionPath(target) {
14355
14509
  const resolved = resolvePlatformString(target);
14356
14510
  if (!resolved)
14357
14511
  return null;
14358
- return isAbsolute2(resolved) ? resolved : join27(homedir10(), resolved);
14512
+ return isAbsolute2(resolved) ? resolved : join29(homedir11(), resolved);
14359
14513
  }
14360
14514
  function checkPath(target) {
14361
14515
  const absolute = resolveDetectionPath(target);
14362
14516
  if (!absolute)
14363
14517
  return null;
14364
- return existsSync33(absolute) ? absolute : null;
14518
+ return existsSync36(absolute) ? absolute : null;
14365
14519
  }
14366
14520
  async function checkMacosBundleId(target) {
14367
14521
  if (platform7() !== "darwin")
@@ -14441,10 +14595,10 @@ class CodexAdapter {
14441
14595
  return true;
14442
14596
  }
14443
14597
  async writeMcpServers(servers, _scope) {
14444
- const configPath = join28(homedir11(), ".codex", "config.toml");
14598
+ const configPath = join30(homedir12(), ".codex", "config.toml");
14445
14599
  let parsed = {};
14446
- if (existsSync34(configPath)) {
14447
- parsed = parse(readFileSync26(configPath, "utf-8"));
14600
+ if (existsSync37(configPath)) {
14601
+ parsed = parse(readFileSync27(configPath, "utf-8"));
14448
14602
  }
14449
14603
  if (!parsed.mcp_servers || typeof parsed.mcp_servers !== "object") {
14450
14604
  parsed.mcp_servers = {};
@@ -14467,48 +14621,39 @@ class CodexAdapter {
14467
14621
  }
14468
14622
  mcpServers[safeName] = entry;
14469
14623
  }
14470
- mkdirSync20(join28(configPath, ".."), { recursive: true });
14624
+ mkdirSync21(join30(configPath, ".."), { recursive: true });
14471
14625
  writeFileSync21(configPath, stringify(parsed));
14472
14626
  }
14473
14627
  async writeSkills(skills, scope) {
14474
- const root = scope === "project" ? process.cwd() : homedir11();
14475
- const baseDir = join28(root, ".agents", "skills");
14476
- const legacyBaseDir = join28(root, ".codex", "skills");
14628
+ const root = scope === "project" ? process.cwd() : homedir12();
14629
+ const baseDir = join30(root, ".agents", "skills");
14630
+ const legacyBaseDir = join30(root, ".codex", "skills");
14477
14631
  for (const skill of skills) {
14478
14632
  if (skill.name !== skill.filename) {
14479
- for (const dir of [join28(baseDir, skill.name), join28(legacyBaseDir, skill.name)]) {
14480
- if (existsSync34(dir)) {
14481
- try {
14482
- rmSync8(dir, { recursive: true, force: true });
14483
- } catch {}
14484
- }
14633
+ for (const dir of [join30(baseDir, skill.name), join30(legacyBaseDir, skill.name)]) {
14634
+ moveToTrash(dir, `skill renamed to ${skill.filename}`);
14485
14635
  }
14486
14636
  }
14487
- const legacyDir = join28(legacyBaseDir, skill.filename);
14488
- if (existsSync34(legacyDir)) {
14489
- try {
14490
- rmSync8(legacyDir, { recursive: true, force: true });
14491
- } catch {}
14492
- }
14493
- const skillDir = join28(baseDir, skill.filename);
14494
- mkdirSync20(skillDir, { recursive: true });
14495
- writeFileSync21(join28(skillDir, "SKILL.md"), buildSkillMd2(skill));
14637
+ moveToTrash(join30(legacyBaseDir, skill.filename), "duplicate skill root consolidated");
14638
+ const skillDir = join30(baseDir, skill.filename);
14639
+ mkdirSync21(skillDir, { recursive: true });
14640
+ writeFileSync21(join30(skillDir, "SKILL.md"), buildSkillMd2(skill));
14496
14641
  }
14497
14642
  return skills.length;
14498
14643
  }
14499
14644
  async writeInstructionHint(hint, scope) {
14500
- const filePath = scope === "project" ? join28(process.cwd(), "AGENTS.md") : join28(homedir11(), ".codex", "AGENTS.md");
14645
+ const filePath = scope === "project" ? join30(process.cwd(), "AGENTS.md") : join30(homedir12(), ".codex", "AGENTS.md");
14501
14646
  writeHintToFile(filePath, hint);
14502
14647
  }
14503
14648
  async writeTeamInstructions(instructions, scope) {
14504
- const filePath = scope === "project" ? join28(process.cwd(), "AGENTS.md") : join28(homedir11(), ".codex", "AGENTS.md");
14649
+ const filePath = scope === "project" ? join30(process.cwd(), "AGENTS.md") : join30(homedir12(), ".codex", "AGENTS.md");
14505
14650
  writeTeamInstructionsToFile(filePath, instructions);
14506
14651
  }
14507
14652
  async writeAgentConfig(config, scope) {
14508
- const configPath = scope === "project" ? join28(process.cwd(), ".codex", "config.toml") : join28(homedir11(), ".codex", "config.toml");
14653
+ const configPath = scope === "project" ? join30(process.cwd(), ".codex", "config.toml") : join30(homedir12(), ".codex", "config.toml");
14509
14654
  let parsed = {};
14510
- if (existsSync34(configPath)) {
14511
- parsed = parse(readFileSync26(configPath, "utf-8"));
14655
+ if (existsSync37(configPath)) {
14656
+ parsed = parse(readFileSync27(configPath, "utf-8"));
14512
14657
  }
14513
14658
  if (config.modelPreference) {
14514
14659
  parsed.model = config.modelPreference;
@@ -14551,14 +14696,23 @@ class CodexAdapter {
14551
14696
  sww.network_access = true;
14552
14697
  }
14553
14698
  }
14554
- mkdirSync20(join28(configPath, ".."), { recursive: true });
14699
+ mkdirSync21(join30(configPath, ".."), { recursive: true });
14555
14700
  writeFileSync21(configPath, stringify(parsed));
14556
14701
  }
14702
+ async removeSkills(skillFilenames, scope) {
14703
+ if (!skillFilenames.length)
14704
+ return;
14705
+ const allowed = new Set(skillFilenames);
14706
+ const root = scope === "project" ? process.cwd() : homedir12();
14707
+ for (const skillsDir of [join30(root, ".agents", "skills"), join30(root, ".codex", "skills")]) {
14708
+ removeMatchingSkillDirs(skillsDir, allowed);
14709
+ }
14710
+ }
14557
14711
  async cleanup(scope, manifest) {
14558
- const configPath = join28(homedir11(), ".codex", "config.toml");
14559
- if (existsSync34(configPath)) {
14712
+ const configPath = join30(homedir12(), ".codex", "config.toml");
14713
+ if (existsSync37(configPath)) {
14560
14714
  try {
14561
- const parsed = parse(readFileSync26(configPath, "utf-8"));
14715
+ const parsed = parse(readFileSync27(configPath, "utf-8"));
14562
14716
  if (parsed.mcp_servers && typeof parsed.mcp_servers === "object") {
14563
14717
  const mcpServers = parsed.mcp_servers;
14564
14718
  for (const key of Object.keys(mcpServers)) {
@@ -14570,27 +14724,15 @@ class CodexAdapter {
14570
14724
  writeFileSync21(configPath, stringify(parsed));
14571
14725
  } catch {}
14572
14726
  }
14573
- const cleanupRoot = scope === "project" ? process.cwd() : homedir11();
14574
- for (const skillsDir of [join28(cleanupRoot, ".agents", "skills"), join28(cleanupRoot, ".codex", "skills")]) {
14575
- if (!existsSync34(skillsDir) || !manifest?.skillFilenames.length)
14576
- continue;
14577
- const allowed = new Set(manifest.skillFilenames);
14578
- for (const entry of readdirSync9(skillsDir)) {
14579
- if (!allowed.has(entry))
14580
- continue;
14581
- try {
14582
- rmSync8(join28(skillsDir, entry), { recursive: true, force: true });
14583
- } catch {}
14584
- }
14585
- }
14586
- const instructionFile = scope === "project" ? join28(process.cwd(), "AGENTS.md") : join28(homedir11(), ".codex", "AGENTS.md");
14727
+ await this.removeSkills(manifest?.skillFilenames ?? [], scope);
14728
+ const instructionFile = scope === "project" ? join30(process.cwd(), "AGENTS.md") : join30(homedir12(), ".codex", "AGENTS.md");
14587
14729
  removeHintFromFile(instructionFile);
14588
14730
  removeTeamInstructionsFromFile(instructionFile);
14589
14731
  }
14590
14732
  async readUsageStats(lastSyncAt) {
14591
14733
  try {
14592
- const codexDir = join28(homedir11(), ".codex");
14593
- if (!existsSync34(codexDir))
14734
+ const codexDir = join30(homedir12(), ".codex");
14735
+ if (!existsSync37(codexDir))
14594
14736
  return null;
14595
14737
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
14596
14738
  const sinceSec = Math.floor(sinceMs / 1000);
@@ -14599,8 +14741,8 @@ class CodexAdapter {
14599
14741
  let tokensUsed = rollout.tokensUsed;
14600
14742
  let latestMs = rollout.latestMs;
14601
14743
  let versions = [];
14602
- const dbPath = join28(codexDir, "state_5.sqlite");
14603
- if (existsSync34(dbPath)) {
14744
+ const dbPath = join30(codexDir, "state_5.sqlite");
14745
+ if (existsSync37(dbPath)) {
14604
14746
  const countResult = queryReadonlySqlite(dbPath, `SELECT count(*) FROM threads WHERE updated_at > ${sinceSec}`);
14605
14747
  const dbSessionCount = parseInt(countResult) || 0;
14606
14748
  const tokensResult = queryReadonlySqlite(dbPath, `SELECT coalesce(sum(tokens_used), 0) FROM threads WHERE updated_at > ${sinceSec}`);
@@ -14617,9 +14759,9 @@ class CodexAdapter {
14617
14759
  }
14618
14760
  let messageCount = rollout.messageCount;
14619
14761
  if (messageCount === 0) {
14620
- const historyPath = join28(codexDir, "history.jsonl");
14621
- if (existsSync34(historyPath)) {
14622
- const content = readFileSync26(historyPath, "utf-8").trim();
14762
+ const historyPath = join30(codexDir, "history.jsonl");
14763
+ if (existsSync37(historyPath)) {
14764
+ const content = readFileSync27(historyPath, "utf-8").trim();
14623
14765
  if (content) {
14624
14766
  for (const line of content.split(/[\r\n]+/)) {
14625
14767
  try {
@@ -14662,19 +14804,19 @@ class CodexAdapter {
14662
14804
  latestMs: 0,
14663
14805
  activeDays: []
14664
14806
  };
14665
- const sessionsDir = join28(homedir11(), ".codex", "sessions");
14666
- if (!existsSync34(sessionsDir))
14807
+ const sessionsDir = join30(homedir12(), ".codex", "sessions");
14808
+ if (!existsSync37(sessionsDir))
14667
14809
  return result;
14668
14810
  const files = [];
14669
14811
  const walk = (dir) => {
14670
14812
  let entries;
14671
14813
  try {
14672
- entries = readdirSync9(dir, { withFileTypes: true });
14814
+ entries = readdirSync11(dir, { withFileTypes: true });
14673
14815
  } catch {
14674
14816
  return;
14675
14817
  }
14676
14818
  for (const e of entries) {
14677
- const full = join28(dir, e.name);
14819
+ const full = join30(dir, e.name);
14678
14820
  if (e.isDirectory())
14679
14821
  walk(full);
14680
14822
  else if (e.name.startsWith("rollout-") && e.name.endsWith(".jsonl"))
@@ -14685,7 +14827,7 @@ class CodexAdapter {
14685
14827
  for (const file of files) {
14686
14828
  let stat;
14687
14829
  try {
14688
- stat = statSync5(file);
14830
+ stat = statSync6(file);
14689
14831
  } catch {
14690
14832
  continue;
14691
14833
  }
@@ -14693,7 +14835,7 @@ class CodexAdapter {
14693
14835
  continue;
14694
14836
  let content;
14695
14837
  try {
14696
- content = readFileSync26(file, "utf-8");
14838
+ content = readFileSync27(file, "utf-8");
14697
14839
  } catch {
14698
14840
  continue;
14699
14841
  }
@@ -14752,20 +14894,20 @@ class CodexAdapter {
14752
14894
  }
14753
14895
  async readSessionDigests(sinceISO) {
14754
14896
  try {
14755
- const sessionsDir = join28(homedir11(), ".codex", "sessions");
14756
- if (!existsSync34(sessionsDir))
14897
+ const sessionsDir = join30(homedir12(), ".codex", "sessions");
14898
+ if (!existsSync37(sessionsDir))
14757
14899
  return null;
14758
14900
  const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
14759
14901
  const files = [];
14760
14902
  const walk = (dir) => {
14761
14903
  let entries;
14762
14904
  try {
14763
- entries = readdirSync9(dir, { withFileTypes: true });
14905
+ entries = readdirSync11(dir, { withFileTypes: true });
14764
14906
  } catch {
14765
14907
  return;
14766
14908
  }
14767
14909
  for (const e of entries) {
14768
- const full = join28(dir, e.name);
14910
+ const full = join30(dir, e.name);
14769
14911
  if (e.isDirectory())
14770
14912
  walk(full);
14771
14913
  else if (e.name.startsWith("rollout-") && e.name.endsWith(".jsonl"))
@@ -14777,7 +14919,7 @@ class CodexAdapter {
14777
14919
  for (const file of files) {
14778
14920
  let stat;
14779
14921
  try {
14780
- stat = statSync5(file);
14922
+ stat = statSync6(file);
14781
14923
  } catch {
14782
14924
  continue;
14783
14925
  }
@@ -14785,7 +14927,7 @@ class CodexAdapter {
14785
14927
  continue;
14786
14928
  let content;
14787
14929
  try {
14788
- content = readFileSync26(file, "utf-8");
14930
+ content = readFileSync27(file, "utf-8");
14789
14931
  } catch {
14790
14932
  continue;
14791
14933
  }
@@ -14800,9 +14942,9 @@ class CodexAdapter {
14800
14942
  }
14801
14943
  async readVersion() {
14802
14944
  try {
14803
- const versionPath = join28(homedir11(), ".codex", "version.json");
14804
- if (existsSync34(versionPath)) {
14805
- const data = JSON.parse(readFileSync26(versionPath, "utf-8"));
14945
+ const versionPath = join30(homedir12(), ".codex", "version.json");
14946
+ if (existsSync37(versionPath)) {
14947
+ const data = JSON.parse(readFileSync27(versionPath, "utf-8"));
14806
14948
  return data.latest_version ?? null;
14807
14949
  }
14808
14950
  } catch {}
@@ -14810,24 +14952,24 @@ class CodexAdapter {
14810
14952
  }
14811
14953
  async readSkillUsage(lastSyncAt) {
14812
14954
  try {
14813
- const sessionsDir = join28(homedir11(), ".codex", "sessions");
14814
- if (!existsSync34(sessionsDir))
14955
+ const sessionsDir = join30(homedir12(), ".codex", "sessions");
14956
+ if (!existsSync37(sessionsDir))
14815
14957
  return null;
14816
14958
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
14817
14959
  const skillCounts = new Map;
14818
14960
  const walkDir2 = (dir) => {
14819
14961
  let entries;
14820
14962
  try {
14821
- entries = readdirSync9(dir);
14963
+ entries = readdirSync11(dir);
14822
14964
  } catch {
14823
14965
  return;
14824
14966
  }
14825
14967
  for (const entry of entries) {
14826
- const fullPath = join28(dir, entry);
14968
+ const fullPath = join30(dir, entry);
14827
14969
  if (entry.endsWith(".jsonl")) {
14828
14970
  let fileStat;
14829
14971
  try {
14830
- fileStat = statSync5(fullPath);
14972
+ fileStat = statSync6(fullPath);
14831
14973
  } catch {
14832
14974
  continue;
14833
14975
  }
@@ -14836,7 +14978,7 @@ class CodexAdapter {
14836
14978
  this.parseRolloutForSkills(fullPath, sinceMs, skillCounts);
14837
14979
  } else {
14838
14980
  try {
14839
- if (statSync5(fullPath).isDirectory())
14981
+ if (statSync6(fullPath).isDirectory())
14840
14982
  walkDir2(fullPath);
14841
14983
  } catch {
14842
14984
  continue;
@@ -14863,7 +15005,7 @@ class CodexAdapter {
14863
15005
  parseRolloutForSkills(filePath, sinceMs, skillCounts) {
14864
15006
  let content;
14865
15007
  try {
14866
- content = readFileSync26(filePath, "utf-8");
15008
+ content = readFileSync27(filePath, "utf-8");
14867
15009
  } catch {
14868
15010
  return;
14869
15011
  }
@@ -14912,11 +15054,11 @@ class CodexAdapter {
14912
15054
  }
14913
15055
  }
14914
15056
  registerDesktopWorkspace(workspacePath, label) {
14915
- const statePath = join28(homedir11(), ".codex", ".codex-global-state.json");
15057
+ const statePath = join30(homedir12(), ".codex", ".codex-global-state.json");
14916
15058
  let state = {};
14917
- if (existsSync34(statePath)) {
15059
+ if (existsSync37(statePath)) {
14918
15060
  try {
14919
- state = JSON.parse(readFileSync26(statePath, "utf-8"));
15061
+ state = JSON.parse(readFileSync27(statePath, "utf-8"));
14920
15062
  } catch {
14921
15063
  return "app_running";
14922
15064
  }
@@ -14943,7 +15085,7 @@ class CodexAdapter {
14943
15085
  }
14944
15086
  labels[workspacePath] = label;
14945
15087
  state["electron-workspace-root-labels"] = labels;
14946
- mkdirSync20(join28(statePath, ".."), { recursive: true });
15088
+ mkdirSync21(join30(statePath, ".."), { recursive: true });
14947
15089
  writeFileSync21(statePath, JSON.stringify(state));
14948
15090
  return "written";
14949
15091
  }
@@ -14964,9 +15106,9 @@ class CodexDesktopAdapter extends CodexAdapter {
14964
15106
  }
14965
15107
 
14966
15108
  // src/agents/cline.ts
14967
- import { existsSync as existsSync35, mkdirSync as mkdirSync21, readFileSync as readFileSync27, readdirSync as readdirSync10, rmSync as rmSync9, unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
14968
- import { join as join29 } from "path";
14969
- import { homedir as homedir12 } from "os";
15109
+ import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as readFileSync28, readdirSync as readdirSync12, rmSync as rmSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
15110
+ import { join as join31 } from "path";
15111
+ import { homedir as homedir13 } from "os";
14970
15112
  class ClineAdapter {
14971
15113
  name = "Cline";
14972
15114
  slug = "cline";
@@ -14981,7 +15123,7 @@ class ClineAdapter {
14981
15123
  return true;
14982
15124
  }
14983
15125
  async writeMcpServers(servers, _scope) {
14984
- const configPath = join29(homedir12(), ".cline", "data", "settings", "cline_mcp_settings.json");
15126
+ const configPath = join31(homedir13(), ".cline", "data", "settings", "cline_mcp_settings.json");
14985
15127
  const entries = {};
14986
15128
  for (const s of servers) {
14987
15129
  entries[s.name] = {
@@ -14994,35 +15136,35 @@ class ClineAdapter {
14994
15136
  async writeSkills(skills, scope) {
14995
15137
  if (scope === "user")
14996
15138
  return 0;
14997
- const rulesDir = join29(process.cwd(), ".clinerules");
14998
- mkdirSync21(rulesDir, { recursive: true });
15139
+ const rulesDir = join31(process.cwd(), ".clinerules");
15140
+ mkdirSync22(rulesDir, { recursive: true });
14999
15141
  for (const skill of skills) {
15000
- writeFileSync22(join29(rulesDir, `${skill.filename}.md`), buildSkillMd2(skill));
15142
+ writeFileSync22(join31(rulesDir, `${skill.filename}.md`), buildSkillMd2(skill));
15001
15143
  }
15002
15144
  return skills.length;
15003
15145
  }
15004
15146
  async writeInstructionHint(hint, scope) {
15005
15147
  if (scope === "user")
15006
15148
  return;
15007
- const filePath = join29(process.cwd(), ".clinerules", "runwork.md");
15008
- mkdirSync21(join29(filePath, ".."), { recursive: true });
15149
+ const filePath = join31(process.cwd(), ".clinerules", "runwork.md");
15150
+ mkdirSync22(join31(filePath, ".."), { recursive: true });
15009
15151
  writeFileSync22(filePath, hint);
15010
15152
  }
15011
15153
  async writeTeamInstructions(instructions, scope) {
15012
15154
  if (scope === "user")
15013
15155
  return;
15014
- const filePath = join29(process.cwd(), ".clinerules", "runwork-team.md");
15015
- mkdirSync21(join29(filePath, ".."), { recursive: true });
15156
+ const filePath = join31(process.cwd(), ".clinerules", "runwork-team.md");
15157
+ mkdirSync22(join31(filePath, ".."), { recursive: true });
15016
15158
  writeFileSync22(filePath, instructions);
15017
15159
  }
15018
15160
  async writeAgentConfig(config, scope) {
15019
15161
  if (scope !== "user")
15020
15162
  return;
15021
- const globalStatePath = join29(homedir12(), ".cline", "data", "globalState.json");
15163
+ const globalStatePath = join31(homedir13(), ".cline", "data", "globalState.json");
15022
15164
  let state = {};
15023
- if (existsSync35(globalStatePath)) {
15165
+ if (existsSync38(globalStatePath)) {
15024
15166
  try {
15025
- state = JSON.parse(readFileSync27(globalStatePath, "utf-8"));
15167
+ state = JSON.parse(readFileSync28(globalStatePath, "utf-8"));
15026
15168
  } catch {}
15027
15169
  }
15028
15170
  if (config.modelPreference) {
@@ -15043,38 +15185,34 @@ class ClineAdapter {
15043
15185
  state.autoApprovalSettings.enabled = false;
15044
15186
  }
15045
15187
  }
15046
- mkdirSync21(join29(globalStatePath, ".."), { recursive: true });
15188
+ mkdirSync22(join31(globalStatePath, ".."), { recursive: true });
15047
15189
  writeFileSync22(globalStatePath, JSON.stringify(state, null, 2));
15048
15190
  }
15191
+ async removeSkills(skillFilenames, scope) {
15192
+ if (scope !== "project")
15193
+ return;
15194
+ removeMatchingSkillFiles(join31(process.cwd(), ".clinerules"), new Set(skillFilenames), ".md");
15195
+ }
15049
15196
  async cleanup(scope, manifest) {
15050
15197
  if (scope === "user") {
15051
- const configPath = join29(homedir12(), ".cline", "data", "settings", "cline_mcp_settings.json");
15198
+ const configPath = join31(homedir13(), ".cline", "data", "settings", "cline_mcp_settings.json");
15052
15199
  removeRunworkMcpServers(configPath, "mcpServers");
15053
15200
  }
15054
15201
  if (scope === "project") {
15055
- const rulesDir = join29(process.cwd(), ".clinerules");
15056
- if (existsSync35(rulesDir)) {
15202
+ const rulesDir = join31(process.cwd(), ".clinerules");
15203
+ if (existsSync38(rulesDir)) {
15057
15204
  for (const file of ["runwork.md", "runwork-team.md"]) {
15058
- const filePath = join29(rulesDir, file);
15059
- if (existsSync35(filePath)) {
15205
+ const filePath = join31(rulesDir, file);
15206
+ if (existsSync38(filePath)) {
15060
15207
  try {
15061
15208
  unlinkSync6(filePath);
15062
15209
  } catch {}
15063
15210
  }
15064
15211
  }
15065
- if (manifest?.skillFilenames.length) {
15066
- const allowed = new Set(manifest.skillFilenames.map((f) => `${f}.md`));
15067
- for (const entry of readdirSync10(rulesDir)) {
15068
- if (allowed.has(entry)) {
15069
- try {
15070
- unlinkSync6(join29(rulesDir, entry));
15071
- } catch {}
15072
- }
15073
- }
15074
- }
15212
+ await this.removeSkills(manifest?.skillFilenames ?? [], scope);
15075
15213
  try {
15076
- if (readdirSync10(rulesDir).length === 0)
15077
- rmSync9(rulesDir, { recursive: true });
15214
+ if (readdirSync12(rulesDir).length === 0)
15215
+ rmSync10(rulesDir, { recursive: true });
15078
15216
  } catch {}
15079
15217
  }
15080
15218
  }
@@ -15082,9 +15220,9 @@ class ClineAdapter {
15082
15220
  }
15083
15221
 
15084
15222
  // src/agents/gemini.ts
15085
- import { existsSync as existsSync36, mkdirSync as mkdirSync22, readdirSync as readdirSync11, readFileSync as readFileSync28, rmSync as rmSync10, statSync as statSync6, writeFileSync as writeFileSync23 } from "fs";
15086
- import { join as join30 } from "path";
15087
- import { homedir as homedir13 } from "os";
15223
+ import { existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync13, readFileSync as readFileSync29, statSync as statSync7, writeFileSync as writeFileSync23 } from "fs";
15224
+ import { join as join32 } from "path";
15225
+ import { homedir as homedir14 } from "os";
15088
15226
  class GeminiAdapter {
15089
15227
  name = "Gemini CLI";
15090
15228
  slug = "gemini";
@@ -15099,7 +15237,7 @@ class GeminiAdapter {
15099
15237
  return true;
15100
15238
  }
15101
15239
  async writeMcpServers(servers, _scope) {
15102
- const configPath = join30(homedir13(), ".gemini", "settings.json");
15240
+ const configPath = join32(homedir14(), ".gemini", "settings.json");
15103
15241
  const entries = {};
15104
15242
  for (const s of servers) {
15105
15243
  entries[s.name] = {
@@ -15110,36 +15248,31 @@ class GeminiAdapter {
15110
15248
  mergeJsonMcpServers(configPath, entries, "mcpServers");
15111
15249
  }
15112
15250
  async writeSkills(skills, scope) {
15113
- const baseDir = scope === "project" ? join30(process.cwd(), ".gemini", "skills") : join30(homedir13(), ".gemini", "skills");
15251
+ const baseDir = scope === "project" ? join32(process.cwd(), ".gemini", "skills") : join32(homedir14(), ".gemini", "skills");
15114
15252
  for (const skill of skills) {
15115
15253
  if (skill.name !== skill.filename) {
15116
- const oldDir = join30(baseDir, skill.name);
15117
- if (existsSync36(oldDir)) {
15118
- try {
15119
- rmSync10(oldDir, { recursive: true, force: true });
15120
- } catch {}
15121
- }
15254
+ moveToTrash(join32(baseDir, skill.name), `skill renamed to ${skill.filename}`);
15122
15255
  }
15123
- const skillDir = join30(baseDir, skill.filename);
15124
- mkdirSync22(skillDir, { recursive: true });
15125
- writeFileSync23(join30(skillDir, "SKILL.md"), buildSkillMd2(skill));
15256
+ const skillDir = join32(baseDir, skill.filename);
15257
+ mkdirSync23(skillDir, { recursive: true });
15258
+ writeFileSync23(join32(skillDir, "SKILL.md"), buildSkillMd2(skill));
15126
15259
  }
15127
15260
  return skills.length;
15128
15261
  }
15129
15262
  async writeInstructionHint(hint, scope) {
15130
- const filePath = scope === "project" ? join30(process.cwd(), "GEMINI.md") : join30(homedir13(), ".gemini", "GEMINI.md");
15263
+ const filePath = scope === "project" ? join32(process.cwd(), "GEMINI.md") : join32(homedir14(), ".gemini", "GEMINI.md");
15131
15264
  writeHintToFile(filePath, hint);
15132
15265
  }
15133
15266
  async writeTeamInstructions(instructions, scope) {
15134
- const filePath = scope === "project" ? join30(process.cwd(), "GEMINI.md") : join30(homedir13(), ".gemini", "GEMINI.md");
15267
+ const filePath = scope === "project" ? join32(process.cwd(), "GEMINI.md") : join32(homedir14(), ".gemini", "GEMINI.md");
15135
15268
  writeTeamInstructionsToFile(filePath, instructions);
15136
15269
  }
15137
15270
  async writeAgentConfig(config, scope) {
15138
- const settingsPath = scope === "project" ? join30(process.cwd(), ".gemini", "settings.json") : join30(homedir13(), ".gemini", "settings.json");
15271
+ const settingsPath = scope === "project" ? join32(process.cwd(), ".gemini", "settings.json") : join32(homedir14(), ".gemini", "settings.json");
15139
15272
  let settings = {};
15140
- if (existsSync36(settingsPath)) {
15273
+ if (existsSync39(settingsPath)) {
15141
15274
  try {
15142
- settings = JSON.parse(readFileSync28(settingsPath, "utf-8"));
15275
+ settings = JSON.parse(readFileSync29(settingsPath, "utf-8"));
15143
15276
  } catch {}
15144
15277
  }
15145
15278
  if (config.modelPreference) {
@@ -15157,13 +15290,13 @@ class GeminiAdapter {
15157
15290
  settings.tools = {};
15158
15291
  settings.tools.exclude = config.permissionRules.deny;
15159
15292
  }
15160
- mkdirSync22(join30(settingsPath, ".."), { recursive: true });
15293
+ mkdirSync23(join32(settingsPath, ".."), { recursive: true });
15161
15294
  writeFileSync23(settingsPath, JSON.stringify(settings, null, 2));
15162
15295
  }
15163
15296
  async readUsageStats(lastSyncAt) {
15164
15297
  try {
15165
- const tmpDir = join30(homedir13(), ".gemini", "tmp");
15166
- if (!existsSync36(tmpDir))
15298
+ const tmpDir = join32(homedir14(), ".gemini", "tmp");
15299
+ if (!existsSync39(tmpDir))
15167
15300
  return null;
15168
15301
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
15169
15302
  let sessionCount = 0;
@@ -15172,27 +15305,27 @@ class GeminiAdapter {
15172
15305
  const activeDays = new Set;
15173
15306
  let projects;
15174
15307
  try {
15175
- projects = readdirSync11(tmpDir, { withFileTypes: true });
15308
+ projects = readdirSync13(tmpDir, { withFileTypes: true });
15176
15309
  } catch {
15177
15310
  return null;
15178
15311
  }
15179
15312
  for (const project of projects) {
15180
15313
  if (!project.isDirectory())
15181
15314
  continue;
15182
- const chatsDir = join30(tmpDir, project.name, "chats");
15315
+ const chatsDir = join32(tmpDir, project.name, "chats");
15183
15316
  let files;
15184
15317
  try {
15185
- files = readdirSync11(chatsDir, { withFileTypes: true });
15318
+ files = readdirSync13(chatsDir, { withFileTypes: true });
15186
15319
  } catch {
15187
15320
  continue;
15188
15321
  }
15189
15322
  for (const file of files) {
15190
15323
  if (!file.name.startsWith("session-") || !file.name.endsWith(".json"))
15191
15324
  continue;
15192
- const filePath = join30(chatsDir, file.name);
15325
+ const filePath = join32(chatsDir, file.name);
15193
15326
  let stat;
15194
15327
  try {
15195
- stat = statSync6(filePath);
15328
+ stat = statSync7(filePath);
15196
15329
  } catch {
15197
15330
  continue;
15198
15331
  }
@@ -15200,7 +15333,7 @@ class GeminiAdapter {
15200
15333
  continue;
15201
15334
  let session;
15202
15335
  try {
15203
- session = JSON.parse(readFileSync28(filePath, "utf-8"));
15336
+ session = JSON.parse(readFileSync29(filePath, "utf-8"));
15204
15337
  } catch {
15205
15338
  continue;
15206
15339
  }
@@ -15240,31 +15373,25 @@ class GeminiAdapter {
15240
15373
  return null;
15241
15374
  }
15242
15375
  }
15376
+ async removeSkills(skillFilenames, scope) {
15377
+ const skillsDir = scope === "project" ? join32(process.cwd(), ".gemini", "skills") : join32(homedir14(), ".gemini", "skills");
15378
+ removeMatchingSkillDirs(skillsDir, new Set(skillFilenames));
15379
+ }
15243
15380
  async cleanup(scope, manifest) {
15244
15381
  if (scope === "user") {
15245
- removeRunworkMcpServers(join30(homedir13(), ".gemini", "settings.json"), "mcpServers");
15246
- }
15247
- const skillsDir = scope === "project" ? join30(process.cwd(), ".gemini", "skills") : join30(homedir13(), ".gemini", "skills");
15248
- if (existsSync36(skillsDir) && manifest?.skillFilenames.length) {
15249
- const allowed = new Set(manifest.skillFilenames);
15250
- for (const entry of readdirSync11(skillsDir)) {
15251
- if (!allowed.has(entry))
15252
- continue;
15253
- try {
15254
- rmSync10(join30(skillsDir, entry), { recursive: true, force: true });
15255
- } catch {}
15256
- }
15382
+ removeRunworkMcpServers(join32(homedir14(), ".gemini", "settings.json"), "mcpServers");
15257
15383
  }
15258
- const instructionFile = scope === "project" ? join30(process.cwd(), "GEMINI.md") : join30(homedir13(), ".gemini", "GEMINI.md");
15384
+ await this.removeSkills(manifest?.skillFilenames ?? [], scope);
15385
+ const instructionFile = scope === "project" ? join32(process.cwd(), "GEMINI.md") : join32(homedir14(), ".gemini", "GEMINI.md");
15259
15386
  removeHintFromFile(instructionFile);
15260
15387
  removeTeamInstructionsFromFile(instructionFile);
15261
15388
  }
15262
15389
  }
15263
15390
 
15264
15391
  // src/agents/generic-adapter.ts
15265
- import { existsSync as existsSync37, mkdirSync as mkdirSync23, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as writeFileSync24 } from "fs";
15266
- import { join as join31 } from "path";
15267
- import { homedir as homedir14 } from "os";
15392
+ import { existsSync as existsSync40, mkdirSync as mkdirSync24, rmSync as rmSync12, writeFileSync as writeFileSync24 } from "fs";
15393
+ import { join as join33 } from "path";
15394
+ import { homedir as homedir15 } from "os";
15268
15395
  class GenericAgentAdapter {
15269
15396
  name;
15270
15397
  slug;
@@ -15289,7 +15416,7 @@ class GenericAgentAdapter {
15289
15416
  async writeMcpServers(servers, _scope) {
15290
15417
  if (!this.def.mcpConfigPath)
15291
15418
  return;
15292
- const filePath = join31(homedir14(), resolvePlatformString(this.def.mcpConfigPath) || "");
15419
+ const filePath = join33(homedir15(), resolvePlatformString(this.def.mcpConfigPath) || "");
15293
15420
  if (!filePath)
15294
15421
  return;
15295
15422
  const entries = {};
@@ -15313,16 +15440,16 @@ class GenericAgentAdapter {
15313
15440
  return 0;
15314
15441
  for (const skill of skills) {
15315
15442
  if (skill.name !== skill.filename) {
15316
- const oldDir = join31(baseDir, skill.name);
15317
- if (existsSync37(oldDir)) {
15443
+ const oldDir = join33(baseDir, skill.name);
15444
+ if (existsSync40(oldDir)) {
15318
15445
  try {
15319
- rmSync11(oldDir, { recursive: true, force: true });
15446
+ rmSync12(oldDir, { recursive: true, force: true });
15320
15447
  } catch {}
15321
15448
  }
15322
15449
  }
15323
- const skillDir = join31(baseDir, skill.filename);
15324
- mkdirSync23(skillDir, { recursive: true });
15325
- writeFileSync24(join31(skillDir, "SKILL.md"), buildSkillMd2(skill));
15450
+ const skillDir = join33(baseDir, skill.filename);
15451
+ mkdirSync24(skillDir, { recursive: true });
15452
+ writeFileSync24(join33(skillDir, "SKILL.md"), buildSkillMd2(skill));
15326
15453
  }
15327
15454
  return skills.length;
15328
15455
  }
@@ -15348,31 +15475,25 @@ class GenericAgentAdapter {
15348
15475
  return;
15349
15476
  writeTeamInstructionsToFile(filePath, instructions);
15350
15477
  }
15478
+ async removeSkills(skillFilenames, scope) {
15479
+ if (!this.def.skillsPaths || !skillFilenames.length)
15480
+ return;
15481
+ const pathTemplate = scope === "project" ? this.def.skillsPaths.project : this.def.skillsPaths.global;
15482
+ if (!pathTemplate)
15483
+ return;
15484
+ const baseDir = resolveToAbsolute(pathTemplate, scope === "project" ? "project" : "global");
15485
+ if (baseDir)
15486
+ removeMatchingSkillDirs(baseDir, new Set(skillFilenames));
15487
+ }
15351
15488
  async cleanup(scope, manifest) {
15352
15489
  if (this.def.mcpConfigPath && scope === "user") {
15353
15490
  const resolved = resolvePlatformString(this.def.mcpConfigPath);
15354
15491
  if (resolved) {
15355
- const filePath = join31(homedir14(), resolved);
15492
+ const filePath = join33(homedir15(), resolved);
15356
15493
  removeRunworkMcpServers(filePath, this.def.mcpConfigKey || "mcpServers");
15357
15494
  }
15358
15495
  }
15359
- if (this.def.skillsPaths && manifest?.skillFilenames.length) {
15360
- const pathTemplate = scope === "project" ? this.def.skillsPaths.project : this.def.skillsPaths.global;
15361
- if (pathTemplate) {
15362
- const baseDir = resolveToAbsolute(pathTemplate, scope === "project" ? "project" : "global");
15363
- if (baseDir && existsSync37(baseDir)) {
15364
- const allowed = new Set(manifest.skillFilenames);
15365
- for (const entry of readdirSync12(baseDir)) {
15366
- if (!allowed.has(entry))
15367
- continue;
15368
- const entryPath = join31(baseDir, entry);
15369
- try {
15370
- rmSync11(entryPath, { recursive: true, force: true });
15371
- } catch {}
15372
- }
15373
- }
15374
- }
15375
- }
15496
+ await this.removeSkills(manifest?.skillFilenames ?? [], scope);
15376
15497
  if (this.def.instructionFile) {
15377
15498
  const pathTemplate = scope === "project" ? this.def.instructionFile.project : this.def.instructionFile.global;
15378
15499
  if (pathTemplate) {
@@ -15448,27 +15569,26 @@ function insightLocalKey(teaches, slug) {
15448
15569
  }
15449
15570
 
15450
15571
  // src/reflect/insight-store.ts
15451
- import { existsSync as existsSync38, mkdirSync as mkdirSync24, readFileSync as readFileSync29, writeFileSync as writeFileSync25 } from "fs";
15452
- import { join as join32 } from "path";
15453
- import { homedir as homedir15 } from "os";
15572
+ init_atomic_json();
15573
+ import { existsSync as existsSync41, readFileSync as readFileSync30 } from "fs";
15574
+ import { join as join34 } from "path";
15575
+ import { homedir as homedir16 } from "os";
15454
15576
  function storePath() {
15455
- return join32(homedir15(), ".runwork", "insights.json");
15577
+ return join34(homedir16(), ".runwork", "insights.json");
15456
15578
  }
15457
15579
  function readAll() {
15458
15580
  const path2 = storePath();
15459
- if (!existsSync38(path2))
15581
+ if (!existsSync41(path2))
15460
15582
  return {};
15461
15583
  try {
15462
- const parsed = JSON.parse(readFileSync29(path2, "utf-8"));
15584
+ const parsed = JSON.parse(readFileSync30(path2, "utf-8"));
15463
15585
  return parsed && typeof parsed === "object" ? parsed : {};
15464
15586
  } catch {
15465
15587
  return {};
15466
15588
  }
15467
15589
  }
15468
15590
  function writeAll(store) {
15469
- const path2 = storePath();
15470
- mkdirSync24(join32(homedir15(), ".runwork"), { recursive: true });
15471
- writeFileSync25(path2, JSON.stringify(store, null, 2));
15591
+ writeJsonAtomic(storePath(), store);
15472
15592
  }
15473
15593
  function notExpired(i, now) {
15474
15594
  const t = new Date(i.expiresAt).getTime();
@@ -15488,37 +15608,43 @@ function loadInsights(opts = {}) {
15488
15608
  const now = Date.now();
15489
15609
  return Object.values(readAll()).filter((i) => notExpired(i, now) && (!opts.workspaceId || i.workspaceId === opts.workspaceId)).sort((a, b) => (b.createdAt ?? "").localeCompare(a.createdAt ?? ""));
15490
15610
  }
15491
- function getInsight(id) {
15611
+ function getInsight(id, opts = {}) {
15492
15612
  const i = readAll()[id];
15493
- return i && notExpired(i, Date.now()) ? i : null;
15613
+ if (!i || !notExpired(i, Date.now()))
15614
+ return null;
15615
+ const allowed = (opts.workspaceIds ?? []).filter((w) => !!w);
15616
+ if (allowed.length && i.workspaceId && i.workspaceId !== "local" && !allowed.includes(i.workspaceId)) {
15617
+ return null;
15618
+ }
15619
+ return i;
15494
15620
  }
15495
15621
 
15496
15622
  // src/reflect/cadence.ts
15497
- import { existsSync as existsSync39, mkdirSync as mkdirSync25, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
15498
- import { join as join33 } from "path";
15499
- import { homedir as homedir16 } from "os";
15623
+ init_atomic_json();
15624
+ import { existsSync as existsSync42, readFileSync as readFileSync31 } from "fs";
15625
+ import { join as join35 } from "path";
15626
+ import { homedir as homedir17 } from "os";
15500
15627
  var DEFAULT_STATE = { enabled: false, lastReflectedAt: null };
15501
15628
  var COOLDOWN_HOURS = 20;
15502
15629
  var ACTIVE_SESSION_THRESHOLD = 10;
15503
15630
  var MAX_INTERVAL_HOURS = 7 * 24;
15504
15631
  var MIN_SESSIONS_FIRST_RUN = 3;
15505
15632
  function statePath() {
15506
- return join33(homedir16(), ".runwork", "reflect-state.json");
15633
+ return join35(homedir17(), ".runwork", "reflect-state.json");
15507
15634
  }
15508
15635
  function loadCadenceState() {
15509
15636
  try {
15510
15637
  const p = statePath();
15511
- if (!existsSync39(p))
15638
+ if (!existsSync42(p))
15512
15639
  return { ...DEFAULT_STATE };
15513
- const parsed = JSON.parse(readFileSync30(p, "utf-8"));
15640
+ const parsed = JSON.parse(readFileSync31(p, "utf-8"));
15514
15641
  return { ...DEFAULT_STATE, ...parsed && typeof parsed === "object" ? parsed : {} };
15515
15642
  } catch {
15516
15643
  return { ...DEFAULT_STATE };
15517
15644
  }
15518
15645
  }
15519
15646
  function saveCadenceState(state) {
15520
- mkdirSync25(join33(homedir16(), ".runwork"), { recursive: true });
15521
- writeFileSync26(statePath(), JSON.stringify(state, null, 2));
15647
+ writeJsonAtomic(statePath(), state);
15522
15648
  }
15523
15649
  function recordReflection(now = new Date) {
15524
15650
  saveCadenceState({ ...loadCadenceState(), lastReflectedAt: now.toISOString() });
@@ -15540,7 +15666,40 @@ function isReflectionDue(state, newSessionCount, now = new Date) {
15540
15666
  return hoursSince >= MAX_INTERVAL_HOURS;
15541
15667
  }
15542
15668
 
15669
+ // src/utils/workspace-state.ts
15670
+ init_atomic_json();
15671
+ import { join as join36 } from "path";
15672
+ import { homedir as homedir18 } from "os";
15673
+ function storePath2() {
15674
+ return join36(homedir18(), ".runwork", "workspaces.json");
15675
+ }
15676
+ function readFile() {
15677
+ const parsed = readJsonOrNull(storePath2());
15678
+ if (parsed && parsed.workspaces && typeof parsed.workspaces === "object")
15679
+ return parsed;
15680
+ return { workspaces: {} };
15681
+ }
15682
+ function loadWorkspaceRecord(workspaceId) {
15683
+ return readFile().workspaces[workspaceId] ?? {};
15684
+ }
15685
+ function updateWorkspaceRecord(workspaceId, patch) {
15686
+ if (!workspaceId)
15687
+ return;
15688
+ const file = readFile();
15689
+ file.workspaces[workspaceId] = { ...file.workspaces[workspaceId], ...patch };
15690
+ writeJsonAtomic(storePath2(), file);
15691
+ }
15692
+ function clearParkedState(workspaceId) {
15693
+ const file = readFile();
15694
+ const record = file.workspaces[workspaceId];
15695
+ if (!record?.parked)
15696
+ return;
15697
+ delete record.parked;
15698
+ writeJsonAtomic(storePath2(), file);
15699
+ }
15700
+
15543
15701
  // src/commands/reflect.ts
15702
+ init_atomic_json();
15544
15703
  init_colors();
15545
15704
  var MAX_NAMES = 40;
15546
15705
  function cap(names) {
@@ -15656,7 +15815,7 @@ function runAnalyst(binary, args, prompt, timeoutMs = ANALYST_TIMEOUT_MS) {
15656
15815
  }
15657
15816
  });
15658
15817
  }
15659
- function enrichInsights(evidence, userSeed) {
15818
+ function enrichInsights(evidence, userSeed, workspaceScope) {
15660
15819
  const insights = evidence?.insights;
15661
15820
  if (!Array.isArray(insights))
15662
15821
  return [];
@@ -15670,7 +15829,7 @@ function enrichInsights(evidence, userSeed) {
15670
15829
  if (!teaches || !slug)
15671
15830
  continue;
15672
15831
  items.push({
15673
- id: computeInsightId(userSeed, insightLocalKey(teaches, slug)),
15832
+ id: computeInsightId(userSeed, `${workspaceScope}:${insightLocalKey(teaches, slug)}`),
15674
15833
  source: "reflection",
15675
15834
  teaches,
15676
15835
  dimension: typeof r.dimension === "string" ? r.dimension : undefined,
@@ -15749,8 +15908,8 @@ var reflectCommand = new Command14("reflect").description("Weekly reflection: an
15749
15908
  const save = (file, content) => {
15750
15909
  if (!outDir)
15751
15910
  return;
15752
- mkdirSync26(outDir, { recursive: true });
15753
- writeFileSync27(join34(outDir, file), content);
15911
+ mkdirSync25(outDir, { recursive: true });
15912
+ writeFileSync25(join37(outDir, file), content);
15754
15913
  };
15755
15914
  const adapters = await detectAgents();
15756
15915
  const digests = [];
@@ -15808,14 +15967,23 @@ Skipping: ${cadence.enabled ? "not enough new work since the last reflection" :
15808
15967
  return;
15809
15968
  }
15810
15969
  }
15970
+ let client;
15971
+ let workspaceId;
15972
+ try {
15973
+ client = new ApiClient(requireAuth());
15974
+ workspaceId = (await resolveWorkspace2(client, {})).workspaceId;
15975
+ } catch {
15976
+ try {
15977
+ workspaceId = requireAuth().defaultWorkspaceId;
15978
+ } catch {}
15979
+ }
15811
15980
  {
15812
- let allowed = loadCadenceState().workspaceReflectionEnabled ?? true;
15981
+ const perWorkspace = workspaceId ? loadWorkspaceRecord(workspaceId).reflectionEnabled : undefined;
15982
+ let allowed = perWorkspace ?? loadCadenceState().workspaceReflectionEnabled ?? true;
15813
15983
  try {
15814
- const client = new ApiClient(requireAuth());
15815
- const { workspaceId } = await resolveWorkspace2(client, {});
15816
- if (workspaceId) {
15984
+ if (client && workspaceId) {
15817
15985
  allowed = (await client.getReflectionSetting(workspaceId)).reflectionEnabled;
15818
- saveCadenceState({ ...loadCadenceState(), workspaceReflectionEnabled: allowed });
15986
+ updateWorkspaceRecord(workspaceId, { reflectionEnabled: allowed });
15819
15987
  }
15820
15988
  } catch {}
15821
15989
  if (!allowed) {
@@ -15890,21 +16058,11 @@ Analyst failed: ${e instanceof Error ? e.message : String(e)}`));
15890
16058
  return "local";
15891
16059
  }
15892
16060
  })();
15893
- const items = evidence ? enrichInsights(evidence, userSeed) : [];
16061
+ const items = evidence ? enrichInsights(evidence, userSeed, workspaceId ?? "local") : [];
15894
16062
  if (evidence)
15895
16063
  save("evidence.json", JSON.stringify(evidence, null, 2));
15896
16064
  save("insights.json", JSON.stringify(items, null, 2));
15897
16065
  if (items.length > 0) {
15898
- let client;
15899
- let workspaceId;
15900
- try {
15901
- client = new ApiClient(requireAuth());
15902
- workspaceId = (await resolveWorkspace2(client, {})).workspaceId;
15903
- } catch {
15904
- try {
15905
- workspaceId = requireAuth().defaultWorkspaceId;
15906
- } catch {}
15907
- }
15908
16066
  const nowIso = new Date().toISOString();
15909
16067
  const expiresIso = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();
15910
16068
  saveInsights(items.map((it) => ({
@@ -15974,8 +16132,9 @@ reflectCommand.command("show [id]").description("Show reflection insights stored
15974
16132
  try {
15975
16133
  workspaceId = requireAuth().defaultWorkspaceId;
15976
16134
  } catch {}
16135
+ const projectWorkspaceId = readJsonOrNull(join37(process.cwd(), ".runwork.json"))?.workspaceId;
15977
16136
  if (id) {
15978
- const insight = getInsight(id);
16137
+ const insight = getInsight(id, { workspaceIds: [projectWorkspaceId, workspaceId] });
15979
16138
  if (!insight) {
15980
16139
  if (wantJson) {
15981
16140
  jsonOut({ error: "not-found", id });
@@ -16016,16 +16175,16 @@ import * as path3 from "node:path";
16016
16175
  init_prompt();
16017
16176
 
16018
16177
  // src/utils/data-input.ts
16019
- import { readFileSync as readFileSync31, existsSync as existsSync40 } from "fs";
16178
+ import { readFileSync as readFileSync32, existsSync as existsSync43 } from "fs";
16020
16179
  async function parseDataInput(dataFlag) {
16021
16180
  if (dataFlag) {
16022
16181
  if (dataFlag.startsWith("@")) {
16023
16182
  const filePath = dataFlag.slice(1);
16024
- if (!existsSync40(filePath)) {
16183
+ if (!existsSync43(filePath)) {
16025
16184
  console.error(`File not found: ${filePath}`);
16026
16185
  process.exit(1);
16027
16186
  }
16028
- const content = readFileSync31(filePath, "utf-8");
16187
+ const content = readFileSync32(filePath, "utf-8");
16029
16188
  return parseJson(content, filePath);
16030
16189
  }
16031
16190
  return parseJson(dataFlag, "--data");
@@ -16165,6 +16324,9 @@ function resolveExportTargets(entities, filter) {
16165
16324
  }
16166
16325
  return { targets };
16167
16326
  }
16327
+ function classifyExportError(message) {
16328
+ return message.includes("not deployed to production") ? "not_deployed" : "error";
16329
+ }
16168
16330
  function appSlugForPath(appName, appId) {
16169
16331
  const slug = appName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
16170
16332
  return slug || appId;
@@ -16454,22 +16616,49 @@ var exportCommand = new Command15("export").description("Export entity data to l
16454
16616
  }
16455
16617
  const results = [];
16456
16618
  for (const target of targets) {
16457
- results.push(await exportOneApp(client, workspaceId, target, {
16458
- format,
16459
- entityName: entity,
16460
- wait: opts.wait !== false,
16461
- outputRoot: opts.output,
16462
- quiet: useJson
16463
- }));
16619
+ try {
16620
+ results.push(await exportOneApp(client, workspaceId, target, {
16621
+ format,
16622
+ entityName: entity,
16623
+ wait: opts.wait !== false,
16624
+ outputRoot: opts.output,
16625
+ quiet: useJson
16626
+ }));
16627
+ } catch (err) {
16628
+ const message = err instanceof Error ? err.message : String(err);
16629
+ const kind = classifyExportError(message);
16630
+ const status = kind === "not_deployed" ? "skipped" : "failed";
16631
+ if (!useJson) {
16632
+ console.error(kind === "not_deployed" ? `${target.appName}: skipped (not deployed to production)` : `${target.appName}: failed: ${message}`);
16633
+ }
16634
+ results.push({
16635
+ appId: target.appId,
16636
+ appName: target.appName,
16637
+ jobId: "",
16638
+ status,
16639
+ records: 0,
16640
+ sizeBytes: 0,
16641
+ outputDir: null,
16642
+ files: [],
16643
+ error: message
16644
+ });
16645
+ }
16464
16646
  }
16465
16647
  if (useJson) {
16466
16648
  jsonOut({ exports: results });
16467
16649
  return;
16468
16650
  }
16651
+ const exported = results.filter((r) => r.status === "completed");
16652
+ const skipped = results.filter((r) => r.status === "skipped");
16469
16653
  const failed = results.filter((r) => r.status === "failed");
16470
- if (failed.length > 0) {
16471
- console.error(`
16472
- ${failed.length} export(s) failed.`);
16654
+ const summary = [`${exported.length} app(s) exported`];
16655
+ if (skipped.length > 0)
16656
+ summary.push(`${skipped.length} skipped (not deployed)`);
16657
+ if (failed.length > 0)
16658
+ summary.push(`${failed.length} failed`);
16659
+ console.log(`
16660
+ ${summary.join(", ")}.`);
16661
+ if (failed.length > 0 || opts.app && skipped.length > 0) {
16473
16662
  process.exit(1);
16474
16663
  }
16475
16664
  } catch (err) {
@@ -17010,8 +17199,8 @@ var endpointsCommand = new Command18("endpoints").alias("routes").description("M
17010
17199
  init_store();
17011
17200
  init_client();
17012
17201
  import { Command as Command19 } from "commander";
17013
- import { writeFileSync as writeFileSync29, readFileSync as readFileSync32 } from "fs";
17014
- import { basename as basename2 } from "path";
17202
+ import { writeFileSync as writeFileSync27, readFileSync as readFileSync33 } from "fs";
17203
+ import { basename as basename3 } from "path";
17015
17204
  init_prompt();
17016
17205
  init_http();
17017
17206
  function formatSize(bytes) {
@@ -17097,14 +17286,14 @@ var downloadCommand = new Command19("download").description("Download a file fro
17097
17286
  const credentials = requireAuth();
17098
17287
  const client = new ApiClient(credentials);
17099
17288
  const { workspaceId } = await resolveWorkspace2(client, opts);
17100
- const outputPath = output || basename2(key);
17289
+ const outputPath = output || basename3(key);
17101
17290
  try {
17102
17291
  const { url } = await client.getPresignedUrl(workspaceId, bucket, { action: "read", key });
17103
17292
  const response = await httpFetch(url);
17104
17293
  if (!response.ok) {
17105
17294
  throw new Error(`Download failed: ${response.status} ${response.statusText}`);
17106
17295
  }
17107
- writeFileSync29(outputPath, Buffer.from(await response.arrayBuffer()));
17296
+ writeFileSync27(outputPath, Buffer.from(await response.arrayBuffer()));
17108
17297
  if (useJson) {
17109
17298
  jsonOut({ success: true, bucket, key, outputPath });
17110
17299
  return;
@@ -17120,9 +17309,9 @@ var uploadCommand = new Command19("upload").description("Upload a local file to
17120
17309
  const credentials = requireAuth();
17121
17310
  const client = new ApiClient(credentials);
17122
17311
  const { workspaceId } = await resolveWorkspace2(client, opts);
17123
- const objectKey = key || basename2(localPath);
17312
+ const objectKey = key || basename3(localPath);
17124
17313
  try {
17125
- const fileBuffer = readFileSync32(localPath);
17314
+ const fileBuffer = readFileSync33(localPath);
17126
17315
  const { url } = await client.getPresignedUrl(workspaceId, bucket, { action: "write", key: objectKey });
17127
17316
  const response = await httpFetch(url, { method: "PUT", body: fileBuffer });
17128
17317
  if (!response.ok) {
@@ -17618,21 +17807,21 @@ function truncateUrl(url, max) {
17618
17807
  var mcpCommand = new Command23("mcp").description("Manage workspace MCP servers").addCommand(listCommand11).addCommand(addCommand).addCommand(removeCommand).addCommand(searchCommand3).addCommand(installCommand2);
17619
17808
 
17620
17809
  // src/commands/setup.ts
17810
+ init_atomic_json();
17621
17811
  init_store();
17622
17812
  init_client();
17623
17813
  import { Command as Command25 } from "commander";
17624
- import { writeFileSync as writeFileSync31, mkdirSync as mkdirSync28 } from "fs";
17625
- import { join as join39 } from "path";
17626
- import { homedir as homedir19 } from "os";
17814
+ import { join as join41 } from "path";
17815
+ import { homedir as homedir20 } from "os";
17627
17816
  init_prompt();
17628
17817
 
17629
17818
  // src/commands/sync.ts
17630
17819
  init_store();
17631
17820
  init_client();
17632
17821
  import { Command as Command24 } from "commander";
17633
- import { readFileSync as readFileSync33, writeFileSync as writeFileSync30, existsSync as existsSync42 } from "fs";
17634
- import { join as join37 } from "path";
17635
- import { homedir as homedir17 } from "os";
17822
+ import { readFileSync as readFileSync34, existsSync as existsSync45 } from "fs";
17823
+ import { join as join40 } from "path";
17824
+ import { homedir as homedir19 } from "os";
17636
17825
 
17637
17826
  // src/commands/mcp-entries.ts
17638
17827
  function buildExternalMcpEntries(mcpServers, resolvedCredentials) {
@@ -18610,6 +18799,9 @@ function computeSyncPlan(input) {
18610
18799
  return plan;
18611
18800
  }
18612
18801
 
18802
+ // src/commands/sync.ts
18803
+ init_atomic_json();
18804
+
18613
18805
  // src/sync/conflict-ui.ts
18614
18806
  init_prompt();
18615
18807
  init_colors();
@@ -18796,8 +18988,20 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
18796
18988
  }
18797
18989
  }
18798
18990
  for (const _action of plan.skips) {}
18799
- for (const action of plan.deletions) {
18800
- vlog(` Deleted locally: ${action.name}`);
18991
+ const deletionSlugs = plan.deletions.map((action) => toSlug(action.name));
18992
+ if (deletionSlugs.length) {
18993
+ for (const adapter2 of ctx.adapters) {
18994
+ if (!adapter2.supportsSkills() || !adapter2.removeSkills)
18995
+ continue;
18996
+ for (const scope of ctx.scopes) {
18997
+ try {
18998
+ await adapter2.removeSkills(deletionSlugs, scope);
18999
+ } catch {}
19000
+ }
19001
+ }
19002
+ for (const action of plan.deletions) {
19003
+ vlog(` Deleted locally: ${action.name}`);
19004
+ }
18801
19005
  }
18802
19006
  return newHashes;
18803
19007
  }
@@ -18890,10 +19094,10 @@ Tip: ${hint.title}`);
18890
19094
  } catch {}
18891
19095
  }
18892
19096
  function loadSetupState(filePath) {
18893
- if (!existsSync42(filePath))
19097
+ if (!existsSync45(filePath))
18894
19098
  return null;
18895
19099
  try {
18896
- return JSON.parse(readFileSync33(filePath, "utf-8"));
19100
+ return JSON.parse(readFileSync34(filePath, "utf-8"));
18897
19101
  } catch {
18898
19102
  return null;
18899
19103
  }
@@ -18914,15 +19118,15 @@ function readLocalSkills(state) {
18914
19118
  if (!baseDir)
18915
19119
  continue;
18916
19120
  for (const skillName of state.skills) {
18917
- const skillMdPath = join37(baseDir, skillName, "SKILL.md");
18918
- if (existsSync42(skillMdPath)) {
18919
- results.push({ name: skillName, content: readFileSync33(skillMdPath, "utf-8") });
19121
+ const skillMdPath = join40(baseDir, skillName, "SKILL.md");
19122
+ if (existsSync45(skillMdPath)) {
19123
+ results.push({ name: skillName, content: readFileSync34(skillMdPath, "utf-8") });
18920
19124
  continue;
18921
19125
  }
18922
19126
  const filename = skillName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
18923
- const flatPath = join37(baseDir, `${filename}.md`);
18924
- if (existsSync42(flatPath)) {
18925
- results.push({ name: skillName, content: readFileSync33(flatPath, "utf-8") });
19127
+ const flatPath = join40(baseDir, `${filename}.md`);
19128
+ if (existsSync45(flatPath)) {
19129
+ results.push({ name: skillName, content: readFileSync34(flatPath, "utf-8") });
18926
19130
  }
18927
19131
  }
18928
19132
  if (results.length > 0)
@@ -19126,9 +19330,9 @@ async function syncFromState(state, statePath2, credentials, opts) {
19126
19330
  persona: state.persona
19127
19331
  });
19128
19332
  let projectAppSkillFilter = null;
19129
- if (existsSync42(".runwork.json")) {
19333
+ if (existsSync45(".runwork.json")) {
19130
19334
  try {
19131
- const config = JSON.parse(readFileSync33(".runwork.json", "utf-8"));
19335
+ const config = JSON.parse(readFileSync34(".runwork.json", "utf-8"));
19132
19336
  if (config.appName) {
19133
19337
  projectAppSkillFilter = config.appName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
19134
19338
  }
@@ -19365,7 +19569,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
19365
19569
  }
19366
19570
  for (const adapter2 of adapters) {
19367
19571
  if (adapter2 instanceof CodexAdapter) {
19368
- const runworkDir = join37(homedir17(), ".runwork");
19572
+ const runworkDir = join40(homedir19(), ".runwork");
19369
19573
  const result = adapter2.registerDesktopWorkspace(runworkDir, "Runwork");
19370
19574
  if (result === "written") {
19371
19575
  vlog(` [${adapter2.name}] Registered workspace in Codex desktop app`);
@@ -19440,7 +19644,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
19440
19644
  delete mergedHashes[del.name];
19441
19645
  }
19442
19646
  state.skillHashes = mergedHashes;
19443
- writeFileSync30(statePath2, JSON.stringify(state, null, 2));
19647
+ writeJsonAtomic(statePath2, state);
19444
19648
  try {
19445
19649
  const telemetryNow = new Date().toISOString();
19446
19650
  const telemetry = await collectTelemetryEvents({
@@ -19460,7 +19664,13 @@ async function syncFromState(state, statePath2, credentials, opts) {
19460
19664
  if (telemetry.healthReported) {
19461
19665
  state.lastHealthReportAt = new Date().toISOString();
19462
19666
  }
19463
- writeFileSync30(statePath2, JSON.stringify(state, null, 2));
19667
+ writeJsonAtomic(statePath2, state);
19668
+ updateWorkspaceRecord(state.workspaceId, {
19669
+ workspaceName: state.workspaceName || undefined,
19670
+ workspaceSlug: state.workspaceSlug,
19671
+ lastTelemetryAt: state.lastTelemetryAt,
19672
+ lastHealthReportAt: state.lastHealthReportAt
19673
+ });
19464
19674
  } catch {}
19465
19675
  const failedNote = summary.adaptersFailed > 0 ? ` (${summary.adaptersFailed} failed)` : "";
19466
19676
  if (isVerbose()) {
@@ -19498,8 +19708,8 @@ var syncCommand = new Command24("sync").description("Sync skills bidirectionally
19498
19708
  verbose: !!opts.verbose,
19499
19709
  redetect: !!opts.redetect
19500
19710
  };
19501
- const projectStatePath = join37(process.cwd(), ".runwork", "setup.json");
19502
- const userStatePath = join37(homedir17(), ".runwork", "setup.json");
19711
+ const projectStatePath = join40(process.cwd(), ".runwork", "setup.json");
19712
+ const userStatePath = join40(homedir19(), ".runwork", "setup.json");
19503
19713
  const projectState = loadSetupState(projectStatePath);
19504
19714
  const userState = loadSetupState(userStatePath);
19505
19715
  if (!projectState && !userState) {
@@ -19519,25 +19729,6 @@ Sync complete.`);
19519
19729
  }
19520
19730
  });
19521
19731
 
19522
- // src/utils/setup-state.ts
19523
- import { existsSync as existsSync43, readFileSync as readFileSync34 } from "fs";
19524
- import { join as join38 } from "path";
19525
- import { homedir as homedir18 } from "os";
19526
- function loadSetupState2() {
19527
- const projectPath = join38(process.cwd(), ".runwork", "setup.json");
19528
- const userPath = join38(homedir18(), ".runwork", "setup.json");
19529
- for (const p of [projectPath, userPath]) {
19530
- if (existsSync43(p)) {
19531
- try {
19532
- return JSON.parse(readFileSync34(p, "utf-8"));
19533
- } catch {
19534
- continue;
19535
- }
19536
- }
19537
- }
19538
- return null;
19539
- }
19540
-
19541
19732
  // src/commands/setup.ts
19542
19733
  var PERSONA_LABELS = {
19543
19734
  1: "everyday",
@@ -19553,7 +19744,7 @@ function resolvePersona(flag, existing) {
19553
19744
  }
19554
19745
  return existing;
19555
19746
  }
19556
- async function resolveAndPersistWorkspace(client, opts) {
19747
+ async function resolveSetupWorkspace(client, opts) {
19557
19748
  const resolved = await resolveWorkspace2(client, opts);
19558
19749
  const { workspaceId } = resolved;
19559
19750
  let allWorkspaces = [];
@@ -19565,29 +19756,89 @@ async function resolveAndPersistWorkspace(client, opts) {
19565
19756
  console.error(`Workspace "${opts.workspace}" not found or not accessible.`);
19566
19757
  process.exit(1);
19567
19758
  }
19568
- const workspaceName = resolved.workspaceName || workspaceMeta?.name || "";
19569
- const workspaceSlug = workspaceMeta?.slug;
19759
+ return {
19760
+ workspaceId,
19761
+ workspaceName: resolved.workspaceName || workspaceMeta?.name || "",
19762
+ workspaceSlug: workspaceMeta?.slug
19763
+ };
19764
+ }
19765
+ function persistDefaultWorkspace(workspaceId, workspaceName) {
19570
19766
  const freshCreds = getCredentials();
19571
- if (freshCreds) {
19572
- saveCredentials({
19573
- ...freshCreds,
19574
- defaultWorkspaceId: workspaceId,
19575
- defaultWorkspaceName: workspaceName
19576
- });
19767
+ if (!freshCreds)
19768
+ return;
19769
+ saveCredentials({
19770
+ ...freshCreds,
19771
+ defaultWorkspaceId: workspaceId,
19772
+ defaultWorkspaceName: workspaceName
19773
+ });
19774
+ }
19775
+ function toSkillFilename(name) {
19776
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
19777
+ }
19778
+ function loadSetupStateForScope(scope) {
19779
+ const path4 = scope === "project" ? join41(process.cwd(), ".runwork", "setup.json") : join41(homedir20(), ".runwork", "setup.json");
19780
+ return readJsonOrNull(path4);
19781
+ }
19782
+ async function parkAndTeardownWorkspace(previous, scopes) {
19783
+ const cleanupScopes = scopes ?? (previous.scope === "both" ? ["project", "user"] : [previous.scope ?? "user"]);
19784
+ const skillFilenames = previous.skillFilenames ?? (previous.skills ?? []).map(toSkillFilename);
19785
+ const patch = {
19786
+ parked: {
19787
+ skillFilenames,
19788
+ mcpServers: previous.mcpServers ?? [],
19789
+ agentDefaults: previous.agentDefaults,
19790
+ agentDefaultsVersion: previous.agentDefaultsVersion,
19791
+ parkedAt: new Date().toISOString()
19792
+ }
19793
+ };
19794
+ if (previous.workspaceName)
19795
+ patch.workspaceName = previous.workspaceName;
19796
+ if (previous.workspaceSlug)
19797
+ patch.workspaceSlug = previous.workspaceSlug;
19798
+ if (previous.lastTelemetryAt)
19799
+ patch.lastTelemetryAt = previous.lastTelemetryAt;
19800
+ if (previous.lastHealthReportAt)
19801
+ patch.lastHealthReportAt = previous.lastHealthReportAt;
19802
+ updateWorkspaceRecord(previous.workspaceId, patch);
19803
+ const manifest = {
19804
+ skillFilenames,
19805
+ mcpServerNames: previous.mcpServers ?? []
19806
+ };
19807
+ for (const slug of previous.configuredAgents ?? []) {
19808
+ const adapter2 = getAdapterBySlug(slug);
19809
+ if (!adapter2?.cleanup)
19810
+ continue;
19811
+ for (const scope of cleanupScopes) {
19812
+ try {
19813
+ await adapter2.cleanup(scope, manifest);
19814
+ console.log(` [${adapter2.name}] Previous workspace removed (${scope})`);
19815
+ } catch (err) {
19816
+ console.warn(` [${adapter2.name}] Cleanup failed (${scope}): ${err instanceof Error ? err.message : err}`);
19817
+ }
19818
+ }
19819
+ }
19820
+ }
19821
+ function resolveTelemetryCursor(carry, targetRecord, now = new Date) {
19822
+ if (carry?.lastTelemetryAt)
19823
+ return carry.lastTelemetryAt;
19824
+ const watermark = targetRecord.lastTelemetryAt;
19825
+ const parkedAt = targetRecord.parked?.parkedAt;
19826
+ if (watermark && parkedAt) {
19827
+ return Date.parse(parkedAt) > Date.parse(watermark) ? parkedAt : watermark;
19577
19828
  }
19578
- return { workspaceId, workspaceName, workspaceSlug };
19829
+ return parkedAt ?? watermark ?? now.toISOString();
19579
19830
  }
19580
- var setupCommand = new Command25("setup").description("Configure local AI agents with workspace skills and MCP servers").option("--workspace <name-or-id>", "Workspace name or ID").option("--agent <slug>", "Only configure a specific agent (e.g. claude-code, cursor)").option("--dry-run", "Show what would be configured without writing files").option("-y, --yes", "Skip all prompts, configure all detected agents with user scope").option("--persona <level>", "Technical-level persona for agent instructions (1=everyday, 2=curious, 3=engineer)").action(async (opts) => {
19831
+ async function runSetup(opts) {
19581
19832
  const credentials = requireAuth();
19582
19833
  const client = new ApiClient(credentials);
19583
- const { workspaceId, workspaceName, workspaceSlug } = await resolveAndPersistWorkspace(client, opts);
19834
+ const { workspaceId, workspaceName, workspaceSlug } = await resolveSetupWorkspace(client, opts);
19584
19835
  console.log(`
19585
19836
  Workspace: ${workspaceName || workspaceId}
19586
19837
  `);
19587
19838
  let agents = await detectAgents();
19588
19839
  if (agents.length === 0) {
19589
19840
  printNoAgentsMessage();
19590
- process.exit(0);
19841
+ process.exit(1);
19591
19842
  }
19592
19843
  if (opts.agent) {
19593
19844
  agents = agents.filter((a) => a.slug === opts.agent);
@@ -19619,8 +19870,8 @@ Configuring all agents (--yes).
19619
19870
  }
19620
19871
  agents = kept;
19621
19872
  if (agents.length === 0) {
19622
- console.log("No agents selected.");
19623
- return;
19873
+ console.log("No agents selected. Nothing was changed.");
19874
+ process.exit(1);
19624
19875
  }
19625
19876
  }
19626
19877
  }
@@ -19634,6 +19885,37 @@ Configuring all agents (--yes).
19634
19885
  const chosen = await promptSelect("Configure for:", scopeChoices);
19635
19886
  scope = chosen.value;
19636
19887
  }
19888
+ const scopes = scope === "both" ? ["project", "user"] : [scope];
19889
+ const outgoing = new Map;
19890
+ for (const s of scopes) {
19891
+ const prior = loadSetupStateForScope(s);
19892
+ if (prior?.workspaceId && prior.workspaceId !== workspaceId) {
19893
+ outgoing.set(s, prior);
19894
+ }
19895
+ }
19896
+ const previous = loadSetupStateForScope(scopes.includes("user") ? "user" : "project");
19897
+ const isSwitch = outgoing.size > 0;
19898
+ if (isSwitch && !opts.dryRun) {
19899
+ const names = [...new Set([...outgoing.values()].map((p) => p.workspaceName || p.workspaceId))];
19900
+ console.log(`Switching workspace: ${names.join(", ")} -> ${workspaceName || workspaceId}`);
19901
+ console.log(`Removing the previous workspace's skills and connections from your AI tools...
19902
+ `);
19903
+ for (const [s, prior] of outgoing) {
19904
+ await parkAndTeardownWorkspace(prior, [s]);
19905
+ }
19906
+ const trashed = currentTrashBatch();
19907
+ if (trashed) {
19908
+ console.log(` A copy of everything removed is kept for ${TRASH_RETENTION_DAYS} days in:`);
19909
+ console.log(` ${trashed}`);
19910
+ }
19911
+ console.log("");
19912
+ } else if (isSwitch && opts.dryRun) {
19913
+ const names = [...new Set([...outgoing.values()].map((p) => p.workspaceName || p.workspaceId))];
19914
+ console.log(`[Dry run] Would switch workspace: ${names.join(", ")} -> ${workspaceName || workspaceId} (teardown + re-setup).`);
19915
+ }
19916
+ const carry = !isSwitch && previous?.workspaceId === workspaceId ? previous : undefined;
19917
+ const targetRecord = loadWorkspaceRecord(workspaceId);
19918
+ const restored = carry ? undefined : targetRecord.parked;
19637
19919
  const state = {
19638
19920
  workspaceId,
19639
19921
  workspaceName: workspaceName || "",
@@ -19643,19 +19925,17 @@ Configuring all agents (--yes).
19643
19925
  lastSyncAt: "",
19644
19926
  mcpServers: [],
19645
19927
  skills: [],
19646
- skillHashes: {},
19928
+ skillHashes: carry?.skillHashes ?? {},
19929
+ agentDefaults: carry?.agentDefaults ?? restored?.agentDefaults,
19930
+ agentDefaultsVersion: carry?.agentDefaultsVersion ?? restored?.agentDefaultsVersion,
19931
+ lastTelemetryAt: resolveTelemetryCursor(carry, targetRecord),
19932
+ lastHealthReportAt: carry?.lastHealthReportAt ?? targetRecord.lastHealthReportAt,
19647
19933
  lastDetectedAt: new Date().toISOString(),
19648
- persona: resolvePersona(opts.persona, loadSetupState2()?.persona)
19934
+ persona: resolvePersona(opts.persona, previous?.persona)
19649
19935
  };
19650
- const scopes = scope === "both" ? ["project", "user"] : [scope];
19651
- for (const s of scopes) {
19652
- const dir = s === "project" ? ".runwork" : join39(homedir19(), ".runwork");
19653
- mkdirSync28(dir, { recursive: true });
19654
- writeFileSync31(join39(dir, "setup.json"), JSON.stringify(state, null, 2));
19655
- }
19656
19936
  if (opts.dryRun) {
19657
19937
  console.log(`
19658
- [Dry run] Saved setup state. Would sync:
19938
+ [Dry run] Nothing written. Would save setup state and sync:
19659
19939
  `);
19660
19940
  console.log(` Agents: ${agents.map((a) => a.name).join(", ")}`);
19661
19941
  console.log(` Scope: ${scope}`);
@@ -19663,11 +19943,18 @@ Configuring all agents (--yes).
19663
19943
  Re-run without --dry-run to sync workspace data.`);
19664
19944
  return;
19665
19945
  }
19946
+ persistDefaultWorkspace(workspaceId, workspaceName);
19947
+ for (const s of scopes) {
19948
+ const dir = s === "project" ? ".runwork" : join41(homedir20(), ".runwork");
19949
+ writeJsonAtomic(join41(dir, "setup.json"), state);
19950
+ }
19951
+ if (restored)
19952
+ clearParkedState(workspaceId);
19666
19953
  console.log(`
19667
19954
  Syncing workspace data...
19668
19955
  `);
19669
19956
  for (const s of scopes) {
19670
- const statePath2 = s === "project" ? join39(process.cwd(), ".runwork", "setup.json") : join39(homedir19(), ".runwork", "setup.json");
19957
+ const statePath2 = s === "project" ? join41(process.cwd(), ".runwork", "setup.json") : join41(homedir20(), ".runwork", "setup.json");
19671
19958
  await syncFromState(state, statePath2, credentials, {
19672
19959
  dryRun: false,
19673
19960
  pullOnly: true,
@@ -19678,25 +19965,94 @@ Syncing workspace data...
19678
19965
  }
19679
19966
  console.log("\nSetup complete. Run `runwork sync` anytime to refresh.");
19680
19967
  await printAdoptionHint(credentials, workspaceId);
19968
+ }
19969
+ var setupCommand = new Command25("setup").description("Configure local AI agents with workspace skills and MCP servers").option("--workspace <name-or-id>", "Workspace name or ID").option("--agent <slug>", "Only configure a specific agent (e.g. claude-code, cursor)").option("--dry-run", "Show what would be configured without writing files").option("-y, --yes", "Skip all prompts, configure all detected agents with user scope").option("--persona <level>", "Technical-level persona for agent instructions (1=everyday, 2=curious, 3=engineer)").action(async (opts) => runSetup(opts));
19970
+
19971
+ // src/commands/workspace.ts
19972
+ init_store();
19973
+ init_client();
19974
+ import { Command as Command26 } from "commander";
19975
+
19976
+ // src/utils/setup-state.ts
19977
+ import { existsSync as existsSync46, readFileSync as readFileSync35 } from "fs";
19978
+ import { join as join42 } from "path";
19979
+ import { homedir as homedir21 } from "os";
19980
+ function loadSetupState2() {
19981
+ const projectPath = join42(process.cwd(), ".runwork", "setup.json");
19982
+ const userPath = join42(homedir21(), ".runwork", "setup.json");
19983
+ for (const p of [projectPath, userPath]) {
19984
+ if (existsSync46(p)) {
19985
+ try {
19986
+ return JSON.parse(readFileSync35(p, "utf-8"));
19987
+ } catch {
19988
+ continue;
19989
+ }
19990
+ }
19991
+ }
19992
+ return null;
19993
+ }
19994
+
19995
+ // src/commands/workspace.ts
19996
+ var workspaceCommand = new Command26("workspace").description("Inspect or switch the workspace this machine is set up for");
19997
+ workspaceCommand.command("list").description("List workspaces you belong to (the active one is marked)").action(async (_opts, command) => {
19998
+ const json = command.optsWithGlobals().json === true;
19999
+ const credentials = requireAuth();
20000
+ const client = new ApiClient(credentials);
20001
+ const workspaces = await client.listWorkspaces();
20002
+ const activeId = loadSetupState2()?.workspaceId ?? credentials.defaultWorkspaceId;
20003
+ if (json) {
20004
+ jsonOut({
20005
+ workspaces: workspaces.map((w) => ({ id: w.id, name: w.name, slug: w.slug, active: w.id === activeId }))
20006
+ });
20007
+ return;
20008
+ }
20009
+ if (workspaces.length === 0) {
20010
+ console.log("No workspaces found for this account.");
20011
+ return;
20012
+ }
20013
+ for (const w of workspaces) {
20014
+ const marker = w.id === activeId ? "*" : " ";
20015
+ console.log(` ${marker} ${w.name} (${w.id})`);
20016
+ }
20017
+ console.log("\n* = active on this machine. Switch with `runwork workspace switch <name-or-id>`.");
20018
+ });
20019
+ workspaceCommand.command("current").description("Show the workspace this machine is currently set up for").action(async (_opts, command) => {
20020
+ const json = command.optsWithGlobals().json === true;
20021
+ const state = loadSetupState2();
20022
+ const credentials = requireAuth();
20023
+ const workspaceId = state?.workspaceId ?? credentials.defaultWorkspaceId ?? null;
20024
+ const workspaceName = state?.workspaceName || credentials.defaultWorkspaceName || null;
20025
+ if (json) {
20026
+ jsonOut({ workspaceId, workspaceName, source: state?.workspaceId ? "setup" : "credentials" });
20027
+ return;
20028
+ }
20029
+ if (!workspaceId) {
20030
+ console.log("This machine is not set up for a workspace yet. Run `runwork setup`.");
20031
+ return;
20032
+ }
20033
+ console.log(`${workspaceName || workspaceId} (${workspaceId})`);
20034
+ });
20035
+ workspaceCommand.command("switch <name-or-id>").description("Re-setup this machine for another workspace (removes the current workspace's skills and connections from your AI tools, then sets up the new one)").option("--persona <level>", "Technical-level persona for agent instructions (1=everyday, 2=curious, 3=engineer)").action(async (target, opts) => {
20036
+ await runSetup({ workspace: target, yes: true, persona: opts.persona });
19681
20037
  });
19682
20038
 
19683
20039
  // src/commands/build-plugin.ts
19684
20040
  init_store();
19685
20041
  init_client();
19686
- import { Command as Command26 } from "commander";
19687
- import { existsSync as existsSync44, readFileSync as readFileSync35 } from "fs";
19688
- import { resolve as resolve3, join as join40 } from "path";
19689
- import { homedir as homedir20 } from "os";
20042
+ import { Command as Command27 } from "commander";
20043
+ import { existsSync as existsSync47, readFileSync as readFileSync36 } from "fs";
20044
+ import { resolve as resolve3, join as join43 } from "path";
20045
+ import { homedir as homedir22 } from "os";
19690
20046
  function loadSetupState3(filePath) {
19691
- if (!existsSync44(filePath))
20047
+ if (!existsSync47(filePath))
19692
20048
  return null;
19693
20049
  try {
19694
- return JSON.parse(readFileSync35(filePath, "utf-8"));
20050
+ return JSON.parse(readFileSync36(filePath, "utf-8"));
19695
20051
  } catch {
19696
20052
  return null;
19697
20053
  }
19698
20054
  }
19699
- var buildPluginCommand = new Command26("build-plugin").description("Build an installable plugin archive for an agent (e.g. Claude Desktop)").requiredOption("--agent <slug>", "Target agent slug (e.g. claude-desktop)").option("--output <path>", "Output zip path", "runwork-plugin.zip").action(async (opts) => {
20055
+ var buildPluginCommand = new Command27("build-plugin").description("Build an installable plugin archive for an agent (e.g. Claude Desktop)").requiredOption("--agent <slug>", "Target agent slug (e.g. claude-desktop)").option("--output <path>", "Output zip path", "runwork-plugin.zip").action(async (opts) => {
19700
20056
  const adapter2 = getAdapterBySlug(opts.agent);
19701
20057
  if (!adapter2) {
19702
20058
  console.error(`Unknown agent: ${opts.agent}`);
@@ -19707,8 +20063,8 @@ var buildPluginCommand = new Command26("build-plugin").description("Build an ins
19707
20063
  process.exit(1);
19708
20064
  }
19709
20065
  const credentials = requireAuth();
19710
- const projectStatePath = join40(process.cwd(), ".runwork", "setup.json");
19711
- const userStatePath = join40(homedir20(), ".runwork", "setup.json");
20066
+ const projectStatePath = join43(process.cwd(), ".runwork", "setup.json");
20067
+ const userStatePath = join43(homedir22(), ".runwork", "setup.json");
19712
20068
  const state = loadSetupState3(projectStatePath) ?? loadSetupState3(userStatePath);
19713
20069
  if (!state) {
19714
20070
  console.error("No setup state found. Run `runwork setup` first.");
@@ -19797,23 +20153,23 @@ var buildPluginCommand = new Command26("build-plugin").description("Build an ins
19797
20153
  });
19798
20154
 
19799
20155
  // src/commands/uninstall.ts
19800
- import { Command as Command27 } from "commander";
19801
- import { existsSync as existsSync45, readFileSync as readFileSync36, rmSync as rmSync12, unlinkSync as unlinkSync7 } from "fs";
19802
- import { join as join41 } from "path";
19803
- import { homedir as homedir21 } from "os";
20156
+ import { Command as Command28 } from "commander";
20157
+ import { existsSync as existsSync48, readFileSync as readFileSync37, rmSync as rmSync13, unlinkSync as unlinkSync7 } from "fs";
20158
+ import { join as join44 } from "path";
20159
+ import { homedir as homedir23 } from "os";
19804
20160
  init_prompt();
19805
20161
  function loadSetupState4(filePath) {
19806
- if (!existsSync45(filePath))
20162
+ if (!existsSync48(filePath))
19807
20163
  return null;
19808
20164
  try {
19809
- return JSON.parse(readFileSync36(filePath, "utf-8"));
20165
+ return JSON.parse(readFileSync37(filePath, "utf-8"));
19810
20166
  } catch {
19811
20167
  return null;
19812
20168
  }
19813
20169
  }
19814
- var uninstallCommand = new Command27("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) => {
19815
- const projectStatePath = join41(process.cwd(), ".runwork", "setup.json");
19816
- const userStatePath = join41(homedir21(), ".runwork", "setup.json");
20170
+ var uninstallCommand = new Command28("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) => {
20171
+ const projectStatePath = join44(process.cwd(), ".runwork", "setup.json");
20172
+ const userStatePath = join44(homedir23(), ".runwork", "setup.json");
19817
20173
  const projectState = loadSetupState4(projectStatePath);
19818
20174
  const userState = loadSetupState4(userStatePath);
19819
20175
  if (!projectState && !userState) {
@@ -19893,10 +20249,10 @@ This will remove all Runwork configuration from your local agents:
19893
20249
  }
19894
20250
  }
19895
20251
  }
19896
- const stateDir = label === "project" ? join41(process.cwd(), ".runwork") : join41(homedir21(), ".runwork");
20252
+ const stateDir = label === "project" ? join44(process.cwd(), ".runwork") : join44(homedir23(), ".runwork");
19897
20253
  if (opts.keepAuth && label === "user") {
19898
- const setupFile = join41(stateDir, "setup.json");
19899
- if (existsSync45(setupFile)) {
20254
+ const setupFile = join44(stateDir, "setup.json");
20255
+ if (existsSync48(setupFile)) {
19900
20256
  try {
19901
20257
  unlinkSync7(setupFile);
19902
20258
  console.log(` Removed ${setupFile} (kept credentials)`);
@@ -19905,9 +20261,9 @@ This will remove all Runwork configuration from your local agents:
19905
20261
  errors++;
19906
20262
  }
19907
20263
  }
19908
- } else if (existsSync45(stateDir)) {
20264
+ } else if (existsSync48(stateDir)) {
19909
20265
  try {
19910
- rmSync12(stateDir, { recursive: true, force: true });
20266
+ rmSync13(stateDir, { recursive: true, force: true });
19911
20267
  console.log(` Removed ${stateDir}`);
19912
20268
  } catch (err) {
19913
20269
  console.warn(` Failed to remove ${stateDir}: ${err instanceof Error ? err.message : err}`);
@@ -19927,9 +20283,9 @@ This will remove all Runwork configuration from your local agents:
19927
20283
  // src/commands/apps.ts
19928
20284
  init_store();
19929
20285
  init_client();
19930
- import { Command as Command28 } from "commander";
20286
+ import { Command as Command29 } from "commander";
19931
20287
  init_init();
19932
- var listCommand12 = new Command28("list").description("List apps in workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
20288
+ var listCommand12 = new Command29("list").description("List apps in workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
19933
20289
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
19934
20290
  const credentials = requireAuth();
19935
20291
  const client = new ApiClient(credentials);
@@ -19959,10 +20315,10 @@ Workspace: ${workspaceName || workspaceId}
19959
20315
  process.exit(1);
19960
20316
  }
19961
20317
  });
19962
- var createCommand3 = new Command28("create").description("Create a new Runwork app").argument("[name]", "App name").action(async (name) => {
20318
+ var createCommand3 = new Command29("create").description("Create a new Runwork app").argument("[name]", "App name").action(async (name) => {
19963
20319
  await runCreateFlow(name);
19964
20320
  });
19965
- var infoCommand2 = new Command28("info").description("Show detailed app info, preview status, and registries").argument("[app]", "App ID, name, or slug").option("--workspace <name-or-id>", "Workspace name or ID").action(async (appArg, opts, command) => {
20321
+ var infoCommand2 = new Command29("info").description("Show detailed app info, preview status, and registries").argument("[app]", "App ID, name, or slug").option("--workspace <name-or-id>", "Workspace name or ID").action(async (appArg, opts, command) => {
19966
20322
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
19967
20323
  const credentials = requireAuth();
19968
20324
  const client = new ApiClient(credentials);
@@ -19987,12 +20343,12 @@ var infoCommand2 = new Command28("info").description("Show detailed app info, pr
19987
20343
  }
19988
20344
  printAppInfo(data);
19989
20345
  });
19990
- var appsCommand = new Command28("apps").description("Manage workspace apps").addCommand(listCommand12).addCommand(createCommand3).addCommand(infoCommand2);
20346
+ var appsCommand = new Command29("apps").description("Manage workspace apps").addCommand(listCommand12).addCommand(createCommand3).addCommand(infoCommand2);
19991
20347
 
19992
20348
  // src/commands/members.ts
19993
20349
  init_store();
19994
20350
  init_client();
19995
- import { Command as Command29 } from "commander";
20351
+ import { Command as Command30 } from "commander";
19996
20352
  function formatMemberRows(members) {
19997
20353
  return members.map((m) => ({
19998
20354
  name: m.user.displayName || m.user.email,
@@ -20002,7 +20358,7 @@ function formatMemberRows(members) {
20002
20358
  userId: m.userId
20003
20359
  }));
20004
20360
  }
20005
- var listCommand13 = new Command29("list").description("List members of a workspace (name, email, role)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
20361
+ var listCommand13 = new Command30("list").description("List members of a workspace (name, email, role)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
20006
20362
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
20007
20363
  const credentials = requireAuth();
20008
20364
  const client = new ApiClient(credentials);
@@ -20031,13 +20387,13 @@ Workspace: ${workspaceName || workspaceId}
20031
20387
  process.exit(1);
20032
20388
  }
20033
20389
  });
20034
- var membersCommand = new Command29("members").description("List workspace members").addCommand(listCommand13);
20390
+ var membersCommand = new Command30("members").description("List workspace members").addCommand(listCommand13);
20035
20391
 
20036
20392
  // src/commands/api.ts
20037
20393
  init_store();
20038
20394
  init_client();
20039
- import { Command as Command30 } from "commander";
20040
- import { readFileSync as readFileSync37 } from "fs";
20395
+ import { Command as Command31 } from "commander";
20396
+ import { readFileSync as readFileSync38 } from "fs";
20041
20397
  function normalizeApiPath(rawPath, baseUrl) {
20042
20398
  if (/^https?:\/\//i.test(rawPath)) {
20043
20399
  const target = new URL(rawPath);
@@ -20049,7 +20405,7 @@ function normalizeApiPath(rawPath, baseUrl) {
20049
20405
  }
20050
20406
  return rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
20051
20407
  }
20052
- var apiCommand = new Command30("api").description("Make an authenticated request to the Runwork platform API (escape hatch for endpoints the CLI does not cover)").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("[path]", "API path (e.g. /api/workspaces); optional with --curl").option("--body <json>", "Request body JSON (or @file.json)").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g. limit=10&offset=0)").option("--curl <command>", "Parse a curl command (method, path, headers, body)").option("--curl-file <file>", "Read curl command from a file").addHelpText("after", `
20408
+ var apiCommand = new Command31("api").description("Make an authenticated request to the Runwork platform API (escape hatch for endpoints the CLI does not cover)").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("[path]", "API path (e.g. /api/workspaces); optional with --curl").option("--body <json>", "Request body JSON (or @file.json)").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g. limit=10&offset=0)").option("--curl <command>", "Parse a curl command (method, path, headers, body)").option("--curl-file <file>", "Read curl command from a file").addHelpText("after", `
20053
20409
  Examples:
20054
20410
  runwork api GET /api/workspaces
20055
20411
  runwork api GET /api/workspaces/<id>/members
@@ -20070,7 +20426,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
20070
20426
  let curlStr = opts.curl;
20071
20427
  if (opts.curlFile) {
20072
20428
  try {
20073
- curlStr = readFileSync37(opts.curlFile, "utf-8");
20429
+ curlStr = readFileSync38(opts.curlFile, "utf-8");
20074
20430
  } catch (err) {
20075
20431
  console.error(`Could not read --curl-file: ${err instanceof Error ? err.message : err}`);
20076
20432
  process.exit(1);
@@ -20090,7 +20446,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
20090
20446
  let raw = opts.body;
20091
20447
  if (raw.startsWith("@")) {
20092
20448
  try {
20093
- raw = readFileSync37(raw.slice(1), "utf-8");
20449
+ raw = readFileSync38(raw.slice(1), "utf-8");
20094
20450
  } catch (err) {
20095
20451
  console.error(`Could not read body file: ${err instanceof Error ? err.message : err}`);
20096
20452
  process.exit(1);
@@ -20132,16 +20488,16 @@ to be read or pasted manually. Prefer a dedicated command when one exists
20132
20488
 
20133
20489
  // src/commands/doctor.ts
20134
20490
  init_colors();
20135
- import { Command as Command31 } from "commander";
20491
+ import { Command as Command32 } from "commander";
20136
20492
 
20137
20493
  // src/health/checks.ts
20138
20494
  init_subprocess();
20139
20495
  init_store();
20140
20496
  init_client();
20141
20497
  import { parse as parse2 } from "smol-toml";
20142
- import { existsSync as existsSync46, readFileSync as readFileSync38 } from "fs";
20143
- import { join as join42, sep as sep4 } from "path";
20144
- import { homedir as homedir22, platform as osPlatform2, arch as osArch } from "os";
20498
+ import { existsSync as existsSync49, readFileSync as readFileSync39 } from "fs";
20499
+ import { join as join45, sep as sep4 } from "path";
20500
+ import { homedir as homedir24, platform as osPlatform2, arch as osArch } from "os";
20145
20501
  init_http();
20146
20502
  init_preflight();
20147
20503
  init_credentials();
@@ -20172,10 +20528,10 @@ function buildContext() {
20172
20528
  const credentials = getCredentials();
20173
20529
  const client = credentials ? new ApiClient(credentials) : null;
20174
20530
  let config = null;
20175
- const configPath = join42(process.cwd(), ".runwork.json");
20176
- if (existsSync46(configPath)) {
20531
+ const configPath = join45(process.cwd(), ".runwork.json");
20532
+ if (existsSync49(configPath)) {
20177
20533
  try {
20178
- config = JSON.parse(readFileSync38(configPath, "utf-8"));
20534
+ config = JSON.parse(readFileSync39(configPath, "utf-8"));
20179
20535
  } catch {}
20180
20536
  }
20181
20537
  return { credentials, client, config, cwd: process.cwd() };
@@ -20276,9 +20632,9 @@ async function checkCliArtifactReachable() {
20276
20632
  }
20277
20633
  async function checkCliInstallLocation() {
20278
20634
  const isWindows2 = osPlatform2() === "win32";
20279
- const home = homedir22();
20280
- const canonicalDir = join42(home, ".runwork", "bin");
20281
- const canonicalBinary = isWindows2 ? join42(canonicalDir, "runwork.exe") : join42(canonicalDir, "runwork");
20635
+ const home = homedir24();
20636
+ const canonicalDir = join45(home, ".runwork", "bin");
20637
+ const canonicalBinary = isWindows2 ? join45(canonicalDir, "runwork.exe") : join45(canonicalDir, "runwork");
20282
20638
  const candidates = [process.execPath, process.argv[1] || ""].filter(Boolean);
20283
20639
  const runsFromCanonical = candidates.some((p) => normalizePath(p) === normalizePath(canonicalBinary));
20284
20640
  if (runsFromCanonical) {
@@ -20288,7 +20644,7 @@ async function checkCliInstallLocation() {
20288
20644
  message: `canonical (${canonicalBinary})`
20289
20645
  };
20290
20646
  }
20291
- if (existsSync46(canonicalBinary)) {
20647
+ if (existsSync49(canonicalBinary)) {
20292
20648
  return {
20293
20649
  name: "cli-install-location",
20294
20650
  status: "warn",
@@ -20410,8 +20766,8 @@ async function checkGitCredentialHelper(ctx) {
20410
20766
  };
20411
20767
  }
20412
20768
  async function checkProjectConfig(ctx) {
20413
- const configPath = join42(ctx.cwd, ".runwork.json");
20414
- if (!existsSync46(configPath)) {
20769
+ const configPath = join45(ctx.cwd, ".runwork.json");
20770
+ if (!existsSync49(configPath)) {
20415
20771
  if (!ctx.credentials) {
20416
20772
  return { name: "project-config", status: "skip", message: "no project (not logged in)" };
20417
20773
  }
@@ -20473,7 +20829,7 @@ async function checkGitRemote(ctx) {
20473
20829
  if (!ctx.config) {
20474
20830
  return { name: "git-remote", status: "skip", message: "skipped (no project)" };
20475
20831
  }
20476
- if (!existsSync46(join42(ctx.cwd, ".git"))) {
20832
+ if (!existsSync49(join45(ctx.cwd, ".git"))) {
20477
20833
  return {
20478
20834
  name: "git-remote",
20479
20835
  status: "fail",
@@ -20527,12 +20883,12 @@ async function checkDeployFreshness(ctx) {
20527
20883
  return { name: "deploy-freshness", status: "skip", message: "local HEAD unknown" };
20528
20884
  }
20529
20885
  function loadSetupState5() {
20530
- const projectPath = join42(process.cwd(), ".runwork", "setup.json");
20531
- const userPath = join42(homedir22(), ".runwork", "setup.json");
20886
+ const projectPath = join45(process.cwd(), ".runwork", "setup.json");
20887
+ const userPath = join45(homedir24(), ".runwork", "setup.json");
20532
20888
  for (const p of [projectPath, userPath]) {
20533
- if (existsSync46(p)) {
20889
+ if (existsSync49(p)) {
20534
20890
  try {
20535
- return JSON.parse(readFileSync38(p, "utf-8"));
20891
+ return JSON.parse(readFileSync39(p, "utf-8"));
20536
20892
  } catch {
20537
20893
  continue;
20538
20894
  }
@@ -20547,13 +20903,13 @@ async function checkCodexNetwork() {
20547
20903
  if (!state || !state.configuredAgents.includes("codex")) {
20548
20904
  return { name, status: "skip", message: "Codex not configured for Runwork" };
20549
20905
  }
20550
- const configPath = join42(homedir22(), ".codex", "config.toml");
20551
- if (!existsSync46(configPath)) {
20906
+ const configPath = join45(homedir24(), ".codex", "config.toml");
20907
+ if (!existsSync49(configPath)) {
20552
20908
  return { name, status: "skip", message: "no Codex config found" };
20553
20909
  }
20554
20910
  let parsed;
20555
20911
  try {
20556
- parsed = parse2(readFileSync38(configPath, "utf-8"));
20912
+ parsed = parse2(readFileSync39(configPath, "utf-8"));
20557
20913
  } catch {
20558
20914
  return { name, status: "warn", message: "could not parse ~/.codex/config.toml" };
20559
20915
  }
@@ -20606,19 +20962,19 @@ async function checkCodexDesktopProject() {
20606
20962
  if (!usesCodex) {
20607
20963
  return { name, status: "skip", message: "Codex not configured for Runwork" };
20608
20964
  }
20609
- const statePath2 = join42(homedir22(), ".codex", ".codex-global-state.json");
20610
- if (!existsSync46(statePath2)) {
20965
+ const statePath2 = join45(homedir24(), ".codex", ".codex-global-state.json");
20966
+ if (!existsSync49(statePath2)) {
20611
20967
  return { name, status: "skip", message: "Codex desktop app not detected" };
20612
20968
  }
20613
20969
  let savedRoots = [];
20614
20970
  try {
20615
- const parsed = JSON.parse(readFileSync38(statePath2, "utf-8"));
20971
+ const parsed = JSON.parse(readFileSync39(statePath2, "utf-8"));
20616
20972
  const roots = parsed["electron-saved-workspace-roots"];
20617
20973
  savedRoots = Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
20618
20974
  } catch {
20619
20975
  return { name, status: "warn", message: "could not read Codex desktop state" };
20620
20976
  }
20621
- const runworkDir = join42(homedir22(), ".runwork");
20977
+ const runworkDir = join45(homedir24(), ".runwork");
20622
20978
  if (savedRoots.includes(runworkDir)) {
20623
20979
  return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
20624
20980
  }
@@ -20671,9 +21027,9 @@ async function checkAgentSetup() {
20671
21027
  if (!adapter2 || !adapter2.supportsMcpScope("user"))
20672
21028
  continue;
20673
21029
  const mcpConfigPath = getMcpConfigPath2(slug, "user");
20674
- if (mcpConfigPath && existsSync46(mcpConfigPath)) {
21030
+ if (mcpConfigPath && existsSync49(mcpConfigPath)) {
20675
21031
  try {
20676
- const content = readFileSync38(mcpConfigPath, "utf-8");
21032
+ const content = readFileSync39(mcpConfigPath, "utf-8");
20677
21033
  const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
20678
21034
  if (missingMcp.length > 0) {
20679
21035
  details.push(`${missingMcp.length} MCP server(s) missing from ${slug} config`);
@@ -20696,8 +21052,8 @@ async function checkAgentSetup() {
20696
21052
  if (!skillsDir)
20697
21053
  continue;
20698
21054
  const missingSkills = state.skills.filter((name) => {
20699
- const skillPath = join42(skillsDir, name, "SKILL.md");
20700
- return !existsSync46(skillPath);
21055
+ const skillPath = join45(skillsDir, name, "SKILL.md");
21056
+ return !existsSync49(skillPath);
20701
21057
  });
20702
21058
  if (missingSkills.length > 0) {
20703
21059
  details.push(`${missingSkills.length} skill(s) missing from ${slug}`);
@@ -20722,33 +21078,66 @@ async function checkAgentSetup() {
20722
21078
  };
20723
21079
  }
20724
21080
  function getMcpConfigPath2(slug, scope) {
20725
- const home = homedir22();
21081
+ const home = homedir24();
20726
21082
  switch (slug) {
20727
21083
  case "claude-code":
20728
- return scope === "project" ? join42(process.cwd(), ".mcp.json") : join42(home, ".claude", "settings.json");
21084
+ return scope === "project" ? join45(process.cwd(), ".mcp.json") : join45(home, ".claude", "settings.json");
20729
21085
  case "cursor":
20730
- return scope === "project" ? join42(process.cwd(), ".cursor", "mcp.json") : join42(home, ".cursor", "mcp.json");
21086
+ return scope === "project" ? join45(process.cwd(), ".cursor", "mcp.json") : join45(home, ".cursor", "mcp.json");
20731
21087
  case "windsurf":
20732
- return scope === "project" ? join42(process.cwd(), ".windsurf", "mcp.json") : join42(home, ".windsurf", "mcp.json");
21088
+ return scope === "project" ? join45(process.cwd(), ".windsurf", "mcp.json") : join45(home, ".windsurf", "mcp.json");
20733
21089
  case "codex":
20734
21090
  case "codex-app":
20735
- return scope === "user" ? join42(home, ".codex", "config.toml") : null;
21091
+ return scope === "user" ? join45(home, ".codex", "config.toml") : null;
20736
21092
  case "gemini":
20737
- return scope === "user" ? join42(home, ".gemini", "settings.json") : null;
21093
+ return scope === "user" ? join45(home, ".gemini", "settings.json") : null;
20738
21094
  default:
20739
21095
  return null;
20740
21096
  }
20741
21097
  }
21098
+ async function checkWorkspacePointers() {
21099
+ const userStatePath = join45(homedir24(), ".runwork", "setup.json");
21100
+ const state = existsSync49(userStatePath) ? (() => {
21101
+ try {
21102
+ return JSON.parse(readFileSync39(userStatePath, "utf-8"));
21103
+ } catch {
21104
+ return null;
21105
+ }
21106
+ })() : null;
21107
+ const credentials = getCredentials();
21108
+ if (!state) {
21109
+ return { name: "workspace-pointers", status: "skip", message: "setup has not run on this machine" };
21110
+ }
21111
+ if (!credentials?.defaultWorkspaceId) {
21112
+ return { name: "workspace-pointers", status: "skip", message: "no default workspace in credentials" };
21113
+ }
21114
+ if (credentials.defaultWorkspaceId === state.workspaceId) {
21115
+ const label = state.workspaceName || state.workspaceId;
21116
+ return { name: "workspace-pointers", status: "pass", message: `${label} everywhere` };
21117
+ }
21118
+ const configured = state.workspaceName || state.workspaceId;
21119
+ const selected = credentials.defaultWorkspaceName || credentials.defaultWorkspaceId;
21120
+ return {
21121
+ name: "workspace-pointers",
21122
+ status: "fail",
21123
+ message: `your AI tools are set up for ${configured}, but ${selected} is selected`,
21124
+ details: [
21125
+ `setup.json (drives sync): ${state.workspaceId}`,
21126
+ `credentials (selected): ${credentials.defaultWorkspaceId}`
21127
+ ],
21128
+ fix: `runwork workspace switch ${credentials.defaultWorkspaceId}`
21129
+ };
21130
+ }
20742
21131
  function getSkillsDir(slug, scope) {
20743
- const home = homedir22();
21132
+ const home = homedir24();
20744
21133
  switch (slug) {
20745
21134
  case "claude-code":
20746
- return scope === "project" ? join42(process.cwd(), ".claude", "skills") : join42(home, ".claude", "skills");
21135
+ return scope === "project" ? join45(process.cwd(), ".claude", "skills") : join45(home, ".claude", "skills");
20747
21136
  case "codex":
20748
21137
  case "codex-app":
20749
- return scope === "project" ? join42(process.cwd(), ".agents", "skills") : join42(home, ".agents", "skills");
21138
+ return scope === "project" ? join45(process.cwd(), ".agents", "skills") : join45(home, ".agents", "skills");
20750
21139
  case "gemini":
20751
- return scope === "project" ? join42(process.cwd(), ".gemini", "skills") : join42(home, ".gemini", "skills");
21140
+ return scope === "project" ? join45(process.cwd(), ".gemini", "skills") : join45(home, ".gemini", "skills");
20752
21141
  default:
20753
21142
  return null;
20754
21143
  }
@@ -20774,7 +21163,8 @@ var CHECK_RUNNERS = [
20774
21163
  { names: ["deploy-freshness"], run: async (ctx) => [await checkDeployFreshness(ctx)] },
20775
21164
  { names: ["agent-setup"], run: async () => [await checkAgentSetup()] },
20776
21165
  { names: ["codex-network"], run: async () => [await checkCodexNetwork()] },
20777
- { names: ["codex-desktop-project"], run: async () => [await checkCodexDesktopProject()] }
21166
+ { names: ["codex-desktop-project"], run: async () => [await checkCodexDesktopProject()] },
21167
+ { names: ["workspace-pointers"], run: async () => [await checkWorkspacePointers()] }
20778
21168
  ];
20779
21169
  var ALL_CHECK_NAMES = CHECK_RUNNERS.flatMap((r) => r.names);
20780
21170
  async function runAllChecks(options) {
@@ -20800,8 +21190,8 @@ async function runAllChecks(options) {
20800
21190
  // src/health/fix.ts
20801
21191
  init_credentials();
20802
21192
  init_remote();
20803
- import { existsSync as existsSync47 } from "fs";
20804
- import { join as join43 } from "path";
21193
+ import { existsSync as existsSync50 } from "fs";
21194
+ import { join as join46 } from "path";
20805
21195
  async function applyDoctorFixes(ctx, failingNames) {
20806
21196
  const failing = new Set(failingNames);
20807
21197
  const outcomes = [];
@@ -20828,7 +21218,7 @@ async function applyDoctorFixes(ctx, failingNames) {
20828
21218
  applied: false,
20829
21219
  message: "no project config -- run inside an app directory"
20830
21220
  });
20831
- } else if (!existsSync47(join43(ctx.cwd, ".git"))) {
21221
+ } else if (!existsSync50(join46(ctx.cwd, ".git"))) {
20832
21222
  outcomes.push({
20833
21223
  name: "git-remote",
20834
21224
  applied: false,
@@ -20847,10 +21237,10 @@ async function applyDoctorFixes(ctx, failingNames) {
20847
21237
  }
20848
21238
 
20849
21239
  // src/agents/runtime-detection.ts
20850
- import { existsSync as existsSync48, readFileSync as readFileSync39, statSync as statSync8, readdirSync as readdirSync13 } from "fs";
20851
- import { homedir as homedir23 } from "os";
20852
- import { join as join44 } from "path";
20853
- var RUNWORK_SESSIONS_DIR = join44(homedir23(), ".runwork", "sessions");
21240
+ import { existsSync as existsSync51, readFileSync as readFileSync40, statSync as statSync9, readdirSync as readdirSync15 } from "fs";
21241
+ import { homedir as homedir25 } from "os";
21242
+ import { join as join47 } from "path";
21243
+ var RUNWORK_SESSIONS_DIR = join47(homedir25(), ".runwork", "sessions");
20854
21244
  function detectCurrentAgent() {
20855
21245
  const claudeCodeSessionId = process.env.CLAUDE_CODE_SESSION_ID;
20856
21246
  if (claudeCodeSessionId) {
@@ -20913,11 +21303,11 @@ function detectCurrentAgent() {
20913
21303
  return null;
20914
21304
  }
20915
21305
  function readHookSessionInfo(sessionId) {
20916
- const path4 = join44(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
20917
- if (!existsSync48(path4))
21306
+ const path4 = join47(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
21307
+ if (!existsSync51(path4))
20918
21308
  return null;
20919
21309
  try {
20920
- const raw = readFileSync39(path4, "utf8");
21310
+ const raw = readFileSync40(path4, "utf8");
20921
21311
  const parsed = JSON.parse(raw);
20922
21312
  return parsed;
20923
21313
  } catch {
@@ -20925,40 +21315,40 @@ function readHookSessionInfo(sessionId) {
20925
21315
  }
20926
21316
  }
20927
21317
  function findClaudeCodeSessionFile(sessionId) {
20928
- const root = join44(homedir23(), ".claude", "projects");
20929
- if (!existsSync48(root))
21318
+ const root = join47(homedir25(), ".claude", "projects");
21319
+ if (!existsSync51(root))
20930
21320
  return null;
20931
21321
  let projectDirs;
20932
21322
  try {
20933
- projectDirs = readdirSync13(root);
21323
+ projectDirs = readdirSync15(root);
20934
21324
  } catch {
20935
21325
  return null;
20936
21326
  }
20937
21327
  for (const dir of projectDirs) {
20938
- const candidate = join44(root, dir, `${sessionId}.jsonl`);
20939
- if (existsSync48(candidate))
21328
+ const candidate = join47(root, dir, `${sessionId}.jsonl`);
21329
+ if (existsSync51(candidate))
20940
21330
  return candidate;
20941
21331
  }
20942
21332
  return null;
20943
21333
  }
20944
21334
  function findCodexRolloutFile(threadId) {
20945
- const root = join44(homedir23(), ".codex", "sessions");
20946
- if (!existsSync48(root))
21335
+ const root = join47(homedir25(), ".codex", "sessions");
21336
+ if (!existsSync51(root))
20947
21337
  return null;
20948
21338
  const stack = [root];
20949
21339
  while (stack.length > 0) {
20950
21340
  const dir = stack.pop();
20951
21341
  let entries;
20952
21342
  try {
20953
- entries = readdirSync13(dir);
21343
+ entries = readdirSync15(dir);
20954
21344
  } catch {
20955
21345
  continue;
20956
21346
  }
20957
21347
  for (const entry of entries) {
20958
- const full = join44(dir, entry);
21348
+ const full = join47(dir, entry);
20959
21349
  let s;
20960
21350
  try {
20961
- s = statSync8(full);
21351
+ s = statSync9(full);
20962
21352
  } catch {
20963
21353
  continue;
20964
21354
  }
@@ -20972,30 +21362,30 @@ function findCodexRolloutFile(threadId) {
20972
21362
  return null;
20973
21363
  }
20974
21364
  function findNewestClaudeCodeSession() {
20975
- const root = join44(homedir23(), ".claude", "projects");
20976
- if (!existsSync48(root))
21365
+ const root = join47(homedir25(), ".claude", "projects");
21366
+ if (!existsSync51(root))
20977
21367
  return null;
20978
21368
  let projectDirs;
20979
21369
  try {
20980
- projectDirs = readdirSync13(root);
21370
+ projectDirs = readdirSync15(root);
20981
21371
  } catch {
20982
21372
  return null;
20983
21373
  }
20984
21374
  let best = null;
20985
21375
  for (const dir of projectDirs) {
20986
- const projectPath = join44(root, dir);
21376
+ const projectPath = join47(root, dir);
20987
21377
  let files;
20988
21378
  try {
20989
- files = readdirSync13(projectPath);
21379
+ files = readdirSync15(projectPath);
20990
21380
  } catch {
20991
21381
  continue;
20992
21382
  }
20993
21383
  for (const file of files) {
20994
21384
  if (!file.endsWith(".jsonl"))
20995
21385
  continue;
20996
- const full = join44(projectPath, file);
21386
+ const full = join47(projectPath, file);
20997
21387
  try {
20998
- const s = statSync8(full);
21388
+ const s = statSync9(full);
20999
21389
  if (!best || s.mtimeMs > best.mtime) {
21000
21390
  best = {
21001
21391
  sessionId: file.replace(/\.jsonl$/, ""),
@@ -21011,8 +21401,8 @@ function findNewestClaudeCodeSession() {
21011
21401
  return best ? { sessionId: best.sessionId, path: best.path } : null;
21012
21402
  }
21013
21403
  function findNewestCodexRollout() {
21014
- const root = join44(homedir23(), ".codex", "sessions");
21015
- if (!existsSync48(root))
21404
+ const root = join47(homedir25(), ".codex", "sessions");
21405
+ if (!existsSync51(root))
21016
21406
  return null;
21017
21407
  const stack = [root];
21018
21408
  let best = null;
@@ -21020,15 +21410,15 @@ function findNewestCodexRollout() {
21020
21410
  const dir = stack.pop();
21021
21411
  let entries;
21022
21412
  try {
21023
- entries = readdirSync13(dir);
21413
+ entries = readdirSync15(dir);
21024
21414
  } catch {
21025
21415
  continue;
21026
21416
  }
21027
21417
  for (const entry of entries) {
21028
- const full = join44(dir, entry);
21418
+ const full = join47(dir, entry);
21029
21419
  let s;
21030
21420
  try {
21031
- s = statSync8(full);
21421
+ s = statSync9(full);
21032
21422
  } catch {
21033
21423
  continue;
21034
21424
  }
@@ -21204,7 +21594,7 @@ function parseCheckNames(raw) {
21204
21594
  const unknown = requested.filter((n) => !known.has(n));
21205
21595
  return { only, unknown };
21206
21596
  }
21207
- var doctorCommand = new Command31("doctor").description("Check system health: auth, network, project config, agent setup").option("-v, --verbose", "Include host-agent detection results, runtime info, and allowlisted env vars (useful for AI agents debugging their own environment)").option("--check <names>", `Run only the named checks (comma-separated). Available: ${ALL_CHECK_NAMES.join(", ")}`).option("--fix", "Auto-remediate fixable failures (git credential helper, runwork remote), then re-check").action(async (opts, command) => {
21597
+ var doctorCommand = new Command32("doctor").description("Check system health: auth, network, project config, agent setup").option("-v, --verbose", "Include host-agent detection results, runtime info, and allowlisted env vars (useful for AI agents debugging their own environment)").option("--check <names>", `Run only the named checks (comma-separated). Available: ${ALL_CHECK_NAMES.join(", ")}`).option("--fix", "Auto-remediate fixable failures (git credential helper, runwork remote), then re-check").action(async (opts, command) => {
21208
21598
  const asJson = shouldOutputJson(command.optsWithGlobals().json);
21209
21599
  let only;
21210
21600
  if (opts.check) {
@@ -21255,8 +21645,8 @@ var doctorCommand = new Command31("doctor").description("Check system health: au
21255
21645
  // src/commands/share-convo.ts
21256
21646
  init_store();
21257
21647
  init_client();
21258
- import { Command as Command32 } from "commander";
21259
- import { readFileSync as readFileSync40, existsSync as existsSync49 } from "fs";
21648
+ import { Command as Command33 } from "commander";
21649
+ import { readFileSync as readFileSync41, existsSync as existsSync52 } from "fs";
21260
21650
  import { createHash as createHash4 } from "crypto";
21261
21651
  function nativeBundleFormatForAgent(slug) {
21262
21652
  if (slug === "claude-code" || slug === "claude-desktop")
@@ -21277,7 +21667,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
21277
21667
  console.error("Error: --transcript-file is required. Pass the path to the LLM-emitted markdown transcript.");
21278
21668
  process.exit(1);
21279
21669
  }
21280
- if (!existsSync49(opts.transcriptFile)) {
21670
+ if (!existsSync52(opts.transcriptFile)) {
21281
21671
  console.error(`Error: transcript file does not exist: ${opts.transcriptFile}`);
21282
21672
  process.exit(1);
21283
21673
  }
@@ -21298,7 +21688,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
21298
21688
  const credentials = requireAuth();
21299
21689
  const client = new ApiClient(credentials);
21300
21690
  const { workspaceId } = await resolveWorkspace2(client, { workspace: opts.workspace });
21301
- const transcriptContent = readFileSync40(opts.transcriptFile, "utf8");
21691
+ const transcriptContent = readFileSync41(opts.transcriptFile, "utf8");
21302
21692
  const bundles = [
21303
21693
  {
21304
21694
  format: "transcript",
@@ -21311,19 +21701,19 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
21311
21701
  const sourceAgent = opts.sourceAgent ?? detected?.slug ?? "generic";
21312
21702
  let nativeFilePath = null;
21313
21703
  if (opts.nativeFile) {
21314
- if (!existsSync49(opts.nativeFile)) {
21704
+ if (!existsSync52(opts.nativeFile)) {
21315
21705
  console.error(`Error: --native-file path does not exist: ${opts.nativeFile}`);
21316
21706
  process.exit(1);
21317
21707
  }
21318
21708
  nativeFilePath = opts.nativeFile;
21319
- } else if (detected?.sessionFilePath && existsSync49(detected.sessionFilePath)) {
21709
+ } else if (detected?.sessionFilePath && existsSync52(detected.sessionFilePath)) {
21320
21710
  nativeFilePath = detected.sessionFilePath;
21321
21711
  }
21322
21712
  if (nativeFilePath) {
21323
21713
  const nativeFormat = nativeBundleFormatForAgent(sourceAgent);
21324
21714
  if (nativeFormat) {
21325
21715
  try {
21326
- const content = readFileSync40(nativeFilePath, "utf8");
21716
+ const content = readFileSync41(nativeFilePath, "utf8");
21327
21717
  bundles.push({
21328
21718
  format: nativeFormat,
21329
21719
  content,
@@ -21339,7 +21729,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
21339
21729
  let metadata = {};
21340
21730
  if (opts.metadataFile) {
21341
21731
  try {
21342
- metadata = JSON.parse(readFileSync40(opts.metadataFile, "utf8"));
21732
+ metadata = JSON.parse(readFileSync41(opts.metadataFile, "utf8"));
21343
21733
  } catch (err) {
21344
21734
  console.error(`Error: --metadata-file is not valid JSON: ${err instanceof Error ? err.message : err}`);
21345
21735
  process.exit(1);
@@ -21394,17 +21784,17 @@ Skipped: ${result.skipped.map((s) => `${s.identifier} (${s.reason})`).join(", ")
21394
21784
  process.exit(1);
21395
21785
  }
21396
21786
  }
21397
- var shareConvoCommand = new Command32("share-convo").description("Share the current AI conversation with a teammate").option("--to <email>", "Recipient email (repeatable)", (value, prev = []) => [...prev, value], []).option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars otherwise)").option("--source-agent <slug>", "Override host-agent detection (e.g. claude-code, codex, claude-desktop)").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional personal note to recipients").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, suggestedNextStep, etc.").option("--metadata-file <path>", "Path to a JSON file with the same metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo(opts, command, false));
21787
+ var shareConvoCommand = new Command33("share-convo").description("Share the current AI conversation with a teammate").option("--to <email>", "Recipient email (repeatable)", (value, prev = []) => [...prev, value], []).option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars otherwise)").option("--source-agent <slug>", "Override host-agent detection (e.g. claude-code, codex, claude-desktop)").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional personal note to recipients").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, suggestedNextStep, etc.").option("--metadata-file <path>", "Path to a JSON file with the same metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo(opts, command, false));
21398
21788
 
21399
21789
  // src/commands/save-convo.ts
21400
- import { Command as Command33 } from "commander";
21401
- var saveConvoCommand = new Command33("save-convo").description("Save the current AI conversation as a personal checkpoint").option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars)").option("--source-agent <slug>", "Override host-agent detection").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional note to your future self").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, etc.").option("--metadata-file <path>", "Path to a JSON file with metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo({ ...opts, personal: true }, command, true));
21790
+ import { Command as Command34 } from "commander";
21791
+ var saveConvoCommand = new Command34("save-convo").description("Save the current AI conversation as a personal checkpoint").option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars)").option("--source-agent <slug>", "Override host-agent detection").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional note to your future self").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, etc.").option("--metadata-file <path>", "Path to a JSON file with metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo({ ...opts, personal: true }, command, true));
21402
21792
 
21403
21793
  // src/commands/inbox.ts
21404
21794
  init_store();
21405
21795
  init_client();
21406
- import { Command as Command34 } from "commander";
21407
- var inboxCommand = new Command34("inbox").description("List shared conversations visible to you").option("--filter <scope>", "Filter: all | received | sent | saved", "all").option("--limit <n>", "Max rows to return", "50").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
21796
+ import { Command as Command35 } from "commander";
21797
+ var inboxCommand = new Command35("inbox").description("List shared conversations visible to you").option("--filter <scope>", "Filter: all | received | sent | saved", "all").option("--limit <n>", "Max rows to return", "50").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
21408
21798
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
21409
21799
  const scope = opts.filter === "received" || opts.filter === "sent" || opts.filter === "saved" ? opts.filter : "all";
21410
21800
  const limit = opts.limit ? parseInt(opts.limit, 10) : 50;
@@ -21444,10 +21834,10 @@ Shared conversations (${scope}, ${total}):
21444
21834
  // src/commands/resume.ts
21445
21835
  init_store();
21446
21836
  init_client();
21447
- import { Command as Command35 } from "commander";
21448
- import { writeFileSync as writeFileSync32, mkdirSync as mkdirSync29, realpathSync } from "fs";
21449
- import { homedir as homedir24 } from "os";
21450
- import { join as join45 } from "path";
21837
+ import { Command as Command36 } from "commander";
21838
+ import { writeFileSync as writeFileSync29, mkdirSync as mkdirSync27, realpathSync } from "fs";
21839
+ import { homedir as homedir26 } from "os";
21840
+ import { join as join48 } from "path";
21451
21841
  import { spawn as spawn5 } from "child_process";
21452
21842
  function encodeClaudeCodeCwd(cwd) {
21453
21843
  let canonical;
@@ -21484,10 +21874,10 @@ function extractCodexUuid(rolloutContent) {
21484
21874
  }
21485
21875
  function placeClaudeJsonl(uuid, content, recipientCwd) {
21486
21876
  const encoded = encodeClaudeCodeCwd(recipientCwd);
21487
- const projectDir = join45(homedir24(), ".claude", "projects", encoded);
21488
- mkdirSync29(projectDir, { recursive: true });
21489
- const placedAt = join45(projectDir, `${uuid}.jsonl`);
21490
- writeFileSync32(placedAt, content);
21877
+ const projectDir = join48(homedir26(), ".claude", "projects", encoded);
21878
+ mkdirSync27(projectDir, { recursive: true });
21879
+ const placedAt = join48(projectDir, `${uuid}.jsonl`);
21880
+ writeFileSync29(placedAt, content);
21491
21881
  return { placedAt, runFromCwd: recipientCwd };
21492
21882
  }
21493
21883
  function placeCodexRollout(uuid, content) {
@@ -21495,11 +21885,11 @@ function placeCodexRollout(uuid, content) {
21495
21885
  const yyyy = String(now.getUTCFullYear());
21496
21886
  const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
21497
21887
  const dd = String(now.getUTCDate()).padStart(2, "0");
21498
- const dir = join45(homedir24(), ".codex", "sessions", yyyy, mm, dd);
21499
- mkdirSync29(dir, { recursive: true });
21888
+ const dir = join48(homedir26(), ".codex", "sessions", yyyy, mm, dd);
21889
+ mkdirSync27(dir, { recursive: true });
21500
21890
  const ts = now.toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
21501
- const placedAt = join45(dir, `rollout-${ts}-${uuid}.jsonl`);
21502
- writeFileSync32(placedAt, content);
21891
+ const placedAt = join48(dir, `rollout-${ts}-${uuid}.jsonl`);
21892
+ writeFileSync29(placedAt, content);
21503
21893
  return { placedAt };
21504
21894
  }
21505
21895
  function pickTargetAgent(opts, sourceAgent) {
@@ -21518,7 +21908,7 @@ function isAgentInstalled(agent) {
21518
21908
  }
21519
21909
  return false;
21520
21910
  }
21521
- var resumeCommand2 = new Command35("resume").description("Resume a shared conversation locally in your agent of choice").argument("<share-id>", "The share ID (sc_*) returned by share-convo or save-convo").option("--agent <slug>", "Override target agent (e.g. claude-code, codex)").option("--into <path>", "Override target cwd (defaults to current $PWD)").option("--dry-run", "Print the resume command instead of executing it").option("--pick", "Show interactive picker (requires TTY) - not yet implemented").option("--workspace <name-or-id>", "Workspace name or ID").action(async (shareId, opts, command) => {
21911
+ var resumeCommand2 = new Command36("resume").description("Resume a shared conversation locally in your agent of choice").argument("<share-id>", "The share ID (sc_*) returned by share-convo or save-convo").option("--agent <slug>", "Override target agent (e.g. claude-code, codex)").option("--into <path>", "Override target cwd (defaults to current $PWD)").option("--dry-run", "Print the resume command instead of executing it").option("--pick", "Show interactive picker (requires TTY) - not yet implemented").option("--workspace <name-or-id>", "Workspace name or ID").action(async (shareId, opts, command) => {
21522
21912
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
21523
21913
  const credentials = requireAuth();
21524
21914
  const client = new ApiClient(credentials);
@@ -21748,7 +22138,7 @@ process.on("uncaughtException", (err) => {
21748
22138
  console.error(`Uncaught exception: ${formatError(err)}`);
21749
22139
  process.exit(1);
21750
22140
  });
21751
- var program = new Command36;
22141
+ var program = new Command37;
21752
22142
  program.name("runwork").description("Runwork CLI - local development for Runwork apps").version(VERSION).option("--json", "Output as JSON (auto-enabled when stdout is not a TTY)");
21753
22143
  program.addCommand(infoCommand);
21754
22144
  program.addCommand(loginCommand);
@@ -21773,6 +22163,7 @@ program.addCommand(apiKeysCommand);
21773
22163
  program.addCommand(agentsCommand);
21774
22164
  program.addCommand(mcpCommand);
21775
22165
  program.addCommand(setupCommand);
22166
+ program.addCommand(workspaceCommand);
21776
22167
  program.addCommand(syncCommand);
21777
22168
  program.addCommand(buildPluginCommand);
21778
22169
  program.addCommand(uninstallCommand);